diff --git a/day8/input b/day8/input new file mode 100644 index 0000000..62e61dd --- /dev/null +++ b/day8/input @@ -0,0 +1,634 @@ +acc +15 +acc +2 +acc -14 +jmp +362 +acc +22 +nop +236 +jmp +474 +acc +10 +jmp +1 +acc +0 +jmp +236 +acc +10 +acc +14 +jmp +334 +acc +12 +acc -1 +jmp +478 +jmp +90 +jmp +208 +acc +49 +jmp +94 +acc +2 +acc -8 +jmp +375 +nop +21 +acc +0 +acc +10 +nop +25 +jmp +492 +nop +182 +acc +49 +acc -12 +jmp -14 +acc -16 +jmp +140 +acc -3 +acc -18 +acc +28 +acc -6 +jmp +558 +acc +2 +acc +27 +nop +438 +acc +41 +jmp +508 +acc +13 +jmp +117 +acc +21 +acc -13 +acc +34 +jmp +1 +jmp +1 +nop +451 +acc +28 +acc +31 +acc +31 +jmp +280 +acc +32 +acc +35 +acc -18 +jmp +509 +acc -15 +acc -8 +nop +288 +acc -16 +jmp +376 +acc -19 +acc -8 +acc +11 +acc +10 +jmp +50 +acc +19 +nop -58 +acc -9 +jmp +43 +acc +10 +acc +2 +nop -63 +jmp +280 +acc -7 +jmp +175 +jmp +69 +acc +16 +acc +9 +acc -2 +acc -5 +jmp +276 +nop +195 +acc +50 +acc -8 +jmp -55 +nop +1 +nop -78 +acc +31 +jmp +535 +acc +9 +acc +33 +acc +4 +acc +48 +jmp +8 +acc +30 +acc +42 +acc +18 +acc +37 +jmp -69 +nop +121 +jmp +44 +acc +3 +acc +33 +acc -6 +acc +37 +jmp +403 +acc -6 +jmp +245 +jmp -93 +acc +5 +jmp +406 +jmp -26 +nop -47 +jmp +239 +acc +7 +acc +31 +acc +14 +acc +0 +jmp +291 +acc +46 +jmp +394 +acc +44 +acc +36 +nop +45 +jmp +137 +acc -16 +acc +10 +acc -4 +acc +7 +jmp +76 +acc +24 +jmp +93 +acc +17 +acc +0 +acc +6 +acc +4 +jmp +385 +acc -8 +acc +49 +acc +28 +jmp +95 +nop +12 +acc +33 +jmp +153 +nop +254 +acc +18 +acc -16 +acc +50 +jmp +299 +acc +27 +acc +47 +acc -17 +jmp -15 +acc +35 +acc +14 +jmp +204 +jmp +93 +acc +46 +nop -5 +nop -158 +jmp +221 +jmp +321 +acc -2 +acc +49 +acc +3 +acc -17 +jmp -52 +jmp +7 +nop +52 +acc +25 +jmp +376 +acc -3 +nop -133 +jmp +32 +jmp +328 +nop +374 +acc +37 +acc +6 +jmp +92 +acc +47 +nop +394 +jmp -13 +jmp -170 +acc +9 +jmp -47 +acc -18 +acc +27 +jmp +1 +acc +3 +acc -5 +jmp +337 +acc +21 +jmp +364 +acc +24 +acc +43 +acc +50 +jmp +58 +jmp -18 +acc +30 +jmp +144 +nop +5 +acc +50 +nop +245 +nop +133 +jmp +270 +jmp -22 +nop -76 +jmp +398 +acc +40 +acc +30 +jmp +361 +acc +36 +acc +30 +jmp +392 +acc -17 +nop +71 +acc -12 +jmp +102 +acc +17 +jmp +283 +acc -16 +jmp +65 +nop -2 +jmp +149 +jmp -103 +jmp -179 +acc +46 +jmp +289 +acc +48 +jmp +114 +acc +13 +jmp +114 +nop +215 +nop -89 +jmp +337 +acc -2 +acc +2 +acc -7 +jmp -18 +jmp -51 +acc +30 +acc +43 +acc +28 +jmp -188 +acc +36 +acc +7 +acc -5 +acc +38 +jmp +88 +jmp +225 +acc -14 +acc -3 +acc -15 +jmp +66 +acc +7 +acc +43 +nop -210 +acc -9 +jmp +109 +acc -10 +jmp +242 +acc -5 +acc +15 +acc +8 +jmp +310 +acc +31 +acc -2 +acc +11 +acc -15 +jmp +103 +acc +32 +jmp -92 +acc -10 +acc +6 +acc -1 +jmp -131 +acc +43 +acc +30 +acc +13 +acc +33 +jmp +25 +acc +9 +acc -14 +acc +19 +acc +44 +jmp -50 +acc -8 +acc +9 +jmp +312 +jmp -96 +acc -3 +acc -3 +acc +24 +jmp +94 +acc -15 +jmp +61 +acc +19 +nop -89 +acc +24 +nop -94 +jmp +5 +acc -13 +acc +25 +acc +42 +jmp +1 +jmp +137 +acc +44 +acc +44 +acc +41 +jmp +152 +jmp +144 +acc -1 +nop +293 +jmp -120 +acc -17 +nop -171 +acc +27 +jmp -173 +jmp +231 +acc +3 +jmp +109 +acc +18 +acc +32 +acc -14 +acc -8 +jmp +177 +acc +28 +jmp -134 +nop +277 +jmp -124 +jmp +167 +nop +274 +acc +6 +acc +43 +acc +10 +jmp -320 +acc +28 +acc -9 +acc +22 +jmp -90 +jmp -203 +jmp -133 +jmp -6 +jmp -181 +jmp +170 +acc +40 +acc +5 +jmp -274 +acc +36 +acc +24 +nop +6 +jmp -339 +jmp -251 +acc +10 +acc +10 +jmp -347 +jmp +263 +acc +37 +jmp -201 +acc -11 +acc +42 +jmp +153 +nop -179 +acc -9 +jmp +8 +jmp -289 +jmp -25 +acc +45 +jmp -142 +acc +42 +acc -10 +jmp +83 +acc +43 +acc +3 +acc -6 +jmp -222 +acc +41 +acc +14 +acc +7 +acc +2 +jmp -35 +jmp +168 +acc +11 +acc +18 +acc +8 +acc -4 +jmp -203 +acc +44 +jmp +10 +nop -184 +acc +0 +jmp +91 +acc -5 +nop +226 +acc +46 +acc -10 +jmp -15 +jmp -321 +acc +0 +acc +33 +jmp +82 +jmp +1 +acc -12 +acc +30 +jmp +152 +acc +6 +jmp -208 +acc +43 +jmp +39 +acc +23 +acc +23 +acc +24 +acc +26 +jmp -390 +acc +15 +acc +3 +acc +14 +acc +46 +jmp -239 +acc -10 +acc +19 +jmp +167 +acc +46 +acc +0 +jmp -280 +acc -7 +jmp -107 +acc +13 +jmp -76 +acc +48 +jmp -65 +nop +23 +nop -89 +acc +47 +jmp -304 +acc -5 +jmp +1 +acc +50 +acc +37 +jmp -129 +acc +27 +jmp +1 +jmp -212 +acc +18 +acc +29 +acc +1 +jmp -74 +acc +24 +acc -12 +jmp -173 +acc -18 +acc -6 +nop -156 +jmp -309 +acc +46 +acc -13 +acc +41 +acc +11 +jmp -188 +acc +32 +jmp -190 +acc +31 +acc +30 +jmp -122 +acc -7 +jmp +37 +acc +2 +acc +16 +acc +45 +acc +44 +jmp -376 +acc +47 +jmp +1 +jmp -147 +acc +47 +acc -18 +acc -1 +acc +2 +jmp -152 +acc +12 +acc -8 +jmp +90 +nop +67 +acc +9 +jmp +1 +jmp -377 +jmp +1 +jmp -238 +jmp +1 +acc +47 +acc +7 +acc +31 +jmp -427 +acc +10 +acc +13 +nop +13 +jmp -8 +nop -292 +acc +11 +nop -203 +jmp -164 +jmp -19 +acc +31 +jmp -289 +acc -7 +acc -16 +acc +35 +jmp -333 +jmp -500 +acc +32 +acc +29 +acc +18 +acc +14 +jmp -161 +jmp -60 +jmp +6 +acc +4 +nop -108 +acc +27 +jmp +2 +jmp -133 +acc +2 +jmp -103 +acc +40 +nop -512 +acc +48 +jmp -196 +acc +47 +acc +40 +nop -346 +acc -2 +jmp -530 +acc +17 +nop -31 +acc +1 +jmp -74 +acc -15 +acc +4 +nop -330 +acc +32 +jmp -115 +acc -3 +jmp +1 +acc +14 +acc +31 +jmp -352 +jmp -10 +acc +18 +jmp -322 +acc +41 +jmp +59 +acc -16 +nop -359 +acc +29 +acc +26 +jmp -418 +acc +10 +acc +47 +jmp -519 +acc -5 +nop +40 +acc +30 +jmp -195 +acc +31 +acc +3 +acc +8 +jmp -10 +acc -12 +acc +21 +acc -1 +jmp +30 +jmp -341 +acc -5 +jmp -405 +acc -13 +jmp -170 +acc +24 +acc -16 +acc +20 +acc +17 +jmp -145 +acc +42 +acc +33 +jmp -395 +nop -142 +acc +45 +acc +15 +jmp -399 +nop -223 +jmp -299 +jmp -453 +acc -6 +nop -498 +acc +42 +jmp -112 +acc +39 +acc +46 +acc +4 +acc +27 +jmp -234 +jmp +1 +acc +45 +acc +47 +jmp -307 +jmp -378 +jmp -431 +acc +13 +acc +29 +jmp -282 +acc +4 +acc -3 +acc +37 +acc +40 +jmp -32 +nop -148 +acc +38 +acc +40 +acc +18 +jmp -171 +nop -546 +jmp -490 +acc +36 +jmp -514 +acc +27 +acc -10 +nop -560 +acc +44 +jmp +1 diff --git a/day8/src/main.zig b/day8/src/main.zig index d29869f..13f71e4 100644 --- a/day8/src/main.zig +++ b/day8/src/main.zig @@ -1,5 +1,222 @@ const std = @import("std"); pub fn main() anyerror!void { - std.log.info("All your codebase are belong to us.", .{}); + var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); + defer arena.deinit(); + var gpa = &arena.allocator; + + var program = try Program.init(gpa); + defer program.*.deinit(); + + var f = try std.fs.cwd().openFile("input", .{}); + var contents = try f.readToEndAlloc(gpa, std.math.maxInt(u32)); + var it = std.mem.tokenize(contents, "\n"); + while (it.next()) |line| { + var s = try Statement.from_string(line); + try program.code.append(s); + } + std.log.debug("Loaded program with {} statements", .{program.code.items.len}); + _ = try program.run(); + + // Part 2 + // Exactly one nop should be a jmp or a jmp a noop + var i : usize = 0; + while (i < program.code.items.len) : (i += 1) { + if (program.code.items[i].op == .acc) { + continue; + } + // Mutate + program.code.items[i].op = switch(program.code.items[i].op) { + .acc => Operation.acc, + .jmp => Operation.nop, + .nop => Operation.jmp, + }; + // Test + var run_ok = program.run() catch false; + // Undo mutation + program.code.items[i].op = switch(program.code.items[i].op) { + .acc => Operation.acc, + .jmp => Operation.nop, + .nop => Operation.jmp, + }; + if (run_ok) { + std.log.info("By changing statement {}, the program exited okay", .{i}); + break; + } + } +} + +pub const Operation = enum { + nop, + acc, + jmp +}; + +pub const ParseError = error { + UnknownStatement, +}; + +pub const Statement = struct { + op: Operation, + arg: i32, + + /// Modifies acc and returns the offset for the next operation + pub fn execute(self: *Statement, acc: *i32) i32 { + var delta : i32 = switch (self.op) { + .nop => 1, + .jmp => self.arg, + .acc => 1, + }; + if (self.op == .acc) { + acc.* += self.arg; + } + return delta; + } + + pub fn from_string(line: []const u8) !Statement { + var arg : i32 = 0; + var op : Operation = undefined; + + var it = std.mem.tokenize(line, " "); + if (it.next()) |l| { + if (std.mem.eql(u8, l, "nop")) { + op = Operation.nop; + } + else if (std.mem.eql(u8, l, "acc")) { + op = Operation.acc; + } + else if (std.mem.eql(u8, l, "jmp")) { + op = Operation.jmp; + } + else { + std.log.err("Unknown statement: '{}'", .{l}); + return ParseError.UnknownStatement; + } + } + else { + // Error, and operator is required + unreachable; + } + if (it.next()) |l| { + arg = atoi(l); + } + else { + // Error, we need an arg + unreachable; + } + + while(it.next()) |l| { + // Error, there shouldn't be anything else on the line + unreachable; + } + + return Statement { + .op = op, + .arg = arg, + }; + } +}; + +pub const Program = struct { + code: std.ArrayList(Statement), + allocator: *std.mem.Allocator, + accumulator: i32 = 0, + + pub fn init(a: *std.mem.Allocator) !*Program { + const self = try a.create(Program); + errdefer a.destroy(self); + + self.* = Program { + .code = std.ArrayList(Statement).init(a), + .allocator = a, + }; + return self; + } + + pub fn deinit(self: *Program) void { + self.code.deinit(); + self.allocator.destroy(self); + } + + pub fn run(self: *Program) !bool { + self.accumulator = 0; + var next_statement_index : usize = 0; + // Statement counter + var map = std.hash_map.AutoHashMap(usize, u32).init(self.allocator); + defer map.deinit(); + + var ended_ok = false; + while (true) { + // Check if we have already exectured this index + var n_accumulator : i32 = self.accumulator; + if (map.contains(next_statement_index)) { + std.log.warn("Infinite loop detected. Statement {} would have run twice", + .{next_statement_index}); + std.log.warn("Acc value at break: {}", .{self.accumulator}); + break; + } + else { + try map.put(next_statement_index, 1); + } + + var delta = self.code.items[next_statement_index].execute(&n_accumulator); + //std.log.debug("Before {}, After {} [statement {} new offset {}] {}", + // .{self.accumulator, n_accumulator, next_statement_index, + // delta, self.code.items[next_statement_index]}); + if (delta < 0) { + next_statement_index -= @intCast(usize, try std.math.absInt(delta)); + } + else { + next_statement_index += @intCast(usize, delta); + } + std.debug.assert(next_statement_index >= 0); + if (next_statement_index >= self.code.items.len) { + std.log.warn("Reached end of code, or jumping past end ({}, {} statements).", + .{next_statement_index, self.code.items.len}); + std.log.warn("Acc value at end: {}", .{self.accumulator}); + ended_ok = true; // maybe... + break; + } + self.accumulator = n_accumulator; + } + return ended_ok; + } +}; + +fn atoi(a: []const u8) i32 { + var i : i32 = 0; + var mul : i32 = 1; + var start : usize = 0; + if (a[0] == '-' or a[0] == '+') { + start = 1; + if (a[0] == '-') { + mul *= -1; + } + } + for(a[start..]) |v, k| { + if (! std.ascii.isDigit(v)) { + std.log.warn("Byte {x} is not a digit", .{v}); + continue; + } + // 48 is '0' in ascii + std.debug.assert(v >= 48 and v < 58); + i += @as(i32, @as(i32, (v - 48)) * std.math.pow(i32, 10, @intCast(i32, a.len - k - 1 - start))); + } + //std.log.debug("{x} --> {}", .{a, i}); + return i * mul; +} + +test "atoi_regular" { + var i = atoi("1234"); + std.testing.expectEqual(i, 1234); +} + +test "atoi_pos" { + var i = atoi("+1234"); + std.testing.expectEqual(i, 1234); +} + +test "atoi_neg" { + var i = atoi("-1234"); + std.testing.expectEqual(i, -1234); }