Skip to content

Instantly share code, notes, and snippets.

@cloudrac3r
Created December 5, 2019 05:58
Show Gist options
  • Save cloudrac3r/1b2995bd991628c8fa45ecabca7cec9f to your computer and use it in GitHub Desktop.
Save cloudrac3r/1b2995bd991628c8fa45ecabca7cec9f to your computer and use it in GitHub Desktop.
Advent of Code 2019 day 5 solution (both parts)
// @ts-check
const {read} = require("../util/read")
const outputQueue = []
const stdinQueue = []
function dataReceiver(data) {
const value = +data.toString()
if (stdinQueue.length) stdinQueue.shift()(value)
}
function listenForInput() {
process.stdin.on("data", dataReceiver)
}
function stopListeningForInput() {
process.stdin.removeListener("data", dataReceiver)
}
function waitForInput() {
return new Promise(resolve => {
process.stdout.write("input > ")
stdinQueue.push(resolve)
})
}
function output(value) {
console.log(value)
outputQueue.push(value)
}
const opMap = new Map([
[1, { // add
args: 3,
noTransformArgs: [2],
code: (tape, value1, value2, loc) => {
tape[loc] = value1 + value2
return null
}
}],
[2, { // multiply
args: 3,
noTransformArgs: [2],
code: (tape, value1, value2, loc) => {
tape[loc] = value1 * value2
return null
}
}],
[3, { // input
args: 1,
noTransformArgs: [0],
code: (tape, loc) => {
return waitForInput().then(input => {
tape[loc] = input
return null
})
}
}],
[4, { // output
args: 1,
noTransformArgs: [0],
code: (tape, loc) => {
output(tape[loc])
return null
}
}],
[5, { // jump if true
args: 2,
noTransformArgs: [],
code: (tape, condition, loc) => {
if (condition !== 0) return loc
else return null
}
}],
[6, { // jump if false
args: 2,
noTransformArgs: [],
code: (tape, condition, loc) => {
if (condition === 0) return loc
else return null
}
}],
[7, { // less than
args: 3,
noTransformArgs: [2],
code: (tape, value1, value2, loc) => {
if (value1 < value2) {
tape[loc] = 1
} else {
tape[loc] = 0
}
return null
}
}],
[8, { // equals
args: 3,
noTransformArgs: [2],
code: (tape, value1, value2, loc) => {
if (value1 === value2) {
tape[loc] = 1
} else {
tape[loc] = 0
}
return null
}
}],
[99, { // exit (handled elsewhere)
args: 0,
noTransformArgs: [],
code: () => {
process.stdin.removeListener("data", dataReceiver)
}
}]
])
/**
* @param {number} pos
* @param {number[]} tape
*/
async function runInstruction(pos, tape) {
// quit if broken
if (tape[pos] === undefined) throw new Error("Out of content!!!")
// organise
const inst = tape[pos++]
console.log("Inst:", inst)
// organise op
const opcode = inst % 100
const op = opMap.get(opcode)
console.log("Opcode:", opcode)
const padInst = inst.toString().padStart(2+op.args, "0").slice(0, -2).split("").reverse().join("")
// organise & resolve params
let params = []
for (let i = 0; i < op.args; i++) {
console.log("next arg:", i, padInst[i], tape[pos])
if (padInst[i] == "1" || op.noTransformArgs.includes(i)) { // direct
params.push(tape[pos++])
} else { // addressed
params.push(tape[tape[pos++]])
}
}
console.log("Params:", params)
const newPos = await op.code(tape, ...params)
if (newPos !== null) pos = newPos
return {pos, done: opcode === 99}
}
async function runTape(tape) {
listenForInput()
let done = false
let pos = 0
while (!done) {
({pos, done} = await runInstruction(pos, tape))
}
stopListeningForInput()
return tape
}
async function runFile(file) {
let tape = read(file).firstLine().split(",").map(x => +x)
console.log("Input tape:", tape)
await runTape(tape)
console.log("Tape:", tape)
console.log("Output:", outputQueue)
const final = outputQueue.length ? ""+outputQueue.slice(-1)[0] : ""
console.log("Final output:", final)
return final
}
module.exports.runFile = runFile
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment