diff --git a/02/src/main.zig b/02/src/main.zig index 270da8c..45b6022 100644 --- a/02/src/main.zig +++ b/02/src/main.zig @@ -5,7 +5,9 @@ fn run(program: []i32, noun: i32, verb: i32) i32 { program[1] = noun; program[2] = verb; - intcode.run(program); + var machine = &intcode.Machine{ .memory = program, .ip = 0 }; + + machine.run(); return program[0]; } diff --git a/lib/intcode/intcode.zig b/lib/intcode/intcode.zig index 95a546d..661f8ac 100644 --- a/lib/intcode/intcode.zig +++ b/lib/intcode/intcode.zig @@ -27,86 +27,101 @@ pub fn loadFromStdIn(alloc: *std.mem.Allocator) anyerror![]i32 { return loadFromStream(alloc, stream); } -pub fn run(program: []i32) void { - // Initial program state - var ip: u32 = 0; - var exit: bool = false; +pub const Machine = struct { + memory: []i32, - // TODO: create a nice struct + ip: usize = 0, - while (!exit) { - // std.debug.warn(" IP {d:4}: ", ip); - const opcode = switch (program[ip]) { + pub fn Run(program: []i32) anyerror!Machine { + var machine = try init(program); + + machine.run(); + + return machine; + } + + pub fn init(program: []i32) anyerror!Machine { + return Machine{ .memory = program }; + } + + pub fn run(self: *Machine) void { + while (self.step()) {} + } + + pub fn step(self: *Machine) bool { + var program = self.memory; + + const opcode = switch (program[self.ip]) { 1 => { - var a = program[@intCast(usize, program[ip + 1])]; - var b = program[@intCast(usize, program[ip + 2])]; - var dest = program[ip + 3]; + var a = program[@intCast(usize, program[self.ip + 1])]; + var b = program[@intCast(usize, program[self.ip + 2])]; + var dest = program[self.ip + 3]; var result = a + b; - // std.debug.warn("ADD: [{}] + [{}] => {} : {} + {} = {} => {}\n", ip + 1, ip + 2, dest, a, b, result, dest); program[@intCast(usize, dest)] = result; - ip += 4; + self.ip += 4; }, 2 => { - var a = program[@intCast(usize, program[ip + 1])]; - var b = program[@intCast(usize, program[ip + 2])]; - var dest = program[ip + 3]; + var a = program[@intCast(usize, program[self.ip + 1])]; + var b = program[@intCast(usize, program[self.ip + 2])]; + var dest = program[self.ip + 3]; var result = a * b; - // std.debug.warn("MULT: [{}] + [{}] => {} : {} + {} = {} => {}\n", ip + 1, ip + 2, dest, a, b, result, dest); program[@intCast(usize, dest)] = result; - ip += 4; + self.ip += 4; }, 99 => { - // std.debug.warn("EXIT\n"); - exit = true; + self.ip += 1; + return false; }, else => { - std.debug.warn("Unknown opcode at IP {}: {}", ip, program[ip]); - exit = true; + std.debug.warn("Unknown opcode at IP {}: {}", self.ip, program[self.ip]); + return false; }, }; + + return true; } -} +}; const assert = std.debug.assert; test "day 2 example 1" { var before: [12]i32 = .{ 1, 9, 10, 3, 2, 3, 11, 0, 99, 30, 40, 50 }; var after: [12]i32 = .{ 3500, 9, 10, 70, 2, 3, 11, 0, 99, 30, 40, 50 }; + var machine = Machine.Run(before[0..before.len]); - run(before[0..before.len]); assert(std.mem.eql(i32, before[0..before.len], after[0..after.len])); } test "day 2 example 2" { var before: [5]i32 = .{ 1, 0, 0, 0, 99 }; var after: [5]i32 = .{ 2, 0, 0, 0, 99 }; + var machine = Machine.Run(before[0..before.len]); - run(before[0..before.len]); assert(std.mem.eql(i32, before[0..before.len], after[0..after.len])); } test "day 2 example 3" { var before: [5]i32 = .{ 2, 3, 0, 3, 99 }; var after: [5]i32 = .{ 2, 3, 0, 6, 99 }; + var machine = Machine.Run(before[0..before.len]); - run(before[0..before.len]); assert(std.mem.eql(i32, before[0..before.len], after[0..after.len])); } test "day 2 example 4" { var before: [6]i32 = .{ 2, 4, 4, 5, 99, 0 }; var after: [6]i32 = .{ 2, 4, 4, 5, 99, 9801 }; + var machine = Machine.Run(before[0..before.len]); - run(before[0..before.len]); assert(std.mem.eql(i32, before[0..before.len], after[0..after.len])); } test "day 2 example 5" { var before: [9]i32 = .{ 1, 1, 1, 4, 99, 5, 6, 0, 99 }; var after: [9]i32 = .{ 30, 1, 1, 4, 2, 5, 6, 0, 99 }; + var machine = Machine.Run(before[0..before.len]); - run(before[0..before.len]); assert(std.mem.eql(i32, before[0..before.len], after[0..after.len])); }