diff --git a/2020/day-08/index.js b/2020/day-08/index.js new file mode 100644 index 0000000..af7e035 --- /dev/null +++ b/2020/day-08/index.js @@ -0,0 +1,3 @@ +// eslint-disable-next-line no-unused-vars +const console = require('../helpers') +require('./solution') diff --git a/2020/day-08/input.txt b/2020/day-08/input.txt new file mode 100644 index 0000000..98cec52 --- /dev/null +++ b/2020/day-08/input.txt @@ -0,0 +1,649 @@ +acc +7 +acc +23 +acc +41 +jmp +173 +acc -17 +acc +42 +acc +31 +jmp +349 +jmp +1 +jmp +252 +nop +574 +jmp +298 +acc +45 +acc +7 +jmp +338 +nop +5 +nop +528 +jmp +547 +jmp +313 +jmp +387 +acc +43 +acc +48 +acc +38 +jmp +45 +jmp +438 +acc +15 +acc +21 +acc +25 +acc +25 +jmp +168 +jmp -5 +acc +49 +acc +43 +jmp +99 +acc -8 +acc +16 +acc -7 +jmp +513 +jmp +484 +jmp +270 +nop +422 +acc -4 +nop +242 +jmp +1 +jmp +11 +nop +122 +nop +263 +acc +2 +jmp +474 +jmp +501 +nop +38 +acc -7 +acc +0 +nop +85 +jmp +496 +acc +11 +acc -13 +acc +40 +acc +29 +jmp +519 +jmp +409 +acc +41 +jmp +1 +acc -17 +jmp +16 +nop +485 +acc -7 +jmp +58 +acc +16 +acc +1 +jmp +123 +jmp +157 +acc +43 +jmp +422 +jmp +1 +acc -19 +acc +48 +jmp +80 +jmp +500 +jmp -59 +acc +34 +acc +11 +jmp +75 +nop +467 +acc -16 +acc +9 +acc +32 +jmp -69 +acc -13 +jmp +422 +jmp +96 +acc -10 +acc -19 +jmp -68 +acc +31 +nop +102 +acc +25 +jmp +140 +acc +34 +acc +45 +acc -9 +acc -17 +jmp -34 +nop +262 +jmp +236 +acc +0 +acc +32 +jmp +269 +acc +16 +jmp +1 +jmp +382 +jmp -39 +acc +45 +nop +166 +nop +408 +acc +10 +jmp +379 +jmp +1 +acc +44 +jmp +249 +nop +334 +acc +36 +nop +442 +acc +5 +jmp +440 +acc +0 +acc +44 +jmp +432 +acc +48 +acc +4 +acc +50 +jmp +355 +acc +31 +jmp +1 +acc +46 +nop -74 +jmp +33 +jmp +91 +nop +463 +acc +41 +nop -2 +jmp +132 +acc +41 +acc +43 +acc +28 +jmp -65 +acc -17 +acc +33 +jmp +183 +acc +11 +jmp +181 +jmp +450 +acc -18 +acc -2 +acc +44 +nop +416 +jmp +108 +acc -18 +acc +12 +acc -1 +acc -19 +jmp +321 +acc +50 +acc -17 +jmp +1 +nop +161 +jmp -41 +jmp +52 +jmp +84 +acc +11 +acc +19 +acc +40 +jmp +293 +acc +29 +jmp +1 +jmp +311 +nop +91 +acc +1 +acc +0 +acc +16 +jmp -42 +acc +0 +acc -16 +acc +41 +nop +348 +jmp -39 +nop -114 +nop +320 +acc +46 +acc -1 +jmp +55 +nop +278 +jmp -94 +acc +47 +jmp +365 +acc +44 +jmp -58 +jmp +1 +jmp +114 +acc -13 +acc -5 +acc +12 +jmp +183 +nop +237 +acc +26 +acc +49 +acc +1 +jmp -189 +acc +7 +acc +2 +jmp -190 +acc -17 +acc +18 +acc -1 +jmp -47 +nop -39 +acc -18 +nop +354 +jmp +264 +acc +46 +jmp +179 +acc +22 +acc +24 +jmp +309 +acc +45 +acc -9 +jmp -206 +jmp +34 +nop +254 +acc +9 +acc +32 +jmp +391 +acc +9 +acc +20 +acc +7 +acc +48 +jmp -85 +acc +27 +acc -3 +jmp +146 +acc -12 +acc +37 +acc +23 +jmp +1 +jmp +48 +acc +46 +jmp +99 +acc -12 +acc -2 +acc +49 +jmp +1 +jmp +293 +jmp +1 +acc +38 +jmp +13 +jmp -215 +jmp -145 +acc +7 +nop +73 +nop +189 +jmp +167 +jmp +332 +acc +29 +jmp -146 +jmp +198 +acc +10 +jmp +342 +acc +31 +jmp -136 +acc +16 +acc +33 +acc +26 +jmp -48 +acc +14 +jmp +91 +acc -15 +nop +274 +acc -2 +jmp -75 +acc +14 +acc +21 +acc +4 +jmp +332 +jmp -243 +acc +25 +acc -5 +jmp +250 +acc -17 +acc +32 +acc +28 +acc +34 +jmp -80 +acc +23 +acc +30 +acc +10 +nop -98 +jmp -205 +acc -16 +acc -15 +acc +49 +acc +15 +jmp +11 +nop +97 +acc -2 +acc +31 +jmp +1 +jmp -130 +acc +25 +jmp +129 +nop -231 +jmp +274 +jmp -280 +acc +0 +acc -14 +acc +8 +nop -224 +jmp +328 +acc +6 +acc +29 +acc +9 +jmp -229 +acc +8 +jmp -284 +acc +4 +acc +0 +jmp -200 +acc +18 +acc +33 +jmp -76 +acc -2 +jmp +139 +nop -70 +acc -6 +acc +9 +jmp -25 +nop +21 +acc +37 +acc +15 +acc +45 +jmp +130 +acc +45 +acc -5 +jmp -86 +acc -15 +jmp +55 +nop -305 +acc +24 +jmp -275 +jmp +1 +acc +31 +acc -19 +jmp -148 +acc +27 +jmp +279 +acc +11 +jmp +253 +acc +17 +nop -1 +acc -15 +jmp -57 +acc +12 +acc +10 +acc -7 +acc +18 +jmp -100 +acc +39 +jmp -180 +jmp +155 +acc -14 +acc -10 +acc -14 +nop -202 +jmp -267 +acc +11 +acc +0 +jmp -130 +acc +19 +acc -18 +jmp +166 +jmp +61 +jmp +13 +acc -2 +jmp +1 +acc +19 +jmp -160 +acc +23 +jmp +1 +acc +37 +acc +40 +jmp +86 +acc +17 +acc -18 +jmp -195 +acc +11 +nop -149 +acc -13 +jmp +41 +acc -16 +jmp -30 +acc +34 +acc +13 +acc +38 +jmp +46 +acc -13 +acc +34 +jmp -273 +acc -9 +acc -8 +acc +23 +acc +8 +jmp +82 +acc +3 +acc +43 +nop +137 +jmp -46 +acc -15 +acc +41 +acc +25 +acc +3 +jmp -208 +acc +0 +jmp -169 +acc +20 +acc +12 +jmp -221 +acc -14 +jmp +96 +acc +47 +acc +25 +acc +7 +jmp +141 +acc -19 +jmp -294 +acc +28 +jmp -94 +acc +35 +jmp +33 +jmp -349 +acc -17 +jmp +193 +jmp +1 +acc -16 +jmp -169 +jmp +1 +nop -258 +acc +44 +nop -13 +jmp -330 +jmp +189 +acc +20 +acc +31 +nop +35 +acc +42 +jmp +64 +acc +9 +nop -406 +acc -14 +jmp +1 +jmp +74 +acc +34 +acc +0 +jmp -285 +jmp -422 +nop -338 +jmp +47 +nop -445 +jmp -145 +jmp +1 +jmp -116 +acc +41 +acc +44 +acc +34 +jmp -146 +acc +44 +jmp -434 +acc +44 +acc +34 +jmp -185 +acc -17 +nop -187 +nop -5 +jmp -96 +nop -20 +jmp -199 +acc +33 +jmp -229 +nop +50 +jmp -263 +acc -5 +acc -4 +acc +16 +jmp -340 +jmp -77 +nop -71 +jmp -168 +acc -18 +nop -447 +nop -479 +jmp -118 +acc +49 +nop -35 +jmp -264 +acc +21 +jmp -76 +acc +25 +acc +46 +jmp -339 +jmp -382 +nop -54 +nop -169 +jmp -208 +acc -8 +jmp -395 +acc -8 +acc +45 +nop -312 +jmp +92 +jmp -31 +acc +45 +acc +42 +nop -259 +jmp -169 +nop -255 +nop -69 +acc +47 +acc +35 +jmp -428 +acc +15 +acc +47 +acc +50 +acc +13 +jmp -491 +jmp -386 +acc +32 +acc +36 +jmp -73 +acc +22 +acc +0 +acc +35 +jmp -531 +acc +21 +nop -365 +acc +16 +jmp +89 +acc +50 +jmp -467 +acc +42 +nop -167 +acc +39 +jmp -481 +acc -13 +acc +49 +acc +8 +acc -11 +jmp -47 +acc +22 +acc +23 +nop +14 +jmp +56 +jmp -57 +acc +0 +acc +45 +acc -12 +jmp -339 +acc +41 +jmp -286 +acc +24 +acc -14 +acc +7 +nop -481 +jmp -539 +acc +14 +jmp -511 +acc +1 +acc -14 +jmp +1 +acc -12 +jmp -123 +acc -17 +acc +11 +jmp -16 +nop -148 +acc -14 +jmp -485 +nop -258 +nop -123 +acc +22 +jmp -359 +nop -527 +nop -443 +acc +43 +jmp +1 +jmp -406 +acc +39 +acc +13 +acc +3 +acc -5 +jmp -585 +acc +41 +acc +26 +jmp -83 +acc +30 +acc +8 +acc +36 +jmp -150 +acc +36 +acc +43 +jmp -305 +acc +10 +acc +33 +jmp -188 +nop -285 +acc -4 +jmp -385 +acc -1 +jmp +1 +nop -23 +jmp -471 +acc +24 +acc +16 +acc +29 +jmp -114 +nop -471 +acc +4 +nop -360 +nop -294 +jmp -220 +acc -18 +acc +21 +acc +10 +acc +0 +jmp -166 +jmp -192 +acc +37 +acc +24 +nop -198 +jmp -425 +acc -19 +acc +43 +jmp -608 +acc +17 +acc +32 +acc +0 +jmp -424 +acc +50 +acc +46 +nop -555 +acc -16 +jmp +1 \ No newline at end of file diff --git a/2020/day-08/runProgram.js b/2020/day-08/runProgram.js new file mode 100644 index 0000000..32437f7 --- /dev/null +++ b/2020/day-08/runProgram.js @@ -0,0 +1,150 @@ +let log = [] +log[0] = [1] +log[1] = [2, 8] +log[2] = [3] +log[3] = [6] +log[4] = [7] +log[6] = [4] +log[7] = [5] + +let program = [ + 'nop +0', + 'acc +1', + 'jmp +4', + 'acc +3', + 'jmp -3', + 'acc -99', + 'acc +1', + 'jmp -4', + 'acc +6' +] + +let accumulator = 0 +let position = 1 +let breaker = false + +/** + * API of commands this language supports + */ +const api = { + nop: (a, b) => { + console.debug(`doing a nop ${b}`) + return a + 1 + }, + acc: (a, b) => { + console.debug(`adding ${b} to accumulator`) + accumulator += api[b.substr(0, 1)]( + 0, + Number(b.substr((1))) + ) + return a + 1 + }, + jmp: (a, b) => { + console.debug(`jumping from ${a} ${b} `) + return a + api[b.substr(0, 1)]( + 0, + Number(b.substr((1))) + ) + }, + '+': (x, y) => x + y, + '-': (x, y) => x - y +} + +const parseCommand = (inst) => { + console.debug('Parsing ', inst) + const [cmd, arg] = inst.split(' ') + return { cmd, arg } +} + +const execInstruction = (inst, instKey = 0, evKey = 0) => { + const { cmd, arg } = parseCommand(inst) + // Run the command + // Support jumping by passing back next + position = api[cmd](instKey, arg) + logEvent({ instKey, evKey }) + // break out when reaching an infinite loop + if (log[instKey].length > 1) { + breaker = true + console.error(`execuetd an error on ${instKey}`, inst, accumulator) + // step back the accumulator + if (cmd === 'acc') { + if (arg.includes('+')) { + api[cmd](0, arg.replace('+', '-')) + } + if (arg.includes('-')) { + api[cmd](0, arg.replace('+-', '+')) + } + } + } + return position +} + +const run = (insts) => { + program = insts + accumulator = 0 + position = 0 + log = [] + let evKey = 0 + + // eslint-disable-next-line no-unmodified-loop-condition + while (breaker === false) { + evKey++ + execInstruction(program[position], position, evKey) + } +} + +const formatLogRow = (command, idx, program) => { + let countStr + if (!log[idx]) { + countStr = '' + } + if (log[idx] && log[idx].length === 1) { + countStr = `${log[idx][0]}` + } + if (log[idx] && log[idx].length > 1) { + countStr = `${log[idx].join(', ')}(!)` + } + const row = `${command.padEnd(8, ' ')}| ${countStr}` + console.debug(row) + return row +} + +const displayLog = () => { + console.debug(`${program.length} steps in program.`) + console.debug('-----------------------------------') + const formattedLog = program.map(formatLogRow) + .reduce((res, row) => { + res += '\n' + res += row + return res + }, '') + + return formattedLog +} + +const logEvent = ({ instKey, evKey }) => { + console.debug(`event ${evKey} called instruction ${instKey}`) + if ( + log[instKey] && + typeof log[instKey] === 'object' && + log[instKey].length > 0 + ) { + // Record another entry on a command already executed once + log[instKey].push(evKey) + return log[instKey] + } else { + // Record the first entry on a command + log[instKey] = [evKey] + } + return log[instKey] +} + +module.exports = { + run, + getAccumulator: () => accumulator, + getPosition: () => position, + execInstruction, + parseCommand, + logEvent, + displayLog +} diff --git a/2020/day-08/runProgram.test.js b/2020/day-08/runProgram.test.js new file mode 100644 index 0000000..79ed830 --- /dev/null +++ b/2020/day-08/runProgram.test.js @@ -0,0 +1,102 @@ +/* eslint-env mocha */ +const { expect } = require('chai') +const { run, getPosition, getAccumulator, execInstruction, parseCommand, logEvent, displayLog } = require('./runProgram') + +const exampleProgram = [ + 'nop +0', + 'acc +1', + 'jmp +4', + 'acc +3', + 'jmp -3', + 'acc -99', + 'acc +1', + 'jmp -4', + 'acc +6' +] +const exampleLog = ` +nop +0 | 1 +acc +1 | 2, 8(!) +jmp +4 | 3 +acc +3 | 6 +jmp -3 | 7 +acc -99 | +acc +1 | 4 +jmp -4 | 5 +acc +6 | ` + +describe('--- Day 8: Handheld Halting ---', () => { + describe('Part 1', () => { + describe('execInstruction()', () => { + it('executes a specified command', () => { + expect(getPosition()).to.equal(1) + expect(execInstruction('acc +3', 300, 600)).to.equal(301) + expect(getAccumulator()).to.equal(3) + expect(getPosition()).to.equal(301) + }) + xit('steps to the next sequential command', () => { + // logEvent() + // expect(false).to.equal(true) + }) + it('can execute a `nop` command which does nothing', () => { + const acc = getAccumulator() + expect(execInstruction('nop +3', 999, 600)).to.equal(1000) + expect(getPosition()).to.equal(1000) + expect(getAccumulator()).to.equal(acc) + }) + it('can execute a `acc` command which increments the accumulator', () => { + const acc = getAccumulator() + expect(execInstruction('acc +100', 1234, 600)).to.equal(1235) + expect(getPosition()).to.equal(1235) + expect(getAccumulator()).to.equal(acc + 100) + }) + it('can execute a `jmp` command which jumps to a different command in the instruction set', () => { + const acc = getAccumulator() + expect(execInstruction('jmp -23', 400, 600)).to.equal(377) + expect(getPosition()).to.equal(377) + expect(getAccumulator()).to.equal(acc) + }) + }) + describe('parseCommand()', () => { + it('parses an instruction string into a structured command object', () => { + const instructions = [ + 'jmp +4', + 'acc +3', + 'jmp -3', + 'acc -99' + ] + instructions.forEach((inst) => { + const { cmd, arg } = parseCommand(inst) + expect(`${cmd} ${arg}`).to.equal(inst) + }) + }) + }) + describe('logEvent()', () => { + it('records the step in the execution log', () => { + const result = logEvent({ instKey: 500, evKey: 17 }) + expect(result).to.deep.equal([17]) + }) + it('tracks the state over multiple logging events', () => { + const result = logEvent({ instKey: 500, evKey: 24 }) + expect(result).to.deep.equal([17, 24]) + }) + }) + describe('displayLog()', () => { + it('renders the output of the execution log', () => { + expect( + displayLog() + ).to.equal( + exampleLog + ) + }) + }) + describe('run()', () => { + it('executes the steps of a given program', () => { + run(exampleProgram) + // stops at infinite loop + expect(getPosition()).to.equal(2) + expect(getAccumulator()).to.equal(6) + expect(displayLog()).to.equal(exampleLog) + }) + }) + }) +}) diff --git a/2020/day-08/solution.js b/2020/day-08/solution.js new file mode 100644 index 0000000..e222dc5 --- /dev/null +++ b/2020/day-08/solution.js @@ -0,0 +1,38 @@ +const fs = require('fs') +const path = require('path') +const filePath = path.join(__dirname, 'input.txt') +const { linesToArray } = require('../../2018/inputParser') +const { run, getAccumulator, displayLog } = require('./runProgram') + +fs.readFile(filePath, { encoding: 'utf8' }, (err, initData) => { + if (err) throw err + + initData = linesToArray(initData.trim()) + + const resetInput = () => { + // Deep copy to ensure we aren't mutating the original data + return JSON.parse(JSON.stringify(initData)) + } + + const part1 = () => { + const data = resetInput() + console.debug(data) + run(data) + console.info(displayLog()) + return getAccumulator() + } + + const part2 = () => { + const data = resetInput() + console.debug(data) + return 'No answer yet' + } + const answers = [] + answers.push(part1()) + answers.push(part2()) + + answers.forEach((ans, idx) => { + console.info(`-- Part ${idx + 1} --`) + console.info(`Answer: ${ans}`) + }) +}) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy