Created
December 5, 2019 14:44
-
-
Save dpeek/c7cfda72353f0998a5ee33e47585ab17 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const opcode = op => { | |
const str = String(op); | |
return parseInt(str.substr(str.length - 2)); | |
}; | |
const mode = (op, pos) => { | |
const str = String(op); | |
if (pos + 2 > str.length) return 0; | |
return parseInt(str.substr(str.length - (2 + pos), 1)); | |
}; | |
const param = (memory, pos, num) => { | |
const op = memory[pos]; | |
const value = memory[pos + num]; | |
return mode(op, num) === 0 ? memory[value] : value; | |
}; | |
const tick = (pos, memory, input, ram, debug = false) => { | |
const op = opcode(memory[pos]); | |
const p1 = param(memory, pos, 1); | |
const p2 = param(memory, pos, 2); | |
const p3 = param(memory, pos, 3); | |
let to; | |
switch (op) { | |
case 1: // add | |
to = memory[pos + 3]; | |
if (debug) console.log(`ADD: [${to}] = ${p1} + ${p2}`); | |
memory[to] = p1 + p2; | |
return pos + 4; | |
case 2: // multiply | |
to = memory[pos + 3]; | |
if (debug) console.log(`MUL: [${to}] = ${p1} * ${p2}`); | |
memory[to] = p1 * p2; | |
return pos + 4; | |
case 3: // input | |
to = memory[pos + 1]; | |
if (debug) console.log(`INP: [${to}] = ${input}`); | |
memory[to] = input; | |
return pos + 2; | |
case 4: // output | |
ram.output = p1; | |
return pos + 2; | |
case 5: // jump-if-true | |
to = p2; //memory[pos + 2]; | |
if (debug) console.log(`IFT: ${p1} !== 0 => ${p1 !== 0}`); | |
if (p1 !== 0) { | |
if (debug) console.log(`JMP: [${to}]`); | |
return to; | |
} | |
return pos + 3; | |
case 6: // jump-if-false | |
to = p2; //memory[pos + 2]; | |
if (debug) console.log(`IFT: ${p1} === 0 => ${p1 === 0}`); | |
if (p1 === 0) { | |
if (debug) console.log(`JMP: [${to}]`); | |
return to; | |
} | |
return pos + 3; | |
case 7: // less than | |
to = memory[pos + 3]; | |
if (debug) { | |
console.log(`ILT: ${p1} < ${p2} => ${p1 < p2}`); | |
console.log(`[${to}] = ${p1 < p2 ? 1 : 0}`); | |
} | |
memory[to] = p1 < p2 ? 1 : 0; | |
return pos + 4; | |
case 8: // equals | |
to = memory[pos + 3]; | |
if (debug) { | |
console.log(`IEQ ${p1} === ${p2} => ${p1 === p2}`); | |
console.log(`[${to}] = ${p1 === p2 ? 1 : 0}`); | |
} | |
memory[to] = p1 === p2 ? 1 : 0; | |
return pos + 4; | |
case 99: // halt | |
if (debug) console.log("HLT"); | |
return -1; | |
default: | |
console.log(`unknown opcode ${op}`); | |
return -1; | |
} | |
}; | |
const run = (program, input, debug = false) => { | |
const ram = {}; | |
const memory = program.split(",").map(str => parseInt(str, 10)); | |
let pos = 0; | |
while (pos > -1) pos = tick(pos, memory, input, ram, debug); | |
return ram.output; | |
}; | |
const tests = [ | |
{ | |
name: | |
"Using position mode, consider whether the input is equal to 8; output 1 (if it is) or 0 (if it is not).", | |
program: "3,9,8,9,10,9,4,9,99,-1,8", | |
cases: [ | |
{ input: 8, output: 1 }, | |
{ input: 9, output: 0 } | |
] | |
}, | |
{ | |
name: | |
"Using position mode, consider whether the input is less than 8; output 1 (if it is) or 0 (if it is not).", | |
program: "3,9,7,9,10,9,4,9,99,-1,8", | |
cases: [ | |
{ input: 7, output: 1 }, | |
{ input: 8, output: 0 } | |
] | |
}, | |
{ | |
name: | |
"Using immediate mode, consider whether the input is equal to 8; output 1 (if it is) or 0 (if it is not).", | |
program: "3,3,1108,-1,8,3,4,3,99", | |
cases: [ | |
{ input: 8, output: 1 }, | |
{ input: 9, output: 0 } | |
] | |
}, | |
{ | |
name: | |
"Using immediate mode, consider whether the input is less than 8; output 1 (if it is) or 0 (if it is not).", | |
program: "3,3,1107,-1,8,3,4,3,99", | |
cases: [ | |
{ input: 7, output: 1 }, | |
{ input: 8, output: 0 } | |
] | |
}, | |
{ | |
name: | |
"Using position mode, take an input, then output 0 if the input was zero or 1 if the input was non-zero.", | |
program: "3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9", | |
cases: [ | |
{ input: 0, output: 0 }, | |
{ input: 2, output: 1 } | |
] | |
}, | |
{ | |
name: | |
"Using immediate mode, take an input, then output 0 if the input was zero or 1 if the input was non-zero.", | |
program: "3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9", | |
cases: [ | |
{ input: 0, output: 0 }, | |
{ input: 2, output: 1 } | |
] | |
}, | |
{ | |
name: | |
"Outputs 999 if the input value is below 8, output 1000 if the input value is equal to 8, or output 1001 if the input value is greater than 8.", | |
program: | |
"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", | |
cases: [ | |
{ input: 4, output: 999 }, | |
{ input: 8, output: 1000 }, | |
{ input: 10, output: 1001 } | |
] | |
} | |
]; | |
tests.forEach(test => { | |
let pass = true; | |
test.cases.forEach(({ input, output }) => { | |
const actual = run(test.program, input); | |
if (actual !== output) { | |
pass = false; | |
console.log("Fail: " + test.name); | |
console.log(`Output was ${actual} should be ${output}`); | |
} | |
}); | |
console.log("Pass: " + test.name); | |
}); | |
const program = require("fs") | |
.readFileSync("./05.txt") | |
.toString(); | |
console.log(run(program, 1)); | |
console.log(run(program, 5)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment