This commit is contained in:
2019-12-09 11:37:00 +00:00
parent 289aa920d0
commit 421455f8ba
6 changed files with 123 additions and 24 deletions

View File

@@ -3,6 +3,7 @@ const std = @import("std");
// We're using pipes as character devices
pub const CharDev = [2]i32;
pub const Word = i64;
pub const MemSize = 1024 * 2;
pub fn loadFromStream(alloc: *std.mem.Allocator, stream: *std.fs.File.InStream.Stream) anyerror![]Word {
var program = try alloc.alloc(Word, 1024);
@@ -37,12 +38,14 @@ const Opcode = enum(u8) {
JZ = 6,
LT = 7,
EQ = 8,
RBO = 9,
END = 99,
};
const Mode = enum(u8) {
Position = 0,
Immediate = 1,
Relative = 2,
};
const Instruction = struct {
@@ -79,6 +82,7 @@ const Instruction = struct {
.JZ => 3,
.LT => 4,
.EQ => 4,
.RBO => 2,
.END => 1,
};
}
@@ -93,6 +97,7 @@ pub const Machine = struct {
idx: usize = 0, // handy for debugging
memory: []Word,
rb: Word = 0,
ip: usize = 0,
@@ -108,9 +113,13 @@ pub const Machine = struct {
}
pub fn init(alloc: *std.mem.Allocator, program: []Word) anyerror!Machine {
var memory = try alloc.alloc(Word, MemSize);
std.mem.set(Word, memory, 0);
std.mem.copy(Word, memory, program);
return Machine{
.alloc = alloc,
.memory = program,
.memory = memory,
.input = try std.os.pipe(),
.output = try std.os.pipe(),
};
@@ -121,6 +130,7 @@ pub const Machine = struct {
}
pub fn deinit(self: *Machine) void {
self.alloc.free(self.memory);
std.os.close(self.input[0]);
std.os.close(self.input[1]);
std.os.close(self.output[0]);
@@ -170,12 +180,18 @@ pub const Machine = struct {
return switch (mode) {
.Immediate => immediate,
.Position => self.memory[@intCast(usize, immediate)],
.Relative => self.memory[@intCast(usize, immediate + self.rb)],
};
}
inline fn __write(self: *Machine, parameter: usize, value: Word) void {
inline fn __write(self: *Machine, parameter: usize, mode: Mode, value: Word) void {
const dest = self.__read(parameter, .Immediate);
self.memory[@intCast(usize, dest)] = value;
switch (mode) {
.Immediate => unreachable,
.Position => self.memory[@intCast(usize, dest)] = value,
.Relative => self.memory[@intCast(usize, dest + self.rb)] = value,
}
}
pub fn step(self: *Machine) anyerror!bool {
@@ -187,18 +203,18 @@ pub const Machine = struct {
const a = self.__read(0, insn.modes[0]);
const b = self.__read(1, insn.modes[1]);
self.__write(2, a + b);
self.__write(2, insn.modes[2], a + b);
},
.MULT => {
const a = self.__read(0, insn.modes[0]);
const b = self.__read(1, insn.modes[1]);
self.__write(2, a * b);
self.__write(2, insn.modes[2], a * b);
},
.IN => {
self.__write(0, try self.readFromInput()); // blocking read
self.__write(0, insn.modes[0], try self.readFromInput()); // blocking read
},
.OUT => {
@@ -220,9 +236,9 @@ pub const Machine = struct {
const b = self.__read(1, insn.modes[1]);
if (a < b) {
self.__write(2, 1);
self.__write(2, insn.modes[2], 1);
} else {
self.__write(2, 0);
self.__write(2, insn.modes[2], 0);
}
},
@@ -231,12 +247,16 @@ pub const Machine = struct {
const b = self.__read(1, insn.modes[1]);
if (a == b) {
self.__write(2, 1);
self.__write(2, insn.modes[2], 1);
} else {
self.__write(2, 0);
self.__write(2, insn.modes[2], 0);
}
},
.RBO => {
self.rb += self.__read(0, insn.modes[0]);
},
.END => {
// std.debug.warn("{}: ended\n", self.idx);
},
@@ -256,54 +276,103 @@ test "day 2 example 1" {
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 };
var machine = try Machine.Run(test_allocator, before[0..before.len]);
defer machine.deinit();
assert(std.mem.eql(Word, before[0..before.len], after[0..after.len]));
assert(std.mem.eql(Word, machine.memory[0..before.len], after[0..after.len]));
}
test "day 2 example 2" {
var before: [5]Word = .{ 1, 0, 0, 0, 99 };
var after: [5]Word = .{ 2, 0, 0, 0, 99 };
var machine = try Machine.Run(test_allocator, before[0..before.len]);
defer machine.deinit();
assert(std.mem.eql(Word, before[0..before.len], after[0..after.len]));
assert(std.mem.eql(Word, machine.memory[0..before.len], after[0..after.len]));
}
test "day 2 example 3" {
var before: [5]Word = .{ 2, 3, 0, 3, 99 };
var after: [5]Word = .{ 2, 3, 0, 6, 99 };
var machine = try Machine.Run(test_allocator, before[0..before.len]);
defer machine.deinit();
assert(std.mem.eql(Word, before[0..before.len], after[0..after.len]));
assert(std.mem.eql(Word, machine.memory[0..before.len], after[0..after.len]));
}
test "day 2 example 4" {
var before: [6]Word = .{ 2, 4, 4, 5, 99, 0 };
var after: [6]Word = .{ 2, 4, 4, 5, 99, 9801 };
var machine = try Machine.Run(test_allocator, before[0..before.len]);
defer machine.deinit();
assert(std.mem.eql(Word, before[0..before.len], after[0..after.len]));
assert(std.mem.eql(Word, machine.memory[0..before.len], after[0..after.len]));
}
test "day 2 example 5" {
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 };
var machine = try Machine.Run(test_allocator, before[0..before.len]);
defer machine.deinit();
assert(std.mem.eql(Word, before[0..before.len], after[0..after.len]));
assert(std.mem.eql(Word, machine.memory[0..before.len], after[0..after.len]));
}
test "day 5 example 1" {
var before: [5]Word = .{ 3, 0, 4, 0, 99 };
var after: [5]Word = .{ 666, 0, 4, 0, 99 };
var machine = try Machine.init(test_allocator, before[0..before.len]);
defer machine.deinit();
try machine.writeToInput(666);
try machine.run();
assert(std.mem.eql(Word, before[0..before.len], after[0..after.len]));
assert(std.mem.eql(Word, machine.memory[0..before.len], after[0..after.len]));
assert(666 == try machine.readFromOutput());
}
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());
}
test "Instruction#decode ADD" {
const insn = try Instruction.decode(1);