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(); }, };