Skip to content

Commit

Permalink
Merge pull request #42 from amclin/feature/2019-day-02
Browse files Browse the repository at this point in the history
Feature/2019 day 02
  • Loading branch information
amclin authored Dec 7, 2019
2 parents dc1eb3a + 36ad2f6 commit a0c26c2
Show file tree
Hide file tree
Showing 6 changed files with 195 additions and 2 deletions.
1 change: 1 addition & 0 deletions 2019/day-02/input.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1,0,0,3,1,1,2,3,1,3,4,3,1,5,0,3,2,1,10,19,2,6,19,23,1,23,5,27,1,27,13,31,2,6,31,35,1,5,35,39,1,39,10,43,2,6,43,47,1,47,5,51,1,51,9,55,2,55,6,59,1,59,10,63,2,63,9,67,1,67,5,71,1,71,5,75,2,75,6,79,1,5,79,83,1,10,83,87,2,13,87,91,1,10,91,95,2,13,95,99,1,99,9,103,1,5,103,107,1,107,10,111,1,111,5,115,1,115,6,119,1,119,10,123,1,123,10,127,2,127,13,131,1,13,131,135,1,135,10,139,2,139,6,143,1,143,9,147,2,147,6,151,1,5,151,155,1,9,155,159,2,159,6,163,1,163,2,167,1,10,167,0,99,2,14,0,0
59 changes: 59 additions & 0 deletions 2019/day-02/intcodeParser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
const add = ({ posIn1, posIn2, posOut, data }) => {
console.debug(`Adding ${data[Number(posIn1)]} to ${data[Number(posIn2)]}`)
data[posOut] = data[Number(posIn1)] + data[Number(posIn2)]
return true
}

const multiply = ({ posIn1, posIn2, posOut, data }) => {
console.debug(`Multiplying ${data[Number(posIn1)]} with ${data[Number(posIn2)]}`)
data[posOut] = data[Number(posIn1)] * data[Number(posIn2)]
return true
}

const terminate = ({ instructionPointer }) => {
console.log(`Reached terminator at instructionPointer ${instructionPointer}. Stopping.`)
return false
}

const step = ({ instructionPointer, data }) => {
console.debug(`Step: ${instructionPointer}`)
const opCodesMap = {
1: add,
2: multiply,
99: terminate
}
const instruction = data.slice(instructionPointer, instructionPointer + 4)
const opcode = instruction[0]

// Run the correct opcode for the specified step
return opCodesMap[opcode]({
posIn1: instruction[1],
posIn2: instruction[2],
posOut: instruction[3],
data,
instructionPointer
})
}

const runProgram = ({ data }) => {
let instructionPointer = 0
let running = true

// Convert to BigInts because operations will exceed 53bit integers
// TODO: Standard chokes on this ES2020 feature. Remove eslint-disable
// once fixed.
// See https://github.com/standard/standard/issues/1436
// eslint-disable-next-line no-undef
data.forEach((key, idx) => { data[idx] = BigInt(key) })

while (running === true && instructionPointer <= data.length) {
const instructionLength = 4
running = step({ instructionPointer, data })
instructionPointer += instructionLength
}
}

module.exports = {
step,
runProgram
}
61 changes: 61 additions & 0 deletions 2019/day-02/intcodeParser.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/* eslint-env mocha */
const expect = require('chai').expect
const { step, runProgram } = require('./intcodeParser')

describe('--- 2019 Day 2: 1202 Program Alarm ---', () => {
describe('Part 1', () => {
describe('intcodeParser', () => {
describe('step()', () => {
it('can add', () => {
const oppcode = 1
const data = [oppcode, 5, 6, 3, 99, 2, 3]
step({ instructionPointer: 0, data })
expect(data[3]).equals(5)
})
it('can multiply', () => {
const oppcode = 2
const data = [oppcode, 5, 6, 3, 99, 2, 3]
step({ instructionPointer: 0, data })
expect(data[3]).equals(6)
})
it('can terminate', () => {
const oppcode = 99
const data = [oppcode, 5, 6, 3, 99, 2, 3]
step({ instructionPointer: 0, data })
expect(data[3]).equals(3)
})
})
})
describe('runProgram()', () => {
it('runs through sequential steps of an intCode program', () => {
const testInputs = [
[1, 0, 0, 0, 99],
[2, 3, 0, 3, 99],
[2, 4, 4, 5, 99, 0],
[1, 1, 1, 4, 99, 5, 6, 0, 99]
]
const testOutputs = [
[2, 0, 0, 0, 99],
[2, 3, 0, 6, 99],
[2, 4, 4, 5, 99, 9801],
[30, 1, 1, 4, 2, 5, 6, 0, 99]
]
// Convert outputs to BigInts
testOutputs.forEach((out, idx) => {
out.forEach((value, idx2) => {
// TODO: Standard chokes on this ES2020 feature. Remove eslint-disable
// once fixed.
// See https://github.com/standard/standard/issues/1436
// eslint-disable-next-line no-undef
testOutputs[idx][idx2] = BigInt(value)
})
})

testInputs.forEach((data, idx) => {
runProgram({ data })
expect(data).to.deep.equal(testOutputs[idx])
})
})
})
})
})
67 changes: 67 additions & 0 deletions 2019/day-02/solution.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
const fs = require('fs')
const path = require('path')
const filePath = path.join(__dirname, 'input.txt')
const { runProgram } = require('./intcodeParser')
const { inputToArray } = require('../../2018/inputParser')

fs.readFile(filePath, { encoding: 'utf8' }, (err, initData) => {
if (err) throw err

initData = inputToArray(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()
// Manipulate input per puzzle instructions for Part 1
data[1] = 12
data[2] = 2
runProgram({ data })
return data[0]
}

const part2 = ({ target, maxNoun, maxVerb }) => {
// Helper for running the program with specified noun and verb inputs
const tryProgram = ({
noun,
verb
}) => {
const data = resetInput()
data[1] = noun
data[2] = verb
runProgram({ data })
console.debug(`Running with noun:${noun} and verb:${verb} produces ${data[0]}`)
return Number(data[0])
}

// Manipulate and loop through attempts for Part 2
let noun = -1
while (noun <= maxNoun) {
let verb = -1
noun++
while (verb <= maxVerb) {
verb++
const output = tryProgram({
noun,
verb
})
// Break the search loop on success
if (output === target) {
return 100 * noun + verb
}
}
}
}

const answer1 = part1()
const answer2 = part2({ target: 19690720, maxNoun: 99, maxVerb: 99 })

console.log('-- Part 1 --')
console.log(`Answer: ${answer1}`)

console.log('-- Part 2 --')
console.log(`Answer: ${answer2}`)
})
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@
[![codecov](https://codecov.io/gh/amclin/advent-of-code/branch/master/graph/badge.svg)](https://codecov.io/gh/amclin/advent-of-code)

### Special Instructions
Run by modifying `index.js` to point to the puzzle you want to execute.

#### Day 14
#### 2019:Day 02
Day 2 requires the use of BigInt which is added to Javascript in ES2020 and I didn't include a polyfill.
This limits the solution to [Javascript engines with BigInt support](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#Browser_compatibility)

#### 2018:Day 14
Day 14 is fast but needs more memory to complete. Run node with 4GB of heap space:
`node --max_old_space_size=4096 index.js`
2 changes: 1 addition & 1 deletion index.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
require('./2019/day-01/part-1/solution')
require('./2019/day-02/solution')

0 comments on commit a0c26c2

Please sign in to comment.