UNPKG

@alexaegis/advent-of-code-intcode

Version:

Advent of Code Intcode Computer

273 lines (272 loc) 6.59 kB
"use strict"; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const adventOfCodeLib = require("@alexaegis/advent-of-code-lib"); var Instruction = /* @__PURE__ */ ((Instruction2) => { Instruction2[Instruction2["ADD"] = 1] = "ADD"; Instruction2[Instruction2["MUL"] = 2] = "MUL"; Instruction2[Instruction2["IN"] = 3] = "IN"; Instruction2[Instruction2["OUT"] = 4] = "OUT"; Instruction2[Instruction2["JIT"] = 5] = "JIT"; Instruction2[Instruction2["JIF"] = 6] = "JIF"; Instruction2[Instruction2["LT"] = 7] = "LT"; Instruction2[Instruction2["EQ"] = 8] = "EQ"; Instruction2[Instruction2["REL"] = 9] = "REL"; Instruction2[Instruction2["HALT"] = 99] = "HALT"; return Instruction2; })(Instruction || {}); const isInstruction = (n) => n >= 1 && n <= 9 || n === 99; const toInstruction = (code) => { const inst = code % 100; if (isInstruction(inst)) { return inst; } else { throw new Error(`Unsupported instruction ${inst}`); } }; var Mode = /* @__PURE__ */ ((Mode2) => { Mode2[Mode2["POS"] = 0] = "POS"; Mode2[Mode2["VAL"] = 1] = "VAL"; Mode2[Mode2["REL"] = 2] = "REL"; return Mode2; })(Mode || {}); class IntCodeComputer { tape; cursor = 0; relBase = 0; halt = false; inputQueue; inputCallback; outputCallback; constructor(tape) { this.tape = tape.reduce((m, n, i) => m.set(i, n), /* @__PURE__ */ new Map()); } *iter() { for (const res of this) { if (res !== void 0) { yield res; } } } *stepper() { yield* this; } set input(input) { if (typeof input === "number") { this.inputQueue = [input]; } else if (typeof input === "function") { this.inputCallback = input; } else { this.inputQueue = input; } } withInput(input) { this.input = input; return this; } withInputCallback(inputCallback) { this.inputCallback = inputCallback; return this; } withOutputCallback(outputCallback) { this.outputCallback = outputCallback; return this; } isHalt() { return this.halt; } pushInput(...input) { if (!this.inputQueue) { this.inputQueue = []; } this.inputQueue.push(...input); return this; } pushAsciiInput(input, nl = true) { if (nl) { input += "\n"; } return this.pushInput(...[...input].map((s) => s.codePointAt(0) ?? 0)); } pushInputIfEmpty(input) { if (!this.inputQueue || this.inputQueue.length === 0) { this.pushInput(input); return true; } else return false; } getValue(pos, mode = Mode.POS, asIndex = false) { let v; switch (mode) { case Mode.POS: { v = this.tape.get(pos) ?? 0; break; } case Mode.REL: { v = this.relBase + (this.tape.get(pos) ?? 0); break; } default: { v = pos; break; } } return asIndex ? v : this.tape.get(v) ?? 0; } reset(tape) { if (tape) { this.tape = tape.reduce((m, n, i) => m.set(i, n), /* @__PURE__ */ new Map()); } this.cursor = 0; this.relBase = 0; this.halt = false; return this; } peek(at) { return this.tape.get(at); } set noun(noun) { this.tape.set(1, noun); } withNoun(noun) { this.noun = noun; return this; } set verb(verb) { this.tape.set(2, verb); } withVerb(verb) { this.verb = verb; return this; } getArg(v, n, asIndex = false, mode) { return this.getValue(this.cursor + n + 1, mode ?? this.getMode(v, n), asIndex); } getMode(v, n) { return adventOfCodeLib.numAt(v, adventOfCodeLib.integerLength(v) - n - 3); } *[Symbol.iterator]() { do { const v = this.tape.get(this.cursor) ?? 0; const i = toInstruction(v); switch (i) { case Instruction.ADD: { this.addOp(this.getArg(v, 0), this.getArg(v, 1), this.getArg(v, 2, true)); break; } case Instruction.MUL: { this.mulOp(this.getArg(v, 0), this.getArg(v, 1), this.getArg(v, 2, true)); break; } case Instruction.IN: { this.inOp(this.getArg(v, 0, true)); yield void 0; break; } case Instruction.OUT: { yield this.outOp(this.getArg(v, 0)); break; } case Instruction.JIT: { this.jitOp(this.getArg(v, 0), this.getArg(v, 1)); break; } case Instruction.JIF: { this.jifOp(this.getArg(v, 0), this.getArg(v, 1)); break; } case Instruction.LT: { this.ltOp(this.getArg(v, 0), this.getArg(v, 1), this.getArg(v, 2, true)); break; } case Instruction.EQ: { this.eqOp(this.getArg(v, 0), this.getArg(v, 1), this.getArg(v, 2, true)); break; } case Instruction.REL: { this.relOp(this.getArg(v, 0)); break; } default: { this.haltOp(); break; } } } while (!this.halt); } run(target) { if (target) { target.push(...this.execute()); } else { this.execute(); } return this; } execute() { return [...this.iter()]; } addOp(a, b, pos) { this.tape.set(pos, a + b); this.cursor += 4; } mulOp(a, b, pos) { this.tape.set(pos, a * b); this.cursor += 4; } inOp(pos) { if (this.inputQueue && this.inputQueue.length > 0) { const next = this.inputQueue.shift(); if (next !== void 0) { this.tape.set(pos, next); } } else if (this.inputCallback) { this.tape.set(pos, this.inputCallback()); } else { throw new Error("No input"); } this.cursor += 2; } outOp(pos) { if (pos === void 0) { throw new Error("Not valid output" + pos); } if (this.outputCallback) { this.outputCallback(pos); } this.cursor += 2; return pos; } jitOp(v, target) { if (v) { this.cursor = target; } else { this.cursor += 3; } } jifOp(v, target) { if (v) { this.cursor += 3; } else { this.cursor = target; } } ltOp(a, b, pos) { this.tape.set(pos, a < b ? 1 : 0); this.cursor += 4; } eqOp(a, b, pos) { this.tape.set(pos, a === b ? 1 : 0); this.cursor += 4; } relOp(pos) { this.relBase += pos; this.cursor += 2; } haltOp() { this.halt = true; } } exports.Instruction = Instruction; exports.IntCodeComputer = IntCodeComputer; exports.Mode = Mode; exports.isInstruction = isInstruction; exports.toInstruction = toInstruction;