Day 5.1
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user