jsadvent/solutions/2020/8.js
2020-12-10 02:33:00 -06:00

64 lines
1.6 KiB
JavaScript

const { Glib } = require('../../lib');
const parseInstruction = (i) => {
const [operation, argument] = i.split(' ');
return { operation, argument: BigInt(argument) };
};
const parse = (input) => Glib.fromLines(input).map(parseInstruction).array;
const operations = new Map([
['nop', (argument, state) => ({})],
['acc', (argument, { acc }) => ({ acc: acc + argument })],
['jmp', (argument, { pc }) => ({ pc: pc + argument })],
]);
const step = (state) => {
const { pc = 0n, program, acc = 0n } = state;
const { operation, argument } = program[pc];
if (!operations.has(operation)) {
throw new Error('no such operation');
}
const newState = operations.get(operation)(argument, state);
if (!newState.hasOwnProperty('pc')) {
newState.pc = pc + 1n;
}
if (!newState.hasOwnProperty('program')) {
newState.program = program.slice();
}
return { ...state, ...newState };
};
const run = (program) => {
let state = { pc: 0n, acc: 0n, program };
const seenInstructions = new Set();
while (!seenInstructions.has(state.pc) && state.pc < program.length) {
seenInstructions.add(state.pc);
state = step(state);
}
return state;
};
module.exports = {
'1': (input) => run(parse(input)).acc,
'2': (input) => {
const program = parse(input);
return program.glib
.map(({ operation, argument }, i) => {
const modified = program.slice();
modified[i] = {
operation: operation === 'nop' ? 'jmp' : 'nop',
argument,
};
return run(modified);
})
.filter(({ pc, program }) => pc === BigInt(program.length))
.map(({ acc }) => acc)
.first();
},
};