Skip to content

Commit a0c26c2

Browse files
Merge pull request #42 from amclin/feature/2019-day-02
Feature/2019 day 02
2 parents dc1eb3a + 36ad2f6 commit a0c26c2

File tree

6 files changed

+195
-2
lines changed

6 files changed

+195
-2
lines changed

2019/day-02/input.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
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

2019/day-02/intcodeParser.js

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
const add = ({ posIn1, posIn2, posOut, data }) => {
2+
console.debug(`Adding ${data[Number(posIn1)]} to ${data[Number(posIn2)]}`)
3+
data[posOut] = data[Number(posIn1)] + data[Number(posIn2)]
4+
return true
5+
}
6+
7+
const multiply = ({ posIn1, posIn2, posOut, data }) => {
8+
console.debug(`Multiplying ${data[Number(posIn1)]} with ${data[Number(posIn2)]}`)
9+
data[posOut] = data[Number(posIn1)] * data[Number(posIn2)]
10+
return true
11+
}
12+
13+
const terminate = ({ instructionPointer }) => {
14+
console.log(`Reached terminator at instructionPointer ${instructionPointer}. Stopping.`)
15+
return false
16+
}
17+
18+
const step = ({ instructionPointer, data }) => {
19+
console.debug(`Step: ${instructionPointer}`)
20+
const opCodesMap = {
21+
1: add,
22+
2: multiply,
23+
99: terminate
24+
}
25+
const instruction = data.slice(instructionPointer, instructionPointer + 4)
26+
const opcode = instruction[0]
27+
28+
// Run the correct opcode for the specified step
29+
return opCodesMap[opcode]({
30+
posIn1: instruction[1],
31+
posIn2: instruction[2],
32+
posOut: instruction[3],
33+
data,
34+
instructionPointer
35+
})
36+
}
37+
38+
const runProgram = ({ data }) => {
39+
let instructionPointer = 0
40+
let running = true
41+
42+
// Convert to BigInts because operations will exceed 53bit integers
43+
// TODO: Standard chokes on this ES2020 feature. Remove eslint-disable
44+
// once fixed.
45+
// See https://github.com/standard/standard/issues/1436
46+
// eslint-disable-next-line no-undef
47+
data.forEach((key, idx) => { data[idx] = BigInt(key) })
48+
49+
while (running === true && instructionPointer <= data.length) {
50+
const instructionLength = 4
51+
running = step({ instructionPointer, data })
52+
instructionPointer += instructionLength
53+
}
54+
}
55+
56+
module.exports = {
57+
step,
58+
runProgram
59+
}

2019/day-02/intcodeParser.test.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/* eslint-env mocha */
2+
const expect = require('chai').expect
3+
const { step, runProgram } = require('./intcodeParser')
4+
5+
describe('--- 2019 Day 2: 1202 Program Alarm ---', () => {
6+
describe('Part 1', () => {
7+
describe('intcodeParser', () => {
8+
describe('step()', () => {
9+
it('can add', () => {
10+
const oppcode = 1
11+
const data = [oppcode, 5, 6, 3, 99, 2, 3]
12+
step({ instructionPointer: 0, data })
13+
expect(data[3]).equals(5)
14+
})
15+
it('can multiply', () => {
16+
const oppcode = 2
17+
const data = [oppcode, 5, 6, 3, 99, 2, 3]
18+
step({ instructionPointer: 0, data })
19+
expect(data[3]).equals(6)
20+
})
21+
it('can terminate', () => {
22+
const oppcode = 99
23+
const data = [oppcode, 5, 6, 3, 99, 2, 3]
24+
step({ instructionPointer: 0, data })
25+
expect(data[3]).equals(3)
26+
})
27+
})
28+
})
29+
describe('runProgram()', () => {
30+
it('runs through sequential steps of an intCode program', () => {
31+
const testInputs = [
32+
[1, 0, 0, 0, 99],
33+
[2, 3, 0, 3, 99],
34+
[2, 4, 4, 5, 99, 0],
35+
[1, 1, 1, 4, 99, 5, 6, 0, 99]
36+
]
37+
const testOutputs = [
38+
[2, 0, 0, 0, 99],
39+
[2, 3, 0, 6, 99],
40+
[2, 4, 4, 5, 99, 9801],
41+
[30, 1, 1, 4, 2, 5, 6, 0, 99]
42+
]
43+
// Convert outputs to BigInts
44+
testOutputs.forEach((out, idx) => {
45+
out.forEach((value, idx2) => {
46+
// TODO: Standard chokes on this ES2020 feature. Remove eslint-disable
47+
// once fixed.
48+
// See https://github.com/standard/standard/issues/1436
49+
// eslint-disable-next-line no-undef
50+
testOutputs[idx][idx2] = BigInt(value)
51+
})
52+
})
53+
54+
testInputs.forEach((data, idx) => {
55+
runProgram({ data })
56+
expect(data).to.deep.equal(testOutputs[idx])
57+
})
58+
})
59+
})
60+
})
61+
})

2019/day-02/solution.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
const fs = require('fs')
2+
const path = require('path')
3+
const filePath = path.join(__dirname, 'input.txt')
4+
const { runProgram } = require('./intcodeParser')
5+
const { inputToArray } = require('../../2018/inputParser')
6+
7+
fs.readFile(filePath, { encoding: 'utf8' }, (err, initData) => {
8+
if (err) throw err
9+
10+
initData = inputToArray(initData.trim())
11+
12+
const resetInput = () => {
13+
// Deep copy to ensure we aren't mutating the original data
14+
return JSON.parse(JSON.stringify(initData))
15+
}
16+
17+
const part1 = () => {
18+
const data = resetInput()
19+
// Manipulate input per puzzle instructions for Part 1
20+
data[1] = 12
21+
data[2] = 2
22+
runProgram({ data })
23+
return data[0]
24+
}
25+
26+
const part2 = ({ target, maxNoun, maxVerb }) => {
27+
// Helper for running the program with specified noun and verb inputs
28+
const tryProgram = ({
29+
noun,
30+
verb
31+
}) => {
32+
const data = resetInput()
33+
data[1] = noun
34+
data[2] = verb
35+
runProgram({ data })
36+
console.debug(`Running with noun:${noun} and verb:${verb} produces ${data[0]}`)
37+
return Number(data[0])
38+
}
39+
40+
// Manipulate and loop through attempts for Part 2
41+
let noun = -1
42+
while (noun <= maxNoun) {
43+
let verb = -1
44+
noun++
45+
while (verb <= maxVerb) {
46+
verb++
47+
const output = tryProgram({
48+
noun,
49+
verb
50+
})
51+
// Break the search loop on success
52+
if (output === target) {
53+
return 100 * noun + verb
54+
}
55+
}
56+
}
57+
}
58+
59+
const answer1 = part1()
60+
const answer2 = part2({ target: 19690720, maxNoun: 99, maxVerb: 99 })
61+
62+
console.log('-- Part 1 --')
63+
console.log(`Answer: ${answer1}`)
64+
65+
console.log('-- Part 2 --')
66+
console.log(`Answer: ${answer2}`)
67+
})

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33
[![codecov](https://codecov.io/gh/amclin/advent-of-code/branch/master/graph/badge.svg)](https://codecov.io/gh/amclin/advent-of-code)
44

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

7-
#### Day 14
8+
#### 2019:Day 02
9+
Day 2 requires the use of BigInt which is added to Javascript in ES2020 and I didn't include a polyfill.
10+
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)
11+
12+
#### 2018:Day 14
813
Day 14 is fast but needs more memory to complete. Run node with 4GB of heap space:
914
`node --max_old_space_size=4096 index.js`

index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
require('./2019/day-01/part-1/solution')
1+
require('./2019/day-02/solution')

0 commit comments

Comments
 (0)