diff --git a/05/build.zig b/05/build.zig new file mode 100644 index 0000000..c228b31 --- /dev/null +++ b/05/build.zig @@ -0,0 +1,15 @@ +const Builder = @import("std").build.Builder; + +pub fn build(b: *Builder) void { + const mode = b.standardReleaseOptions(); + const exe = b.addExecutable("05", "src/main.zig"); + exe.addPackagePath("intcode", "../lib/intcode/intcode.zig"); + exe.setBuildMode(mode); + exe.install(); + + const run_cmd = exe.run(); + run_cmd.step.dependOn(b.getInstallStep()); + + const run_step = b.step("run", "Run the app"); + run_step.dependOn(&run_cmd.step); +} diff --git a/05/input b/05/input new file mode 100644 index 0000000..2109937 --- /dev/null +++ b/05/input @@ -0,0 +1 @@ +3,225,1,225,6,6,1100,1,238,225,104,0,1102,40,93,224,1001,224,-3720,224,4,224,102,8,223,223,101,3,224,224,1,224,223,223,1101,56,23,225,1102,64,78,225,1102,14,11,225,1101,84,27,225,1101,7,82,224,1001,224,-89,224,4,224,1002,223,8,223,1001,224,1,224,1,224,223,223,1,35,47,224,1001,224,-140,224,4,224,1002,223,8,223,101,5,224,224,1,224,223,223,1101,75,90,225,101,9,122,224,101,-72,224,224,4,224,1002,223,8,223,101,6,224,224,1,224,223,223,1102,36,63,225,1002,192,29,224,1001,224,-1218,224,4,224,1002,223,8,223,1001,224,7,224,1,223,224,223,102,31,218,224,101,-2046,224,224,4,224,102,8,223,223,101,4,224,224,1,224,223,223,1001,43,38,224,101,-52,224,224,4,224,1002,223,8,223,101,5,224,224,1,223,224,223,1102,33,42,225,2,95,40,224,101,-5850,224,224,4,224,1002,223,8,223,1001,224,7,224,1,224,223,223,1102,37,66,225,4,223,99,0,0,0,677,0,0,0,0,0,0,0,0,0,0,0,1105,0,99999,1105,227,247,1105,1,99999,1005,227,99999,1005,0,256,1105,1,99999,1106,227,99999,1106,0,265,1105,1,99999,1006,0,99999,1006,227,274,1105,1,99999,1105,1,280,1105,1,99999,1,225,225,225,1101,294,0,0,105,1,0,1105,1,99999,1106,0,300,1105,1,99999,1,225,225,225,1101,314,0,0,106,0,0,1105,1,99999,1007,226,677,224,1002,223,2,223,1005,224,329,1001,223,1,223,1007,226,226,224,1002,223,2,223,1006,224,344,101,1,223,223,1107,677,226,224,102,2,223,223,1006,224,359,1001,223,1,223,108,677,677,224,1002,223,2,223,1006,224,374,1001,223,1,223,107,677,677,224,1002,223,2,223,1005,224,389,101,1,223,223,8,677,677,224,1002,223,2,223,1005,224,404,1001,223,1,223,108,226,226,224,1002,223,2,223,1005,224,419,101,1,223,223,1008,677,677,224,1002,223,2,223,1005,224,434,101,1,223,223,1008,226,226,224,1002,223,2,223,1005,224,449,101,1,223,223,7,677,226,224,1002,223,2,223,1006,224,464,1001,223,1,223,7,226,226,224,1002,223,2,223,1005,224,479,1001,223,1,223,1007,677,677,224,102,2,223,223,1005,224,494,101,1,223,223,1108,677,226,224,102,2,223,223,1006,224,509,1001,223,1,223,8,677,226,224,102,2,223,223,1005,224,524,1001,223,1,223,1107,226,226,224,102,2,223,223,1006,224,539,1001,223,1,223,1008,226,677,224,1002,223,2,223,1006,224,554,1001,223,1,223,1107,226,677,224,1002,223,2,223,1006,224,569,1001,223,1,223,1108,677,677,224,102,2,223,223,1005,224,584,101,1,223,223,7,226,677,224,102,2,223,223,1006,224,599,1001,223,1,223,1108,226,677,224,102,2,223,223,1006,224,614,101,1,223,223,107,226,677,224,1002,223,2,223,1005,224,629,101,1,223,223,108,226,677,224,1002,223,2,223,1005,224,644,101,1,223,223,8,226,677,224,1002,223,2,223,1005,224,659,1001,223,1,223,107,226,226,224,1002,223,2,223,1006,224,674,101,1,223,223,4,223,99,226 diff --git a/05/src/main.zig b/05/src/main.zig new file mode 100644 index 0000000..ae55384 --- /dev/null +++ b/05/src/main.zig @@ -0,0 +1,20 @@ +const std = @import("std"); +const intcode = @import("intcode"); + +pub fn main() anyerror!void { + var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); + defer arena.deinit(); + + const alloc = &arena.allocator; + + var program = try intcode.loadFromStdIn(alloc); + var machine = try intcode.Machine.init(alloc, program); + + try machine.input.append(1); // Air conditioner unit + try machine.run(); + + std.debug.warn("Part 1\n"); + for (machine.output.toSlice()) |value, idx| { + std.debug.warn("Test {}: {}\n", idx, value); + } +} diff --git a/lib/intcode/intcode.zig b/lib/intcode/intcode.zig index fe9b82b..50460ca 100644 --- a/lib/intcode/intcode.zig +++ b/lib/intcode/intcode.zig @@ -30,6 +30,58 @@ pub fn loadFromStdIn(alloc: *std.mem.Allocator) anyerror![]i32 { return loadFromStream(alloc, stream); } +const Opcode = enum(u8) { + ADD = 1, + MULT = 2, + IN = 3, + OUT = 4, + END = 99, +}; + +const Mode = enum(u8) { + Position = 0, + Immediate = 1, +}; + +const Instruction = struct { + op: Opcode, + + // Modes for each parameter of the opcode. Parameter 0 is in position 0, etc + modes: [3]Mode, + + pub fn decode(value: i32) !Instruction { + assert(value > 0 and value < 99999); + + var buf: [6]u8 = undefined; + const str = try std.fmt.bufPrint(&buf, "{d:0<6}", value); + const op = ((str[4] - '0') * 10) + (str[5] - '0'); + + return Instruction{ + .op = @intToEnum(Opcode, op), + .modes = [3]Mode{ + @intToEnum(Mode, buf[3] - '0'), + @intToEnum(Mode, buf[2] - '0'), + @intToEnum(Mode, buf[1] - '0'), + }, + }; + } + + /// Number of bytes taken up by a particular instruction + pub fn size(self: Instruction) usize { + return switch (self.op) { + .ADD => 4, + .MULT => 4, + .IN => 2, + .OUT => 2, + .END => 1, + }; + } + + pub fn halt(self: Instruction) bool { + return self.op == .END; + } +}; + pub const Machine = struct { memory: []i32, @@ -58,52 +110,52 @@ pub const Machine = struct { while (try self.step()) {} } + /// Read an immediate or position value from memory. Parameter determines + /// which field following the current instruction to read from + inline fn __read(self: *Machine, parameter: usize, mode: Mode) i32 { + const immediate = self.memory[self.ip + parameter + 1]; + + return switch (mode) { + .Immediate => immediate, + .Position => self.memory[@intCast(usize, immediate)], + }; + } + + inline fn __write(self: *Machine, parameter: usize, value: i32) void { + const dest = self.__read(parameter, .Immediate); + self.memory[@intCast(usize, dest)] = value; + } + pub fn step(self: *Machine) anyerror!bool { var program = self.memory; + const insn = try Instruction.decode(program[self.ip]); - const opcode = switch (program[self.ip]) { - 1 => { - 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; + const opcode = switch (insn.op) { + .ADD => { + const a = self.__read(0, insn.modes[0]); + const b = self.__read(1, insn.modes[1]); - program[@intCast(usize, dest)] = result; - self.ip += 4; + self.__write(2, a + b); }, - 2 => { - 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; - program[@intCast(usize, dest)] = result; - self.ip += 4; - }, - 3 => { - const input = self.input.orderedRemove(0); - const dest = program[self.ip + 1]; + .MULT => { + const a = self.__read(0, insn.modes[0]); + const b = self.__read(1, insn.modes[1]); - program[@intCast(usize, dest)] = input; - self.ip += 2; + self.__write(2, a * b); }, - 4 => { - const output = program[@intCast(usize, program[self.ip + 1])]; - try self.output.append(output); - self.ip += 2; + .IN => { + self.__write(0, self.input.orderedRemove(0)); }, - 99 => { - self.ip += 1; - return false; - }, - else => { - std.debug.warn("Unknown opcode at IP {}: {}\n", self.ip, program[self.ip]); - return false; + .OUT => { + try self.output.append(self.__read(0, insn.modes[0])); }, + .END => {}, }; - return true; + self.ip += insn.size(); + return !insn.halt(); } }; @@ -162,3 +214,66 @@ test "day 5 example 1" { assert(machine.output.len == 1); assert(machine.output.at(0) == 666); } + +test "Instruction#decode ADD" { + const insn = try Instruction.decode(1); + + assert(insn.op == Opcode.ADD); + assert(insn.modes[0] == .Position); + assert(insn.modes[1] == .Position); + assert(insn.modes[2] == .Position); +} + +test "Instruction#decode MULT" { + const insn = try Instruction.decode(2); + + assert(insn.op == Opcode.MULT); + assert(insn.modes[0] == .Position); + assert(insn.modes[1] == .Position); + assert(insn.modes[2] == .Position); +} + +test "Instruction#decode IN" { + const insn = try Instruction.decode(3); + + assert(insn.op == Opcode.IN); + assert(insn.modes[0] == .Position); + assert(insn.modes[1] == .Position); + assert(insn.modes[2] == .Position); +} + +test "Instruction#decode OUT" { + const insn = try Instruction.decode(4); + + assert(insn.op == Opcode.OUT); + assert(insn.modes[0] == .Position); + assert(insn.modes[1] == .Position); + assert(insn.modes[2] == .Position); +} + +test "Instruction#decode END Position" { + const insn = try Instruction.decode(99); + + assert(insn.op == Opcode.END); + assert(insn.modes[0] == .Position); + assert(insn.modes[1] == .Position); + assert(insn.modes[2] == .Position); +} + +test "Instruction#decode END Immediate" { + const insn = try Instruction.decode(11199); + + assert(insn.op == Opcode.END); + assert(insn.modes[0] == .Immediate); + assert(insn.modes[1] == .Immediate); + assert(insn.modes[2] == .Immediate); +} + +test "Instruction#decode END mixed" { + const insn = try Instruction.decode(10099); + + assert(insn.op == Opcode.END); + assert(insn.modes[0] == .Position); + assert(insn.modes[1] == .Position); + assert(insn.modes[2] == .Immediate); +}