const std = @import("std"); pub fn main() !void { const content = @embedFile("data.txt"); var lines = std.mem.split(u8, content, "\n"); var gpa = std.heap.GeneralPurposeAllocator(.{}){}; const allocator = gpa.allocator(); const instructions = lines.next().?; _ = lines.next(); var map = std.StringArrayHashMap([]const u8).init(allocator); defer map.deinit(); while (lines.next()) |line| { if (line.len == 0) { break; } try map.put(line[0..3], line[7..15]); } var i: u16 = 0; var cur = try allocator.dupe(u8, "AAA"); while (true) : (i += 1) { if (std.mem.eql(u8, cur, "ZZZ")) { break; } const ins = instructions[i % instructions.len]; const nodes = map.get(cur).?; if (ins == 'L') { std.mem.copy(u8, cur, nodes[0..3]); } else { std.mem.copy(u8, cur, nodes[5..8]); } } std.debug.print("Part 1: {d}\n", .{i}); // Part 2 var nodes = std.ArrayList([]const u8).init(allocator); defer nodes.deinit(); var steps = std.ArrayList(u32).init(allocator); defer steps.deinit(); // Find starting nodes for (map.keys()) |k| { if (k[2] == 'A') { try nodes.append(k); } } // for each starting node, how long until we get to a Z-ending node for (nodes.items) |node| { var j: u32 = 0; cur = try allocator.dupe(u8, node); while (true) : (j += 1) { // std.debug.print("checking node: {s}\n", .{cur}); if (cur[2] == 'Z') { break; } const ins = instructions[j % instructions.len]; const next = map.get(cur).?; if (ins == 'L') { std.mem.copy(u8, cur, next[0..3]); } else { std.mem.copy(u8, cur, next[5..8]); } } try steps.append(j); } var lowest: u64 = steps.items[0]; for (0..steps.items.len - 1) |j| { lowest = lcm(lowest, steps.items[j + 1]).?; } std.debug.print("Part 2: {d}\n", .{lowest}); } fn lcm(left: u64, right: u64) ?u64 { var i: u64 = @max(left, right); while (true) : (i += @max(left, right)) { if (i % left == 0 and i % right == 0) { return @as(u64, @intCast(i)); } } return null; }