Skip to content

Instantly share code, notes, and snippets.

@ericlifka
Last active December 10, 2017 00:45
Show Gist options
  • Save ericlifka/5b5b3d46d76137d9877567f8806b6895 to your computer and use it in GitHub Desktop.
Save ericlifka/5b5b3d46d76137d9877567f8806b6895 to your computer and use it in GitHub Desktop.
advent of code
let numbers =
`... snip ...`
.split('')
.map(n => parseInt(n, 10))
let sum = 0
for (let index = 0; index < numbers.length; index++)
if (numbers[index] === numbers[(index + 1) % numbers.length])
sum += numbers[index]
console.log('part1', sum)
let jump = numbers.length / 2
sum = 0
numbers.forEach((num, index, arr) => {
if (num === arr[(index + jump) % arr.length])
sum += num
})
console.log('part2', sum)
grid =
`... snip ...`
.split('\n')
.map(row => row
.split(/\s+/)
.map(n => parseInt(n, 10))
.sort((l, r) => r - l))
console.log('part1',
grid.reduce((total, row) =>
total + Math.max.apply(null, row) - Math.min.apply(null, row)
, 0))
console.log('part2',
grid.reduce((total, row) => {
let result = 0
for (let outer = 0; outer <= row.length - 2; outer++)
for (let inner = outer + 1; inner <= row.length - 1; inner++)
if (row[outer] % row[inner] === 0)
result += row[outer] / row[inner]
return total + result
}, 0))
let cache = { '0.0': 1 }
const coordToKey = ({x, y}) => `${x}.${y}`
const getVal = (coord) => cache[ coordToKey(coord) ] || 0
const setVal = (coord, val) => cache[ coordToKey(coord) ] = val
const neighborCoords = ({x, y}) =>
[ [1, 0], [-1, 0], [0, 1], [0, -1], [-1, 1], [1, -1], [1, 1], [-1, -1] ]
.map(([dx, dy]) => ({ x: x + dx, y: y + dy }))
function sequenceGenerator(start = 0) {
let seq = [ 1, 0, -1, 0 ]
let cur = start
return function () {
let val = seq[ cur ]
cur = (cur + 1) % seq.length
return val
}
}
function iterateSpiralNumbers(callback) {
let current = 1
let blockSize = 1
let coord = { x: 0, y: 0 }
let directionGenerators = {
x: sequenceGenerator(),
y: sequenceGenerator(3)
}
let direction = {
x: directionGenerators.x(),
y: directionGenerators.y()
}
while (true) {
for (let doTwice = 0; doTwice < 2; doTwice++) {
for (let blockIndex = 0; blockIndex < blockSize; blockIndex++) {
current++
coord.x += direction.x
coord.y += direction.y
let result = callback(current, coord)
if (result !== undefined)
return result
}
direction.x = directionGenerators.x()
direction.y = directionGenerators.y()
}
blockSize++
}
}
console.log('part1',
iterateSpiralNumbers((number, coord) => {
if (number === 312051)
return { distance: Math.abs(coord.x) + Math.abs(coord.y), coord }
}))
console.log('part2',
iterateSpiralNumbers((number, coord) => {
let sum = neighborCoords(coord)
.map(getVal)
.reduce((total, val) => total + val)
setVal(coord, sum)
if (sum > 312051)
return { sum, coord }
}))
let words =
`... snip ...`
console.log('part1',
words
.split('\n')
.map(passphrase => passphrase
.split(' ')
.sort())
.reduce((total, passphrase) => {
for (let i = 0; i < passphrase.length - 1; i++)
if (passphrase[ i ] === passphrase[ i + 1 ])
return total
return total + 1
}, 0))
console.log('part2',
words
.split('\n')
.map(passphrase => passphrase
.split(' ')
.map(word => word.split('').sort().join(''))
.sort())
.reduce((total, passphrase) => {
for (let i = 0; i < passphrase.length - 1; i++)
if (passphrase[ i ] === passphrase[ i + 1 ])
return total
return total + 1
}, 0))
let maze =
`...snip...`
.split('\n')
.map(n => parseInt(n, 10))
let position = 0
let steps = 0
while (maze[ position ] !== undefined) {
let instruction = maze[ position ]
maze[ position ] += instruction >= 3 ? -1 : 1
position += instruction
steps++
}
console.log(steps)
let data =
`... snip ...`
.split(/\s+/)
.map(n => parseInt(n, 10))
let cycles = 0
let cache = { }
const saveState = () => cache[ data.join(',') ] = cycles
const stateRepeated = () => cache[ data.join(',') ]
const max = () =>
data.indexOf(Math.max.apply(null, data))
function distribute({ position, value }) {
while ( value > 0 ) {
position = (position + 1) % data.length
data[ position ]++
value--
}
}
function removeMax() {
let position = max()
let value = data[ position ]
data[ position ] = 0
return { position, value }
}
while (!stateRepeated()) {
saveState()
distribute(removeMax())
cycles++
}
console.log(`cycles: ${cycles}, cycle time: ${cycles - stateRepeated()}`)
const removeComma = str =>
str[ str.length - 1 ] === ',' ?
str.slice(0, -1) :
str
const NODE_CACHE = { }
const cache = node => NODE_CACHE[ node.name ] = node
const lookup = name => NODE_CACHE[ name ]
const buildNode = ([ name, weight, arrow, ...children ]) => cache({
name,
weight: parseInt(weight.slice(1, -1), 10),
children: arrow ? children.map(removeComma) : [ ]
})
function link(node) {
node.children = node.children.map(lookup)
node.children.forEach(child => child.parent = node)
return node
}
const calcWeight = node => node.totalWeight =
node.children.length === 0 ?
node.weight :
node.children.map(calcWeight)
.reduce((total, weight) => total + weight, node.weight)
function findImbalance(node) {
let {children, children: {length}} = node
if (length === 0) // no children base case, assume self
return node
let weightBuckets = { }
children.forEach(child => weightBuckets[ child.totalWeight ] ?
weightBuckets[ child.totalWeight ].push(child) :
weightBuckets[ child.totalWeight ] = [ child ])
let weights = Object.keys(weightBuckets)
if (weights.length === 1) // all children are balanced so _this_ is the node that's wrong
return node
let rightWeight = weights.find(weight => weightBuckets[ weight ].length !== 1)
let wrongWeight = weights.find(weight => weightBuckets[ weight ].length === 1)
let tree = weightBuckets[ wrongWeight ][ 0 ]
let wrongNode = findImbalance(tree)
if (tree === wrongNode) // we only want to do this on the one where we've found the exact wrong node, not heigher in the tree
console.log(`part2: ${wrongNode.name} weighs ${wrongNode.weight} should weigh ${rightWeight - wrongWeight + wrongNode.weight}`)
return wrongNode
}
let nodes = input()
.split('\n')
.map(desc => desc.split(' '))
.map(buildNode)
.map(link)
let top = nodes[ 0 ] // pick any node and find the top of the tree
while (top.parent)
top = top.parent
console.log(`part1: ${top.name} is the top of the tree`)
calcWeight(top)
findImbalance(top)
function input() {
return `... snip ...`
}
let maxSeen = 0
const registers = { }
const getR = register => registers[ register ]
const setR = (register, value) => {
registers[ register ] = value
if (value > maxSeen)
maxSeen = value
}
const splitChar = char =>
str => str.split(char)
const actionFn = (register, direction, value) =>
() =>
setR(register, direction === 'inc' ?
getR(register) + value :
getR(register) - value)
const comparatorFn = (register, comparator, compValue) =>
() => {
let regValue = getR(register)
switch (comparator) {
case '>': return regValue > compValue
case '<': return regValue < compValue
case '>=': return regValue >= compValue
case '<=': return regValue <= compValue
case '==': return regValue == compValue
case '!=': return regValue != compValue
}
}
const buildInstruction = ([ register, direction, value, _if, condRegister, comparator, compValue ]) => ({
register,
action: actionFn(register, direction, parseInt(value, 10)),
predicate: comparatorFn(condRegister, comparator, parseInt(compValue, 10))
})
let instructions = input()
.split('\n')
.map(splitChar(' '))
.map(buildInstruction)
instructions.forEach(({register}) => setR(register, 0))
instructions.forEach(({register, action, predicate}) => {
if (predicate())
action()
})
let max =
Object.keys(registers)
.sort((l, r) => getR(r) - getR(l))
.map(reg => ({reg, value: getR(reg)}))[ 0 ]
console.log('part1 max: ', max)
console.log('part2 max: ', maxSeen)
function input() {
return `... snip ...`
}
const makeStream = (string, position = 0) =>
() => string[ position++ ]
const makeGroup = parent => {
let group = { parent, children: [ ] }
if (parent)
parent.children.push(group)
return group
}
let char
let group
let inTrash = false
let trashCount = 0
let stream = makeStream(getInput())
while (char = stream()) {
if (inTrash && char === ">")
inTrash = false
else if (inTrash && char === "!")
stream()
else if (inTrash)
trashCount++
else if (char === "<")
inTrash = true
else if (char === "{")
group = makeGroup(group)
else if (char === "}" && group.parent)
group = group.parent
}
const calcScore = (group, scoreLevel = 1) =>
scoreLevel + group.children.reduce((score, group) => score + calcScore(group, scoreLevel + 1), 0)
console.log(`group score: ${calcScore(group)}, trash count: ${trashCount}`)
function getInput() {
return `... snip ...`
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment