2019-12-02 21:09:05 +00:00
|
|
|
const std = @import("std");
|
|
|
|
|
2019-12-07 21:26:59 +00:00
|
|
|
// We're using pipes as character devices
|
|
|
|
pub const CharDev = [2]i32;
|
2019-12-09 10:48:40 +00:00
|
|
|
pub const Word = i64;
|
2019-12-09 11:37:00 +00:00
|
|
|
pub const MemSize = 1024 * 2;
|
2019-12-05 22:31:18 +00:00
|
|
|
|
2019-12-09 10:48:40 +00:00
|
|
|
pub fn loadFromStream(alloc: *std.mem.Allocator, stream: *std.fs.File.InStream.Stream) anyerror![]Word {
|
|
|
|
var program = try alloc.alloc(Word, 1024);
|
2019-12-02 21:09:05 +00:00
|
|
|
|
|
|
|
var buf = [_]u8{0} ** 255;
|
|
|
|
var i: u32 = 0;
|
|
|
|
|
|
|
|
while (try stream.readUntilDelimiterOrEof(&buf, ',')) |num| {
|
|
|
|
var trimmed = std.mem.trimRight(u8, num, "\r\n");
|
2019-12-09 10:48:40 +00:00
|
|
|
program[i] = try std.fmt.parseInt(Word, trimmed, 10);
|
2019-12-02 21:09:05 +00:00
|
|
|
i += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
std.debug.warn("\n");
|
|
|
|
|
|
|
|
return program[0..program.len];
|
|
|
|
}
|
|
|
|
|
2019-12-09 10:48:40 +00:00
|
|
|
pub fn loadFromStdIn(alloc: *std.mem.Allocator) anyerror![]Word {
|
2019-12-02 21:09:05 +00:00
|
|
|
const file = std.io.getStdIn();
|
|
|
|
const stream = &file.inStream().stream;
|
|
|
|
|
|
|
|
return loadFromStream(alloc, stream);
|
|
|
|
}
|
|
|
|
|
2019-12-06 00:10:14 +00:00
|
|
|
const Opcode = enum(u8) {
|
|
|
|
ADD = 1,
|
|
|
|
MULT = 2,
|
|
|
|
IN = 3,
|
|
|
|
OUT = 4,
|
2019-12-06 00:44:48 +00:00
|
|
|
JNZ = 5,
|
|
|
|
JZ = 6,
|
|
|
|
LT = 7,
|
|
|
|
EQ = 8,
|
2019-12-09 11:37:00 +00:00
|
|
|
RBO = 9,
|
2019-12-06 00:10:14 +00:00
|
|
|
END = 99,
|
|
|
|
};
|
|
|
|
|
|
|
|
const Mode = enum(u8) {
|
|
|
|
Position = 0,
|
|
|
|
Immediate = 1,
|
2019-12-09 11:37:00 +00:00
|
|
|
Relative = 2,
|
2019-12-06 00:10:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const Instruction = struct {
|
|
|
|
op: Opcode,
|
|
|
|
|
|
|
|
// Modes for each parameter of the opcode. Parameter 0 is in position 0, etc
|
|
|
|
modes: [3]Mode,
|
|
|
|
|
2019-12-09 10:48:40 +00:00
|
|
|
pub fn decode(value: Word) !Instruction {
|
2019-12-06 00:10:14 +00:00
|
|
|
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,
|
2019-12-06 00:44:48 +00:00
|
|
|
.JNZ => 3,
|
|
|
|
.JZ => 3,
|
|
|
|
.LT => 4,
|
|
|
|
.EQ => 4,
|
2019-12-09 11:37:00 +00:00
|
|
|
.RBO => 2,
|
2019-12-06 00:10:14 +00:00
|
|
|
.END => 1,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn halt(self: Instruction) bool {
|
|
|
|
return self.op == .END;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-12-05 22:07:05 +00:00
|
|
|
pub const Machine = struct {
|
2019-12-07 18:35:03 +00:00
|
|
|
alloc: *std.mem.Allocator,
|
2019-12-07 22:41:14 +00:00
|
|
|
idx: usize = 0, // handy for debugging
|
2019-12-07 18:35:03 +00:00
|
|
|
|
2019-12-09 10:48:40 +00:00
|
|
|
memory: []Word,
|
2019-12-09 11:37:00 +00:00
|
|
|
rb: Word = 0,
|
2019-12-02 21:09:05 +00:00
|
|
|
|
2019-12-05 22:07:05 +00:00
|
|
|
ip: usize = 0,
|
2019-12-02 21:09:05 +00:00
|
|
|
|
2019-12-11 20:40:09 +00:00
|
|
|
halted: bool = false,
|
|
|
|
|
2019-12-05 22:31:18 +00:00
|
|
|
input: CharDev,
|
|
|
|
output: CharDev,
|
|
|
|
|
2019-12-09 10:48:40 +00:00
|
|
|
pub fn Run(alloc: *std.mem.Allocator, program: []Word) anyerror!Machine {
|
2019-12-05 22:31:18 +00:00
|
|
|
var machine = try init(alloc, program);
|
2019-12-05 22:07:05 +00:00
|
|
|
|
2019-12-05 22:31:18 +00:00
|
|
|
try machine.run();
|
2019-12-05 22:07:05 +00:00
|
|
|
|
|
|
|
return machine;
|
|
|
|
}
|
|
|
|
|
2019-12-09 10:48:40 +00:00
|
|
|
pub fn init(alloc: *std.mem.Allocator, program: []Word) anyerror!Machine {
|
2019-12-09 11:37:00 +00:00
|
|
|
var memory = try alloc.alloc(Word, MemSize);
|
|
|
|
std.mem.set(Word, memory, 0);
|
|
|
|
std.mem.copy(Word, memory, program);
|
|
|
|
|
2019-12-05 22:31:18 +00:00
|
|
|
return Machine{
|
2019-12-07 18:35:03 +00:00
|
|
|
.alloc = alloc,
|
2019-12-09 11:37:00 +00:00
|
|
|
.memory = memory,
|
2019-12-07 21:26:59 +00:00
|
|
|
.input = try std.os.pipe(),
|
|
|
|
.output = try std.os.pipe(),
|
2019-12-05 22:31:18 +00:00
|
|
|
};
|
2019-12-05 22:07:05 +00:00
|
|
|
}
|
|
|
|
|
2019-12-05 22:31:18 +00:00
|
|
|
pub fn run(self: *Machine) anyerror!void {
|
|
|
|
while (try self.step()) {}
|
2019-12-05 22:07:05 +00:00
|
|
|
}
|
|
|
|
|
2019-12-07 17:31:23 +00:00
|
|
|
pub fn deinit(self: *Machine) void {
|
2019-12-09 11:37:00 +00:00
|
|
|
self.alloc.free(self.memory);
|
2019-12-07 21:26:59 +00:00
|
|
|
std.os.close(self.input[0]);
|
|
|
|
std.os.close(self.input[1]);
|
|
|
|
std.os.close(self.output[0]);
|
|
|
|
std.os.close(self.output[1]);
|
2019-12-07 18:35:03 +00:00
|
|
|
}
|
|
|
|
|
2019-12-09 10:48:40 +00:00
|
|
|
pub fn readFromInput(self: *Machine) !Word {
|
2019-12-07 21:26:59 +00:00
|
|
|
return self.__in(self.input);
|
2019-12-07 18:35:03 +00:00
|
|
|
}
|
|
|
|
|
2019-12-09 10:48:40 +00:00
|
|
|
pub fn writeToInput(self: *Machine, val: Word) !void {
|
2019-12-07 21:26:59 +00:00
|
|
|
return self.__out(self.input, val);
|
2019-12-07 18:35:03 +00:00
|
|
|
}
|
|
|
|
|
2019-12-09 10:48:40 +00:00
|
|
|
pub fn readFromOutput(self: *Machine) !Word {
|
2019-12-07 21:26:59 +00:00
|
|
|
return self.__in(self.output);
|
2019-12-07 18:35:03 +00:00
|
|
|
}
|
|
|
|
|
2019-12-09 10:48:40 +00:00
|
|
|
pub fn writeToOutput(self: *Machine, val: Word) !void {
|
2019-12-07 21:26:59 +00:00
|
|
|
return self.__out(self.output, val);
|
2019-12-07 18:35:03 +00:00
|
|
|
}
|
|
|
|
|
2019-12-09 10:48:40 +00:00
|
|
|
fn __in(self: *Machine, dev: CharDev) !Word {
|
2019-12-07 21:26:59 +00:00
|
|
|
const fd = dev[0]; // Read from the pipe
|
2019-12-09 10:48:40 +00:00
|
|
|
var store: [8]u8 = undefined;
|
2019-12-07 18:35:03 +00:00
|
|
|
|
2019-12-07 22:41:14 +00:00
|
|
|
// std.debug.warn("{}: __in({} <- {})\n", self.idx, dev[0], dev[1]);
|
2019-12-07 21:26:59 +00:00
|
|
|
var n = try std.os.read(fd, &store);
|
2019-12-09 10:48:40 +00:00
|
|
|
std.debug.assert(n == 8); // TODO: handle partial reads
|
2019-12-07 18:35:03 +00:00
|
|
|
|
2019-12-09 10:48:40 +00:00
|
|
|
return std.mem.readIntNative(Word, &store);
|
2019-12-07 18:35:03 +00:00
|
|
|
}
|
|
|
|
|
2019-12-09 10:48:40 +00:00
|
|
|
fn __out(self: *Machine, dev: CharDev, val: Word) !void {
|
2019-12-07 21:26:59 +00:00
|
|
|
const fd = dev[1]; // Write to the pipe
|
|
|
|
const bytes = std.mem.asBytes(&val);
|
2019-12-07 18:35:03 +00:00
|
|
|
|
2019-12-07 22:41:14 +00:00
|
|
|
// std.debug.warn("{}: __out({} -> {}, {})\n", self.idx, dev[1], dev[0], val);
|
2019-12-07 21:26:59 +00:00
|
|
|
try std.os.write(fd, bytes);
|
2019-12-07 17:31:23 +00:00
|
|
|
}
|
|
|
|
|
2019-12-06 00:10:14 +00:00
|
|
|
/// Read an immediate or position value from memory. Parameter determines
|
|
|
|
/// which field following the current instruction to read from
|
2019-12-09 10:48:40 +00:00
|
|
|
inline fn __read(self: *Machine, parameter: usize, mode: Mode) Word {
|
2019-12-06 00:10:14 +00:00
|
|
|
const immediate = self.memory[self.ip + parameter + 1];
|
|
|
|
|
|
|
|
return switch (mode) {
|
|
|
|
.Immediate => immediate,
|
|
|
|
.Position => self.memory[@intCast(usize, immediate)],
|
2019-12-09 11:37:00 +00:00
|
|
|
.Relative => self.memory[@intCast(usize, immediate + self.rb)],
|
2019-12-06 00:10:14 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2019-12-09 11:37:00 +00:00
|
|
|
inline fn __write(self: *Machine, parameter: usize, mode: Mode, value: Word) void {
|
2019-12-06 00:10:14 +00:00
|
|
|
const dest = self.__read(parameter, .Immediate);
|
2019-12-09 11:37:00 +00:00
|
|
|
|
|
|
|
switch (mode) {
|
|
|
|
.Immediate => unreachable,
|
|
|
|
.Position => self.memory[@intCast(usize, dest)] = value,
|
|
|
|
.Relative => self.memory[@intCast(usize, dest + self.rb)] = value,
|
|
|
|
}
|
2019-12-06 00:10:14 +00:00
|
|
|
}
|
|
|
|
|
2019-12-05 22:31:18 +00:00
|
|
|
pub fn step(self: *Machine) anyerror!bool {
|
2019-12-06 00:44:48 +00:00
|
|
|
const insn = try Instruction.decode(self.memory[self.ip]);
|
|
|
|
const start_ip = self.ip;
|
2019-12-05 22:07:05 +00:00
|
|
|
|
2019-12-06 00:10:14 +00:00
|
|
|
const opcode = switch (insn.op) {
|
|
|
|
.ADD => {
|
|
|
|
const a = self.__read(0, insn.modes[0]);
|
|
|
|
const b = self.__read(1, insn.modes[1]);
|
2019-12-02 21:09:05 +00:00
|
|
|
|
2019-12-09 11:37:00 +00:00
|
|
|
self.__write(2, insn.modes[2], a + b);
|
2019-12-02 21:09:05 +00:00
|
|
|
},
|
2019-12-05 22:45:18 +00:00
|
|
|
|
2019-12-06 00:10:14 +00:00
|
|
|
.MULT => {
|
|
|
|
const a = self.__read(0, insn.modes[0]);
|
|
|
|
const b = self.__read(1, insn.modes[1]);
|
2019-12-05 22:45:18 +00:00
|
|
|
|
2019-12-09 11:37:00 +00:00
|
|
|
self.__write(2, insn.modes[2], a * b);
|
2019-12-05 22:45:18 +00:00
|
|
|
},
|
2019-12-06 00:10:14 +00:00
|
|
|
|
|
|
|
.IN => {
|
2019-12-09 11:37:00 +00:00
|
|
|
self.__write(0, insn.modes[0], try self.readFromInput()); // blocking read
|
2019-12-02 21:09:05 +00:00
|
|
|
},
|
2019-12-06 00:44:48 +00:00
|
|
|
|
2019-12-06 00:10:14 +00:00
|
|
|
.OUT => {
|
2019-12-07 18:35:03 +00:00
|
|
|
try self.writeToOutput(self.__read(0, insn.modes[0]));
|
2019-12-02 21:09:05 +00:00
|
|
|
},
|
2019-12-06 00:44:48 +00:00
|
|
|
|
|
|
|
.JNZ => {
|
|
|
|
if (self.__read(0, insn.modes[0]) != 0)
|
|
|
|
self.ip = @intCast(usize, self.__read(1, insn.modes[1]));
|
|
|
|
},
|
|
|
|
|
|
|
|
.JZ => {
|
|
|
|
if (self.__read(0, insn.modes[0]) == 0)
|
|
|
|
self.ip = @intCast(usize, self.__read(1, insn.modes[1]));
|
|
|
|
},
|
|
|
|
|
|
|
|
.LT => {
|
|
|
|
const a = self.__read(0, insn.modes[0]);
|
|
|
|
const b = self.__read(1, insn.modes[1]);
|
|
|
|
|
|
|
|
if (a < b) {
|
2019-12-09 11:37:00 +00:00
|
|
|
self.__write(2, insn.modes[2], 1);
|
2019-12-06 00:44:48 +00:00
|
|
|
} else {
|
2019-12-09 11:37:00 +00:00
|
|
|
self.__write(2, insn.modes[2], 0);
|
2019-12-06 00:44:48 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
.EQ => {
|
|
|
|
const a = self.__read(0, insn.modes[0]);
|
|
|
|
const b = self.__read(1, insn.modes[1]);
|
|
|
|
|
|
|
|
if (a == b) {
|
2019-12-09 11:37:00 +00:00
|
|
|
self.__write(2, insn.modes[2], 1);
|
2019-12-06 00:44:48 +00:00
|
|
|
} else {
|
2019-12-09 11:37:00 +00:00
|
|
|
self.__write(2, insn.modes[2], 0);
|
2019-12-06 00:44:48 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2019-12-09 11:37:00 +00:00
|
|
|
.RBO => {
|
|
|
|
self.rb += self.__read(0, insn.modes[0]);
|
|
|
|
},
|
|
|
|
|
2019-12-11 20:40:09 +00:00
|
|
|
.END => self.halted = true,
|
2019-12-02 21:09:05 +00:00
|
|
|
};
|
2019-12-05 22:07:05 +00:00
|
|
|
|
2019-12-06 00:44:48 +00:00
|
|
|
// Only modify IP if the instruction itself has not
|
|
|
|
if (self.ip == start_ip) self.ip += insn.size();
|
|
|
|
|
2019-12-06 00:10:14 +00:00
|
|
|
return !insn.halt();
|
2019-12-02 21:09:05 +00:00
|
|
|
}
|
2019-12-05 22:07:05 +00:00
|
|
|
};
|
2019-12-05 19:45:14 +00:00
|
|
|
|
|
|
|
const assert = std.debug.assert;
|
2019-12-05 22:31:18 +00:00
|
|
|
const test_allocator = std.heap.page_allocator;
|
2019-12-05 19:45:14 +00:00
|
|
|
|
|
|
|
test "day 2 example 1" {
|
2019-12-09 10:48:40 +00:00
|
|
|
var before: [12]Word = .{ 1, 9, 10, 3, 2, 3, 11, 0, 99, 30, 40, 50 };
|
|
|
|
var after: [12]Word = .{ 3500, 9, 10, 70, 2, 3, 11, 0, 99, 30, 40, 50 };
|
2019-12-05 22:31:18 +00:00
|
|
|
var machine = try Machine.Run(test_allocator, before[0..before.len]);
|
2019-12-09 11:37:00 +00:00
|
|
|
defer machine.deinit();
|
2019-12-05 19:45:14 +00:00
|
|
|
|
2019-12-09 11:37:00 +00:00
|
|
|
assert(std.mem.eql(Word, machine.memory[0..before.len], after[0..after.len]));
|
2019-12-05 19:45:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
test "day 2 example 2" {
|
2019-12-09 10:48:40 +00:00
|
|
|
var before: [5]Word = .{ 1, 0, 0, 0, 99 };
|
|
|
|
var after: [5]Word = .{ 2, 0, 0, 0, 99 };
|
2019-12-05 22:31:18 +00:00
|
|
|
var machine = try Machine.Run(test_allocator, before[0..before.len]);
|
2019-12-09 11:37:00 +00:00
|
|
|
defer machine.deinit();
|
2019-12-05 19:45:14 +00:00
|
|
|
|
2019-12-09 11:37:00 +00:00
|
|
|
assert(std.mem.eql(Word, machine.memory[0..before.len], after[0..after.len]));
|
2019-12-05 19:45:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
test "day 2 example 3" {
|
2019-12-09 10:48:40 +00:00
|
|
|
var before: [5]Word = .{ 2, 3, 0, 3, 99 };
|
|
|
|
var after: [5]Word = .{ 2, 3, 0, 6, 99 };
|
2019-12-05 22:31:18 +00:00
|
|
|
var machine = try Machine.Run(test_allocator, before[0..before.len]);
|
2019-12-09 11:37:00 +00:00
|
|
|
defer machine.deinit();
|
2019-12-05 19:45:14 +00:00
|
|
|
|
2019-12-09 11:37:00 +00:00
|
|
|
assert(std.mem.eql(Word, machine.memory[0..before.len], after[0..after.len]));
|
2019-12-05 19:45:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
test "day 2 example 4" {
|
2019-12-09 10:48:40 +00:00
|
|
|
var before: [6]Word = .{ 2, 4, 4, 5, 99, 0 };
|
|
|
|
var after: [6]Word = .{ 2, 4, 4, 5, 99, 9801 };
|
2019-12-05 22:31:18 +00:00
|
|
|
var machine = try Machine.Run(test_allocator, before[0..before.len]);
|
2019-12-09 11:37:00 +00:00
|
|
|
defer machine.deinit();
|
2019-12-05 19:45:14 +00:00
|
|
|
|
2019-12-09 11:37:00 +00:00
|
|
|
assert(std.mem.eql(Word, machine.memory[0..before.len], after[0..after.len]));
|
2019-12-05 19:45:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
test "day 2 example 5" {
|
2019-12-09 10:48:40 +00:00
|
|
|
var before: [9]Word = .{ 1, 1, 1, 4, 99, 5, 6, 0, 99 };
|
|
|
|
var after: [9]Word = .{ 30, 1, 1, 4, 2, 5, 6, 0, 99 };
|
2019-12-05 22:31:18 +00:00
|
|
|
var machine = try Machine.Run(test_allocator, before[0..before.len]);
|
2019-12-09 11:37:00 +00:00
|
|
|
defer machine.deinit();
|
2019-12-05 22:31:18 +00:00
|
|
|
|
2019-12-09 11:37:00 +00:00
|
|
|
assert(std.mem.eql(Word, machine.memory[0..before.len], after[0..after.len]));
|
2019-12-05 22:31:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
test "day 5 example 1" {
|
2019-12-09 10:48:40 +00:00
|
|
|
var before: [5]Word = .{ 3, 0, 4, 0, 99 };
|
|
|
|
var after: [5]Word = .{ 666, 0, 4, 0, 99 };
|
2019-12-05 22:31:18 +00:00
|
|
|
var machine = try Machine.init(test_allocator, before[0..before.len]);
|
2019-12-09 11:37:00 +00:00
|
|
|
defer machine.deinit();
|
2019-12-05 22:31:18 +00:00
|
|
|
|
2019-12-07 18:35:03 +00:00
|
|
|
try machine.writeToInput(666);
|
2019-12-05 22:31:18 +00:00
|
|
|
try machine.run();
|
2019-12-02 21:09:05 +00:00
|
|
|
|
2019-12-09 11:37:00 +00:00
|
|
|
assert(std.mem.eql(Word, machine.memory[0..before.len], after[0..after.len]));
|
2019-12-07 21:26:59 +00:00
|
|
|
assert(666 == try machine.readFromOutput());
|
2019-12-02 21:09:05 +00:00
|
|
|
}
|
2019-12-06 00:10:14 +00:00
|
|
|
|
2019-12-09 11:37:00 +00:00
|
|
|
test "day 9 example 1" {
|
|
|
|
var before: [16]Word = .{ 109, 1, 204, -1, 1001, 100, 1, 100, 1008, 100, 16, 101, 1006, 101, 0, 99 };
|
|
|
|
var after: [16]Word = before;
|
|
|
|
var output: [16]Word = undefined;
|
|
|
|
|
|
|
|
var machine = try Machine.init(test_allocator, before[0..before.len]);
|
|
|
|
defer machine.deinit();
|
|
|
|
try machine.run();
|
|
|
|
|
|
|
|
assert(std.mem.eql(Word, machine.memory[0..before.len], after[0..after.len]));
|
|
|
|
|
|
|
|
for (output) |*b| {
|
|
|
|
b.* = try machine.readFromOutput();
|
|
|
|
}
|
|
|
|
|
|
|
|
// This program produces a copy of itself as output
|
|
|
|
assert(std.mem.eql(Word, machine.memory[0..before.len], output[0..after.len]));
|
|
|
|
}
|
|
|
|
|
|
|
|
test "day 9 example 2" {
|
|
|
|
var before: [8]Word = .{ 1102, 34915192, 34915192, 7, 4, 7, 99, 0 };
|
|
|
|
var after: [8]Word = .{ 1102, 34915192, 34915192, 7, 4, 7, 99, 1219070632396864 };
|
|
|
|
|
|
|
|
var machine = try Machine.init(test_allocator, before[0..before.len]);
|
|
|
|
defer machine.deinit();
|
|
|
|
try machine.run();
|
|
|
|
|
|
|
|
assert(std.mem.eql(Word, machine.memory[0..before.len], after[0..after.len]));
|
|
|
|
std.debug.assert(1219070632396864 == try machine.readFromOutput());
|
|
|
|
}
|
|
|
|
|
|
|
|
test "day 9 example 3" {
|
|
|
|
var before: [3]Word = .{ 104, 1125899906842624, 99 };
|
|
|
|
var after: [3]Word = before;
|
|
|
|
|
|
|
|
var machine = try Machine.init(test_allocator, before[0..before.len]);
|
|
|
|
defer machine.deinit();
|
|
|
|
try machine.run();
|
|
|
|
|
|
|
|
assert(std.mem.eql(Word, machine.memory[0..before.len], after[0..after.len]));
|
|
|
|
std.debug.assert(1125899906842624 == try machine.readFromOutput());
|
|
|
|
}
|
|
|
|
|
2019-12-06 00:10:14 +00:00
|
|
|
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);
|
|
|
|
}
|