Public
Edited
Dec 13
Paused
Importers
2 stars
Also listed in…
Ξ🎄Advent of Code 2019
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
class Computer {
// -------------------------- Initialise Computer
constructor(inputs = [0], instrs = [99]) {
// -------------------------- Union types
this.Status = {
Running: AOC.type("Running", []),
AwaitingInput: AOC.type("AwaitingInput", []),
Halted: AOC.type("Halted", [])
};
this.Mode = {
Position: AOC.type("Position", []),
Immediate: AOC.type("Immediate", []),
Relative: AOC.type("Relative", [])
};
this.Opcode = {
Add: (a, b, c) => AOC.type("Add", [a, b, c]),
Mult: (a, b, c) => AOC.type("Mult", [a, b, c]),
Input: (a) => AOC.type("Input", [a]),
Output: (a) => AOC.type("Output", [a]),
JmpIfTrue: (a, b) => AOC.type("JmpIfTrue", [a, b]),
JmpIfFalse: (a, b) => AOC.type("JmpIfFalse", [a, b]),
LessThan: (a, b, c) => AOC.type("LessThan", [a, b, c]),
Equals: (a, b, c) => AOC.type("Equals", [a, b, c]),
ShiftBase: (a) => AOC.type("ShiftBase", [a]),
Halt: AOC.type("Halt", []),
NoOp: AOC.type("NoOp", [])
};

this.mem = instrs.map(AOC.identity); // Clone the program in memory.
this.outputStore = [];
this.inputStore = inputs.map(AOC.identity); // Clone the inputs into the input store
this.instrPtr = 0; // Instruction pointer. i.e. address of the current instruction to process.
this.relativeBase = 0; // Offset for relative instructions.
this.out = 0; // Single ouput value, default.
this.status = this.Status.Running;
}

// -------------------------- Memory
read(addr, mode = this.Mode.Immediate) {
return mode.case({
Immediate: () => (this.mem[addr] === undefined ? 0 : this.mem[addr]),
Position: () =>
this.read(this.mem[addr] === undefined ? 0 : this.mem[addr]),
Relative: () =>
this.read(
this.relativeBase +
(this.mem[addr] === undefined ? 0 : this.mem[addr])
)
});
}

poke(addr, val) {
this.mem[addr] = val;
return this;
}

// -------------------------- Adding input
addInput(input) {
this.inputStore.unshift(input);
return this;
}

addInputs(inputs) {
this.inputStore.unshift(...inputs);
return this;
}

// -------------------------- Operations
readOp(addr) {
const toMode = (modeNum) =>
modeNum === "1"
? this.Mode.Immediate
: modeNum === "2"
? this.Mode.Relative
: this.Mode.Position;

// OpCode is in the rightmost two digits, the mode of each parameter stored in the other digits.
const [modes, opcode] = [
("" + Math.floor(this.read(addr) / 100)).split("").map(toMode).reverse(),
this.read(addr) % 100
];

const readParam = this.read(
addr + 1,
modes.length > 0 ? modes[0] : this.Mode.Position
);
const readAddressModeParam = (a, md) => {
const offset = md === this.Mode.Relative ? this.relativeBase : 0;
return offset + this.read(addr + a);
};
const readAddressParam = (a) =>
readAddressModeParam(a, modes.length > 0 ? modes[0] : this.Mode.Position);
const read3Params = [
this.read(addr + 1, modes.length > 0 ? modes[0] : this.Mode.Position),
this.read(addr + 2, modes.length > 1 ? modes[1] : this.Mode.Position),
readAddressModeParam(3, modes.length > 2 ? modes[2] : this.Mode.Position)
];
switch (opcode) {
case 1:
return this.Opcode.Add(...read3Params);
case 2:
return this.Opcode.Mult(...read3Params);
case 3:
return this.Opcode.Input(readAddressParam(1));
case 4:
return this.Opcode.Output(readParam);
case 5:
return this.Opcode.JmpIfTrue(...read3Params);
case 6:
return this.Opcode.JmpIfFalse(...read3Params);
case 7:
return this.Opcode.LessThan(...read3Params);
case 8:
return this.Opcode.Equals(...read3Params);
case 9:
return this.Opcode.ShiftBase(readParam);
case 99:
return this.Opcode.Halt;
default:
return this.Opcode.NoOp;
}
}

// -------------------------- Execution
run() {
let addr = this.instrPtr;
while (
this.status === this.Status.Running ||
(this.status === this.Status.AwaitingInput && this.inputStore.length > 0)
) {
this.readOp(addr).case({
Add: (p1, p2, p3) => {
this.instrPtr = addr + 4;
this.mem[p3] = p1 + p2;
addr += 4;
},
Mult: (p1, p2, p3) => {
this.instrPtr = addr + 4;
this.mem[p3] = p1 * p2;
addr += 4;
},
Input: (p1) => {
if (this.inputStore.length > 0) {
this.mem[p1] = this.inputStore.shift();
this.status = this.Status.Running;
} else {
this.status = this.Status.AwaitingInput;
}
addr += 2;
},
Output: (p1) => {
this.out = p1;
this.outputStore.push(p1);
this.instrPtr = addr + 2;
addr += 2;
},
JmpIfTrue: (p1, p2, p3) => {
const newAddr = p1 === 0 ? addr + 3 : p2;
this.instrPtr = newAddr;
addr = this.instrPtr;
},
JmpIfFalse: (p1, p2, p3) => {
const newAddr = p1 === 0 ? p2 : addr + 3;
this.instrPtr = newAddr;
addr = this.instrPtr;
},
LessThan: (p1, p2, p3) => {
this.instrPtr = addr + 4;
this.mem[p3] = p1 < p2 ? 1 : 0;
addr += 4;
},
Equals: (p1, p2, p3) => {
this.instrPtr = addr + 4;
this.mem[p3] = p1 === p2 ? 1 : 0;
addr += 4;
},
ShiftBase: (p1) => {
this.instrPtr = addr + 2;
this.relativeBase = this.relativeBase + p1;
addr += 2;
},

Halt: () => {
this.status = this.Status.Halted;
},
NoOp: () => {
this.status = this.Status.Halted;
}
});
}
return this;
}
}
Insert cell
Insert cell
Insert cell
{
const input = 123;
const prog = [3, 50, 4, 50, 99];
return AOC.assert(new Computer([input], prog).run().out, input);
}
Insert cell
Insert cell
{
const prog = [1002, 4, 3, 4, 33];
return AOC.assert(new Computer([0], prog).run().read(4), 99);
}
Insert cell
Insert cell
{
const input = 8;
const prog = [3, 9, 8, 9, 10, 9, 4, 9, 99, -1, 8];
return AOC.assert(new Computer([input], prog).run().out, input === 8 ? 1 : 0);
}
Insert cell
Insert cell
{
const input = 7;
const prog = [3, 9, 7, 9, 10, 9, 4, 9, 99, -1, 8];
return AOC.assert(new Computer([input], prog).run().out, input < 8 ? 1 : 0);
}
Insert cell
Insert cell
{
const input = 7;
const prog = [
3, 21, 1008, 21, 8, 20, 1005, 20, 22, 107, 8, 21, 20, 1006, 20, 31, 1106, 0,
36, 98, 0, 0, 1002, 21, 125, 20, 4, 20, 1105, 1, 46, 104, 999, 1105, 1, 46,
1101, 1000, 1, 20, 4, 20, 1105, 1, 46, 98, 99
];
return AOC.assert(
new Computer([input], prog).run().out,
input < 8 ? 999 : input === 8 ? 1000 : 1001
);
}
Insert cell
Insert cell
{
const input = 17;
const prog = [3, 10, 4, 10, 3, 11, 4, 11, 99];
const comp = new Computer([input], prog).run();
return AOC.assert(
comp.out === input && comp.status.label === "AwaitingInput",
true
);
}
Insert cell
Insert cell
{
const [input1, input2] = [123, 456];
const prog = [3, 10, 4, 10, 3, 11, 4, 11, 99];
const output = new Computer([input1], prog)
.run()
.addInput(input2)
.run().outputStore;
return AOC.assert(AOC.equalArrays(output, [input1, input2]), true);
}
Insert cell
Insert cell
{
const input = 13;
const prog = [109, 50, 203, 0, 204, 0, 99];
return AOC.assert(new Computer([input], prog).run().out, input);
}
Insert cell
Insert cell
{
const input = 99;
const prog = [109, 50, 203, 11, 207, 11, 12, 11, 4, 11, 99, -1, 8];
return AOC.assert(new Computer([input], prog).run().out, input < 8 ? 1 : 0);
}
Insert cell
Insert cell
{
const input = 123;
const prog = [109, 500, 203, 50, 204, 50, 99];
return AOC.assert(new Computer([input], prog).run().out, input);
}
Insert cell
Insert cell
{
const prog = [
109, 1, 204, -1, 1001, 100, 1, 100, 1008, 100, 16, 101, 1006, 101, 0, 99
];
const output = new Computer([], prog).run().outputStore;
return AOC.assert(AOC.equalArrays(output, prog), true);
}
Insert cell
Insert cell
{
const prog = [1102, 34915192, 34915192, 7, 4, 7, 99, 0];
return AOC.assert(new Computer([], prog).run().out, 34915192 * 34915192);
}
Insert cell
Insert cell
{
const prog = [104, 1125899906842624, 99];
return AOC.assert(new Computer([], prog).run().out, 1125899906842624);
}
Insert cell
Insert cell
Insert cell
{
const input = 13;
const prog = [109, 500, 203, 50, 2201, 50, 50, 60, 4, 60, 99];
return AOC.assert(new Computer([input], prog).run().out, 2 * input);
}
Insert cell
Insert cell
{
const input = 13;
const prog = [109, 500, 203, 50, 2202, 50, 50, 60, 4, 60, 99];
return AOC.assert(new Computer([input], prog).run().out, input * input);
}
Insert cell
Insert cell
{
const prog = [109, 500, 203, 50, 1205, 50, 10, 104, -1, 99, 104, 1, 99];
return AOC.assert(new Computer([0], prog).run().out, -1);
}
Insert cell
Insert cell
{
const prog = [109, 500, 203, 50, 1206, 50, 10, 104, 1, 99, 104, -1, 99];
return AOC.assert(new Computer([0], prog).run().out, -1);
}
Insert cell
Insert cell
{
const input = -13;
const prog = [109, 500, 203, 50, 1207, 50, 0, 7, 4, 7, 99];
return AOC.assert(new Computer([input], prog).run().out, input < 0 ? 1 : 0);
}
Insert cell
Insert cell
{
const prog = [109, 500, 21107, 77, 88, 50, 204, 50, 99];
return AOC.assert(new Computer([], prog).run().out, 1);
}
Insert cell
Insert cell
{
const input = 12345;
const prog = [109, 500, 203, 50, 1208, 50, 0, 7, 4, 7, 99];
return AOC.assert(new Computer([input], prog).run().out, input === 0 ? 1 : 0);
}
Insert cell
Insert cell
{
const input = 500;
const prog = [
103, 50, 9, 50, 4, 50, 209, -450, 204, -950, 109, -1000, 204, 50, 99
];
const output = new Computer([input], prog).run().outputStore;
return AOC.assert(AOC.equalArrays(output, [input, input, input]), true);
}
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more