This commit is contained in:
2019-12-06 00:10:14 +00:00
parent a46f56da7f
commit 156e9250b3
4 changed files with 184 additions and 33 deletions

View File

@@ -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);
}