Skip to content

Commit

Permalink
Merge pull request #132 from amclin/feat/2020-day-10
Browse files Browse the repository at this point in the history
Feat/2020 day 10
  • Loading branch information
amclin authored Dec 20, 2020
2 parents b3cf433 + e21b7c1 commit 18b7582
Show file tree
Hide file tree
Showing 5 changed files with 282 additions and 0 deletions.
3 changes: 3 additions & 0 deletions 2020/day-10/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// eslint-disable-next-line no-unused-vars
const console = require('../helpers')
require('./solution')
93 changes: 93 additions & 0 deletions 2020/day-10/input.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
47
99
115
65
10
55
19
73
80
100
71
110
64
135
49
3
1
98
132
2
38
118
66
116
104
87
79
114
40
37
44
97
4
140
60
86
56
133
7
146
85
111
134
53
121
77
117
21
12
81
145
129
107
93
22
48
11
54
92
78
67
20
138
125
57
96
26
147
124
34
74
143
13
28
126
50
29
70
39
63
41
91
32
84
144
27
139
33
88
72
23
103
16
107 changes: 107 additions & 0 deletions 2020/day-10/jolts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
const countDifferences = (data) => {
const tallies = Array(4).fill(0)
// Always account for the outlet
data.push(0)
// Always add the native adapter at the end
tallies[3]++

// Iterate through the adapters
data.sort((a, b) => a - b)
.forEach((curr, idx) => {
if (!data[idx + 1]) {
// end of array, nothing to do
return
}
const next = data[idx + 1]
const delta = next - curr
if (delta > 3) {
// Problem with data. Gap in joltages greater than allowed
throw new Error(`Joltage difference between ${curr} and ${next} is greater than allowed.`)
}

console.debug(`Joltage difference between ${curr} and ${next} is ${delta}.`)
tallies[delta]++
})
console.debug('Tallied voltage differences:', tallies)
return tallies
}

const countCombinations = (data) => {
const tallies = Array(5).fill(0)
const delta = (idx) => {
return data[idx] - data[idx - 1]
}

// Always account for the outlet
data.push(0)
data = data.sort((a, b) => a - b)

const deltas = data.reduce((res, el, idx) => {
console.debug(idx, el, delta(idx))
if (idx <= 0) {
return res
}
res.push(delta(idx))
return res
}, [])
console.debug('joltage deltas', deltas)

// I'm really not proud of this solution. It hardcodes too much logic with magic constants
// and only works because there are no joltage differences of 2, and the max allowed
// skip is 3.
//
// Since the rules say adapters can support 1, 2, or 3 jolt diferences,
// that means if the difference between n and n+2 is 3 or less, n+1 can be safely
// skipped. Potentially we can skip two.
// Every time we skip a number, the total amount of variations doubles

// This logic would be a LOT messier if we had diffs of 2 in the data set

// When we have 2 skips in a row, we need to leave one combo in case
// skipping both exceeds the max difference
// TODO: we aren't implementing this because our data set doesn't have
// any diffs of 2, which means we never have a 1 + 2 skip to worry about

// When we have 3 skips in a row, we're definitely exceeding the max difference
// if the next is also a skip so we have to leave at least one in place

// When we have 5 skips in a row.... etc..
// TODO: we aren't implementing this because dataset doesn't have any examples

deltas.forEach((d, idx, arr) => {
if (d === 1 && arr[idx + 1] === 1 && arr[idx + 2] === 1 && arr[idx + 3] === 1) {
console.debug('Found 4 in a row')
tallies[4]++
deltas.splice(idx, 4)
} else if (d === 1 && arr[idx + 1] === 1 && arr[idx + 2] === 1) {
console.debug('Found 3 in a row')
tallies[3]++
deltas.splice(idx, 3)
} else if (d === 1 && arr[idx + 1] === 1) {
console.debug('Found 2 in a row')
tallies[2]++
deltas.splice(idx, 2)
} else if (d === 1) {
console.debug('Found 1 in a row')
tallies[1]++
deltas.splice(idx, 1)
}
})

console.debug('skippable ranges', tallies)
console.debug([1, 1 ** tallies[1], 2 ** tallies[2], 4 ** tallies[3], 7 ** tallies[4]])
return (
1 ** tallies[1]
) * (
2 ** tallies[2]
) * (
4 ** tallies[3]
) * (
7 ** tallies[4] // 4 in a row is special case because we can't skip more than 3
)
}

module.exports = {
countDifferences,
countCombinations
}
44 changes: 44 additions & 0 deletions 2020/day-10/jolts.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/* eslint-env mocha */
const { expect } = require('chai')
const { countDifferences, countCombinations } = require('./jolts')

const srcAdapters = [
[16, 10, 15, 5, 1, 11, 7, 19, 6, 12, 4],
[28, 33, 18, 42, 31, 14, 46, 20, 48, 47, 24, 23, 49, 45, 19, 38, 39, 11, 1, 32, 25, 35, 8, 17, 7, 9, 4, 2, 34, 10, 3]
]

describe('--- Day 10: Adapter Array ---', () => {
let adapters
beforeEach(() => {
// reset test data since arrays get mutated using a quick-and-dirty deep copy
adapters = JSON.parse(JSON.stringify(srcAdapters))
})
describe('Part 1', () => {
describe('countDifferences()', () => {
it('tabulates the amoount of joltage differences in the adapter set', () => {
const result = countDifferences(adapters[0])
expect(result[1]).to.equal(7)
expect(result[3]).to.equal(5)
const result2 = countDifferences(adapters[1])
expect(result2[1]).to.equal(22)
expect(result2[3]).to.equal(10)
})
it('throws an error if any joltage differences exceed 3', () => {
expect(() => countDifferences([5, 40])).to.throw()
})
it('throws an error if any joltage differences is less than 1', () => {
expect(() => countDifferences([5, 5])).to.throw()
})
})
})
describe('Part 2', () => {
describe('countCombinations()', () => {
it('tabulates the amount of adapter combinations in the set', () => {
const result = countCombinations(adapters[0])
expect(result).to.equal(8)
const result2 = countCombinations(adapters[1])
expect(result2).to.equal(19208)
})
})
})
})
35 changes: 35 additions & 0 deletions 2020/day-10/solution.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const fs = require('fs')
const path = require('path')
const filePath = path.join(__dirname, 'input.txt')
const { inputToArray } = require('../../2018/inputParser')
const { countDifferences, countCombinations } = require('./jolts')

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

initData = inputToArray(initData.trim()).map(Number)

const resetInput = () => {
// Deep copy to ensure we aren't mutating the original data
return JSON.parse(JSON.stringify(initData))
}

const part1 = () => {
const data = resetInput()
const differences = countDifferences(data)
return differences[1] * differences[3]
}

const part2 = () => {
const data = resetInput()
return countCombinations(data)
}
const answers = []
answers.push(part1())
answers.push(part2())

answers.forEach((ans, idx) => {
console.info(`-- Part ${idx + 1} --`)
console.info(`Answer: ${ans}`)
})
})

0 comments on commit 18b7582

Please sign in to comment.