-
-
Save mfulton26/d751b83501161a264c576c0cdadfd33b to your computer and use it in GitHub Desktop.
Advent of Code Solutions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
const [,year,day] = /(\d+)\/day\/(\d+)/.exec(location.href).map(Number); | |
const getRawInput = async function() { | |
if (location.href.endsWith("input")) { | |
return document.body.innerText; | |
} else { | |
const response = await fetch(`${day}/input`); | |
return response.text(); | |
} | |
}; | |
const getInput = ()=>getRawInput().then(raw=>raw.slice(0, -1)); | |
getInput().then(function(input) { | |
function solvePart(part) { | |
console.group(`Part ${part}`); | |
const solve = window[`solveYear${year}Day${day}Part${part}`]; | |
if (solve) { | |
console.time("duartion"); | |
console.log("answer:", solve(input)); | |
console.timeEnd("duartion"); | |
} else { | |
console.info(undefined); | |
} | |
console.groupEnd(`Part ${part}`); | |
} | |
console.time(); | |
solvePart(1); | |
if (day !== 25) { | |
solvePart(2); | |
} | |
console.timeEnd(); | |
}); | |
} | |
function solveYear2017Day1Part1(input) { | |
const digits = input.split("").map(Number); | |
let sum = 0; | |
for (let i = 0; i < digits.length; i++) { | |
const digit = digits[i]; | |
const nextDigit = digits[(i + 1) % digits.length]; | |
if (digit === nextDigit) { | |
sum += digit; | |
} | |
} | |
return sum; | |
} | |
function solveYear2017Day1Part2(input) { | |
const digits = input.split("").map(Number); | |
const offset = digits.length / 2; | |
let sum = 0; | |
for (let i = 0; i < digits.length; i++) { | |
const digit = digits[i]; | |
const nextDigit = digits[(i + offset) % digits.length]; | |
if (digit === nextDigit) { | |
sum += digit; | |
} | |
} | |
return sum; | |
} | |
function solveYear2017Day2Part1(input) { | |
function sumBy(array, callback) { | |
return array.reduce((sum,value)=>sum + callback(value), 0); | |
} | |
const table = input.split("\n").map(line=>line.split("\t").map(Number)); | |
return sumBy(table, function(values) { | |
return Math.max(...values) - Math.min(...values); | |
}); | |
} | |
function solveYear2017Day2Part2(input) { | |
function sumBy(array, callback) { | |
return array.reduce((sum,value)=>sum + callback(value), 0); | |
} | |
const table = input.split("\n").map(line=>line.split("\t").map(Number)); | |
return sumBy(table, function(values) { | |
values.sort((a,b)=>a - b); | |
for (let i = 0; i < values.length; i++) { | |
const a = values[i]; | |
for (let j = i + 1; j < values.length; j++) { | |
const b = values[j]; | |
const quotient = b / a; | |
if (Number.isInteger(quotient)) { | |
return quotient; | |
} | |
} | |
} | |
}); | |
} | |
function solveYear2017Day3Part1(input) { | |
function coordinates(n) { | |
let x = y = 0; | |
for (; n > 1; n--) { | |
const k = Math.floor(Math.sqrt(4 * (n - 2) + 1)) % 4; | |
const angle = k * Math.PI / 2; | |
x += Math.round(Math.sin(angle)); | |
y -= Math.round(Math.cos(angle)); | |
} | |
return [x, y]; | |
} | |
const value = Number(input); | |
return coordinates(value).reduce((sum,n)=>sum + Math.abs(n), 0); | |
} | |
function solveYear2017Day3Part2(input) { | |
function coordinates(n) { | |
let x = y = 0; | |
for (; n > 1; n--) { | |
const k = Math.floor(Math.sqrt(4 * (n - 2) + 1)) % 4; | |
const angle = k * Math.PI / 2; | |
x += Math.round(Math.sin(angle)); | |
y -= Math.round(Math.cos(angle)); | |
} | |
return [x, y]; | |
} | |
const value = Number(input); | |
const sums = {}; | |
sums[[0, 0]] = 1; | |
for (let n = 2; ; n++) { | |
const [x,y] = coordinates(n); | |
let sum = 0; | |
for (let dx = -1; dx <= 1; dx++) { | |
const ax = x + dx; | |
for (let dy = -1; dy <= 1; dy++) { | |
const ay = y + dy; | |
sum += sums[[ax, ay]] || 0; | |
} | |
} | |
sums[[x, y]] = sum; | |
if (sum > value) { | |
return sum; | |
} | |
} | |
} | |
function solveYear2017Day4Part1(input) { | |
const passphrases = input.split("\n"); | |
function isValid(passphrase) { | |
const words = passphrase.split(" "); | |
const dedupedWords = new Set(words); | |
return dedupedWords.size === words.length; | |
} | |
return passphrases.filter(isValid).length; | |
} | |
function solveYear2017Day4Part2(input) { | |
const passphrases = input.split("\n"); | |
function isValid(passphrase) { | |
const words = passphrase.split(" "); | |
const dedupedAnagrams = new Set(words.map(function(word) { | |
return word.split("").sort().join(""); | |
})); | |
return dedupedAnagrams.size === words.length; | |
} | |
return passphrases.filter(isValid).length; | |
} | |
function solveYear2017Day5Part1(input) { | |
const instructions = input.split("\n").map(Number); | |
let step = 0; | |
for (let index = 0; index < instructions.length; step++) { | |
index += instructions[index]++; | |
} | |
return step; | |
} | |
function solveYear2017Day5Part2(input) { | |
const instructions = input.split("\n").map(Number); | |
let step = 0; | |
for (let index = 0; index < instructions.length; step++) { | |
const instruction = instructions[index]; | |
if (instruction >= 3) { | |
instructions[index] = instruction - 1; | |
} else { | |
instructions[index] = instruction + 1; | |
} | |
index += instruction; | |
} | |
return step; | |
} | |
function solveYear2017Day6Part1(input) { | |
const banks = input.split("\t").map(Number); | |
const seen = new Set([banks.join()]); | |
while (true) { | |
let blocksToRedistribute = Math.max(...banks); | |
const indexOfBankToRedistribute = banks.indexOf(blocksToRedistribute); | |
banks[indexOfBankToRedistribute] = 0; | |
for (let offset = 1; blocksToRedistribute; offset++) { | |
const indexOfBank = (indexOfBankToRedistribute + offset) % banks.length; | |
blocksToRedistribute--; | |
banks[indexOfBank]++; | |
} | |
const key = banks.join(); | |
if (seen.has(key)) { | |
return seen.size; | |
} else { | |
seen.add(key); | |
} | |
} | |
} | |
function solveYear2017Day6Part2(input) { | |
function detectInfiniteLoop(banks) { | |
const seen = new Set([banks.join()]); | |
while (true) { | |
let blocksToRedistribute = Math.max(...banks); | |
const indexOfBankToRedistribute = banks.indexOf(blocksToRedistribute); | |
banks[indexOfBankToRedistribute] = 0; | |
for (let offset = 1; blocksToRedistribute; offset++) { | |
const indexOfBank = (indexOfBankToRedistribute + offset) % banks.length; | |
blocksToRedistribute--; | |
banks[indexOfBank]++; | |
} | |
const key = banks.join(); | |
if (seen.has(key)) { | |
return { | |
same: banks, | |
size: seen.size | |
}; | |
} else { | |
seen.add(key); | |
} | |
} | |
} | |
const banks = input.split("\t").map(Number); | |
return detectInfiniteLoop(detectInfiniteLoop(banks).same).size; | |
} | |
function solveYear2017Day7Part1(input) { | |
const names = []; | |
const parentNames = {}; | |
for (const line of input.split("\n")) { | |
const [lhs,rhs] = line.split(" -> "); | |
const [,name,] = /(\S+)\s\((\d+)\)/.exec(lhs); | |
names.push(name); | |
if (rhs) { | |
for (const childName of rhs.split(", ")) { | |
parentNames[childName] = name; | |
} | |
} | |
} | |
return names.find(name=>!parentNames.hasOwnProperty(name)); | |
} | |
function solveYear2017Day7Part2(input) { | |
const names = []; | |
const weights = {}; | |
const parentNames = {}; | |
const childrenNames = {}; | |
for (const line of input.split("\n")) { | |
const [lhs,rhs] = line.split(" -> "); | |
const [,name,weight] = /(\S+)\s\((\d+)\)/.exec(lhs); | |
names.push(name) | |
weights[name] = Number(weight); | |
if (rhs) { | |
childrenNames[name] = rhs.split(", "); | |
for (const childName of childrenNames[name]) { | |
parentNames[childName] = name; | |
} | |
} | |
} | |
const totalWeights = {}; | |
{ | |
const queue = names.filter(name=>!childrenNames.hasOwnProperty(name)); | |
while (queue.length) { | |
const name = queue.shift(); | |
const weight = weights[name]; | |
totalWeights[name] = weight | |
if (childrenNames.hasOwnProperty(name)) { | |
const childNames = childrenNames[name]; | |
for (const childName of childNames) { | |
totalWeights[name] += totalWeights[childName]; | |
} | |
} | |
const parentName = parentNames[name]; | |
if (parentName && !queue.includes(parentName)) { | |
queue.push(parentName); | |
} | |
} | |
} | |
let unbalancedName = names.find(name=>!parentNames.hasOwnProperty(name)); | |
let delta; | |
while (true) { | |
const childNames = childrenNames[unbalancedName]; | |
const childTotalWeights = childNames.map(childName=>totalWeights[childName]); | |
function findCounts(array) { | |
const counts = new Map(); | |
for (const element of array) { | |
const count = counts.get(element); | |
counts.set(element, count ? count + 1 : 1); | |
} | |
return counts; | |
} | |
const counts = findCounts(childTotalWeights); | |
const indexOfUnbalancedChildName = childTotalWeights.findIndex(w=>counts.get(w) === 1); | |
if (indexOfUnbalancedChildName === -1) { | |
return weights[unbalancedName] + delta; | |
} else { | |
unbalancedName = childNames[indexOfUnbalancedChildName]; | |
const unbalancedTotalWeight = childTotalWeights[indexOfUnbalancedChildName]; | |
const desiredTotalWeight = childTotalWeights.find(w=>w != unbalancedTotalWeight) | |
delta = desiredTotalWeight - unbalancedTotalWeight | |
} | |
} | |
} | |
function solveYear2017Day8Part1(input) { | |
const comparators = { | |
"<": (a,b)=>a < b, | |
">": (a,b)=>a > b, | |
"<=": (a,b)=>a <= b, | |
">=": (a,b)=>a >= b, | |
"==": (a,b)=>a == b, | |
"!=": (a,b)=>a != b, | |
}; | |
const operators = { | |
"inc": (a,b)=>a + b, | |
"dec": (a,b)=>a - b | |
}; | |
const values = {}; | |
let max = 0; | |
for (const line of input.split("\n")) { | |
const match = /(\S+) (inc|dec) (\S+) if (\S+) (\S+) (\S+)/.exec(line); | |
const register = match[1]; | |
const operator = operators[match[2]]; | |
const amount = Number(match[3]); | |
if (comparators[match[5]](values[match[4]] || 0, Number(match[6]))) { | |
const value = operator(values[register] || 0, amount); | |
values[register] = value; | |
if (value > max) { | |
max = value; | |
} | |
} | |
} | |
return Math.max(...Object.values(values)); | |
} | |
function solveYear2017Day8Part2(input) { | |
const comparators = { | |
"<": (a,b)=>a < b, | |
">": (a,b)=>a > b, | |
"<=": (a,b)=>a <= b, | |
">=": (a,b)=>a >= b, | |
"==": (a,b)=>a == b, | |
"!=": (a,b)=>a != b, | |
}; | |
const operators = { | |
"inc": (a,b)=>a + b, | |
"dec": (a,b)=>a - b | |
}; | |
const values = {}; | |
let max = 0; | |
for (const line of input.split("\n")) { | |
const match = /(\S+) (inc|dec) (\S+) if (\S+) (\S+) (\S+)/.exec(line); | |
const register = match[1]; | |
const operator = operators[match[2]]; | |
const amount = Number(match[3]); | |
if (comparators[match[5]](values[match[4]] || 0, Number(match[6]))) { | |
const value = operator(values[register] || 0, amount); | |
values[register] = value; | |
if (value > max) { | |
max = value; | |
} | |
} | |
} | |
return max; | |
} | |
function solveYear2017Day9Part1(input) { | |
var characters = input[Symbol.iterator](); | |
let score = 0; | |
let depth = 0; | |
for (const character of characters) { | |
switch (character) { | |
case "{": | |
score += ++depth; | |
break; | |
case "}": | |
depth--; | |
break; | |
case "<": | |
character = characters.next().value; | |
while (character != ">") { | |
if (character === "!") { | |
characters.next(); | |
} | |
character = characters.next().value; | |
} | |
break; | |
} | |
} | |
return score; | |
} | |
function solveYear2017Day9Part2(input) { | |
var characters = input[Symbol.iterator](); | |
let score = 0; | |
let depth = 0; | |
let garbageCount = 0; | |
for (const character of characters) { | |
switch (character) { | |
case "{": | |
score += ++depth; | |
break; | |
case "}": | |
depth--; | |
break; | |
case "<": | |
character = characters.next().value; | |
while (character != ">") { | |
if (character === "!") { | |
characters.next(); | |
} else { | |
garbageCount++; | |
} | |
character = characters.next().value; | |
} | |
break; | |
} | |
} | |
return garbageCount; | |
} | |
function solveYear2017Day10Part1(input) { | |
const lengths = input.split(",").map(Number); | |
let list = Array.from(Array(256).keys()); | |
let currentPosition = 0; | |
let skipSize = 0; | |
for (const length of lengths) { | |
list = list.concat(list.splice(0, length).reverse()); | |
list = list.concat(list.splice(0, skipSize % list.length)); | |
currentPosition += length; | |
currentPosition += skipSize++; | |
currentPosition %= list.length; | |
} | |
list = list.splice(list.length - currentPosition).concat(list); | |
return list[0] * list[1]; | |
} | |
function solveYear2017Day10Part2(input) { | |
function bytesToHexString(bytes) { | |
return bytes.map(n=>("0" + n.toString(16)).substr(-2)).join(""); | |
} | |
const lengths = input.split("").map(c=>c.charCodeAt(0)).concat(17, 31, 73, 47, 23); | |
let list = Array.from(Array(256).keys()); | |
let currentPosition = 0; | |
let skipSize = 0; | |
for (let i = 0; i < 64; i++) { | |
for (const length of lengths) { | |
list = list.concat(list.splice(0, length).reverse()); | |
list = list.concat(list.splice(0, skipSize % list.length)); | |
currentPosition += length; | |
currentPosition += skipSize++; | |
currentPosition %= list.length; | |
} | |
} | |
list = list.splice(list.length - currentPosition).concat(list); | |
const denseHash = Array.from(Array(16).keys()).map(function(index) { | |
const begin = index * 16; | |
const end = begin + 16; | |
return list.slice(begin, end).reduce((a,b)=>a ^ b); | |
}); | |
return bytesToHexString(denseHash); | |
} | |
function solveYear2017Day11Part1(input) { | |
const f = { | |
"n": ([x,y,z])=>([x, y, z + 1]), | |
"s": ([x,y,z])=>([x, y, z - 1]), | |
"ne": ([x,y,z])=>([x + 0.5, y, z]), | |
"sw": ([x,y,z])=>([x - 0.5, y, z]), | |
"nw": ([x,y,z])=>([x, y + 0.5, z]), | |
"se": ([x,y,z])=>([x, y - 0.5, z]) | |
}; | |
let c = [0, 0, 0]; | |
for (const d of input.split(",")) { | |
c = f[d](c); | |
} | |
return Math.abs(c[0] - c[1]) + Math.abs(c[0] + c[1] + c[2]); | |
} | |
function solveYear2017Day11Part2(input) { | |
const f = { | |
"n": ([x,y,z])=>([x, y, z + 1]), | |
"s": ([x,y,z])=>([x, y, z - 1]), | |
"ne": ([x,y,z])=>([x + 0.5, y, z]), | |
"sw": ([x,y,z])=>([x - 0.5, y, z]), | |
"nw": ([x,y,z])=>([x, y + 0.5, z]), | |
"se": ([x,y,z])=>([x, y - 0.5, z]) | |
}; | |
let c = [0, 0, 0]; | |
let max = 0; | |
for (const d of input.split(",")) { | |
c = f[d](c); | |
let m = Math.abs(c[0] - c[1]) + Math.abs(c[0] + c[1] + c[2]); | |
if (m > max) { | |
max = m; | |
} | |
} | |
return max; | |
} | |
function solveYear2017Day12Part1(input) { | |
const connections = new Map(); | |
for (const line of input.split("\n")) { | |
const [,key,values] = /(\d+) <-> (.*)/.exec(line); | |
connections.set(key, values.split(", ")); | |
} | |
const connectedIds = new Set(); | |
const queue = ["0"]; | |
while (queue.length) { | |
const id = queue.shift(); | |
if (!connectedIds.has(id)) { | |
connectedIds.add(id); | |
queue.push(...connections.get(id)); | |
} | |
} | |
return connectedIds.size; | |
} | |
function solveYear2017Day12Part2(input) { | |
const connections = new Map(); | |
for (const line of input.split("\n")) { | |
const [,key,values] = /(\d+) <-> (.*)/.exec(line); | |
connections.set(key, values.split(", ")); | |
} | |
function findConnectedIds(id) { | |
const connectedIds = new Set(); | |
const queue = [id]; | |
while (queue.length) { | |
const id = queue.shift(); | |
if (!connectedIds.has(id)) { | |
connectedIds.add(id); | |
queue.push(...connections.get(id)); | |
} | |
} | |
return connectedIds; | |
} | |
const ids = new Set(); | |
let groupCount = 0; | |
for (const id of connections.keys()) { | |
if (ids.has(id)) { | |
continue; | |
} | |
const connectedIds = findConnectedIds(id); | |
connectedIds.forEach(id=>ids.add(id)); | |
groupCount++; | |
} | |
return groupCount; | |
} | |
function solveYear2017Day13Part1(input) { | |
const ranges = []; | |
for (line of input.split("\n")) { | |
const [depth,range] = line.split(": ").map(Number); | |
ranges[depth] = range; | |
} | |
return ranges.reduce(function(severity, range, depth) { | |
const position = depth % (2 * (range - 1)); | |
return position ? severity : severity + depth * range; | |
}, 0); | |
} | |
function solveYear2017Day13Part2(input) { | |
const ranges = []; | |
for (line of input.split("\n")) { | |
const [depth,range] = line.split(": ").map(Number); | |
ranges[depth] = range; | |
} | |
function isCaught(delay) { | |
return ranges.some(function(range, depth) { | |
const position = (delay + depth) % (2 * (range - 1)); | |
return position === 0; | |
}); | |
} | |
let delay = 0; | |
while (isCaught(delay)) { | |
++delay; | |
} | |
return delay; | |
} | |
function solveYear2017Day14Part1(input) { | |
function parseBytes(string, radix) { | |
return string.split("").map(s=>parseInt(s, radix)); | |
} | |
function bytesToBinString(bytes) { | |
return bytes.map(n=>("0000" + n.toString(2)).substr(-4)).join(""); | |
} | |
let matchCount = 0; | |
for (let row = 0; row < 128; row++) { | |
const hashHexString = solveYear2017Day10Part2(`${input}-${row}`); | |
const hashBytes = parseBytes(hashHexString, 16); | |
const hashBinString = bytesToBinString(hashBytes); | |
matchCount += (hashBinString.match(/1/g) || []).length; | |
} | |
return matchCount; | |
} | |
function solveYear2017Day14Part2(input) { | |
function parseBytes(string, radix) { | |
return string.split("").map(s=>parseInt(s, radix)); | |
} | |
function bytesToBinString(bytes) { | |
return bytes.map(n=>("0000" + n.toString(2)).substr(-4)).join(""); | |
} | |
const grid = []; | |
for (let row = 0; row < 128; row++) { | |
const hashHexString = solveYear2017Day10Part2(`${input}-${row}`); | |
const hashBytes = parseBytes(hashHexString, 16); | |
const hashBinString = bytesToBinString(hashBytes); | |
grid.push(hashBinString.split("").map(s=>s === "1" ? 0 : undefined)); | |
} | |
let regionCount = 0; | |
function set(row, column, value) { | |
if (grid[row] && grid[row][column] === 0) { | |
grid[row][column] = value; | |
set(row - 1, column, value); | |
set(row + 1, column, value); | |
set(row, column - 1, value); | |
set(row, column + 1, value); | |
} | |
} | |
for (let row = 0; row < grid.length; row++) { | |
for (let column = 0; column < grid[row].length; column++) { | |
if (grid[row][column] === 0) { | |
set(row, column, ++regionCount); | |
} | |
} | |
} | |
return regionCount; | |
} | |
function solveYear2017Day15Part1(input) { | |
function *generator(value, factor) { | |
while (true) { | |
value = (value * factor) % 2147483647; | |
yield value; | |
} | |
} | |
const a = generator(Number(/Generator A starts with (\d+)/.exec(input)[1]), 16807); | |
const b = generator(Number(/Generator B starts with (\d+)/.exec(input)[1]), 48271); | |
let matchCount = 0; | |
for (let i = 0; i < 40E6; i++) { | |
if ((a.next().value & 0xFFFF) === (b.next().value & 0xFFFF)) { | |
++matchCount; | |
} | |
} | |
return matchCount; | |
} | |
function solveYear2017Day15Part2(input) { | |
function *generator(value, factor) { | |
while (true) { | |
value = (value * factor) % 2147483647; | |
yield value; | |
} | |
} | |
let a = generator(Number(/Generator A starts with (\d+)/.exec(input)[1]), 16807); | |
let b = generator(Number(/Generator B starts with (\d+)/.exec(input)[1]), 48271); | |
function *filter(generator, predicate) { | |
for (value of generator) { | |
if (predicate(value)) { | |
yield value; | |
} | |
} | |
} | |
a = filter(a, v=>v % 4 === 0); | |
b = filter(b, v=>v % 8 === 0); | |
let matchCount = 0; | |
for (let i = 0; i < 5E6; i++) { | |
if ((a.next().value & 0xFFFF) === (b.next().value & 0xFFFF)) { | |
++matchCount; | |
} | |
} | |
return matchCount; | |
} | |
function solveYear2017Day16Part1(input) { | |
let programs = "abcdefghijklmnop".split(""); | |
const fn = { | |
s: x=>programs = programs.splice(-x).concat(programs), | |
x: (a,b)=>[programs[a],programs[b]] = [programs[b], programs[a]], | |
p: (a,b)=>fn.x(programs.indexOf(a), programs.indexOf(b)) | |
} | |
input.split(",").map(s=>fn[s[0]](...s.substr(1).split("/"))); | |
return programs.join(""); | |
} | |
function solveYear2017Day16Part2(input) { | |
let programs = "abcdefghijklmnop".split(""); | |
const fn = { | |
s: x=>()=>programs = programs.splice(-x).concat(programs), | |
x: (a,b)=>()=>[programs[a],programs[b]] = [programs[b], programs[a]], | |
p: (a,b)=>()=>fn.x(programs.indexOf(a), programs.indexOf(b))() | |
} | |
const moves = input.split(",").map(s=>fn[s[0]](...s.substr(1).split("/"))); | |
moves.forEach(move=>move()); | |
const first = programs.join(""); | |
for (let i = 1; i < 1E9; i++) { | |
moves.forEach(move=>move()); | |
if (programs.join("") === first) { | |
i = 1E9 - 1E9 % i; | |
} | |
} | |
return programs.join(""); | |
} | |
function solveYear2017Day17Part1(input) { | |
const steps = Number(input); | |
let buffer = [0]; | |
let position = 0; | |
for (let i = 1; i <= 2017; i++) { | |
position += steps + 1; | |
position %= buffer.length; | |
buffer.splice(position, 0, i); | |
} | |
return buffer[(position + 1) % buffer.length]; | |
} | |
function solveYear2017Day17Part2(input) { | |
const steps = Number(input); | |
let bufferLength = 1; | |
let position = 0; | |
let value; | |
for (let i = 1; i < 50E6; i++) { | |
position += steps + 1; | |
position %= bufferLength++; | |
if (position === 0) { | |
value = i; | |
} | |
} | |
return value; | |
} | |
function solveYear2017Day18Part1(input) { | |
let sound; | |
const registers = new Proxy({},{ | |
get: (target,name)=>target.hasOwnProperty(name) ? target[name] : 0 | |
}); | |
const valueOf = x=>isNaN(x) ? registers[x] : Number(x); | |
function instruction(x, y) { | |
this.x = x; | |
this.y = y; | |
this.offset = 1; | |
} | |
const fn = { | |
snd: function(x) { | |
instruction.call(this, x); | |
this.exec = ()=>{ | |
sound = valueOf(x); | |
} | |
}, | |
set: function(x, y) { | |
instruction.call(this, x, y); | |
this.exec = ()=>{ | |
registers[x] = valueOf(y); | |
} | |
}, | |
add: function(x, y) { | |
instruction.call(this, x, y); | |
this.exec = ()=>{ | |
registers[x] += valueOf(y) | |
} | |
}, | |
mul: function(x, y) { | |
instruction.call(this, x, y); | |
this.exec = ()=>{ | |
registers[x] *= valueOf(y) | |
} | |
}, | |
mod: function(x, y) { | |
instruction.call(this, x, y); | |
this.exec = ()=>{ | |
registers[x] %= valueOf(y) | |
} | |
}, | |
rcv: function(x) { | |
instruction.call(this, x); | |
this.exec = ()=>{ | |
if (registers[x]) { | |
return "done"; | |
} | |
} | |
}, | |
jgz: function(x, y) { | |
instruction.call(this, x, y); | |
this.exec = ()=>{ | |
this.offset = valueOf(x) > 0 ? valueOf(y) : 1; | |
} | |
}, | |
} | |
const instructions = input.split("\n").map(function(line) { | |
const words = line.split(" "); | |
return new fn[words[0]](...words.splice(1)); | |
}); | |
for (let i = 0; i >= 0 && i < instructions.length; i += instructions[i].offset) { | |
const instruction = instructions[i]; | |
if (instruction.exec() === "done") { | |
break; | |
} | |
} | |
return sound; | |
} | |
function solveYear2017Day18Part2(input) { | |
const queues = [[], []]; | |
const counts = [0, 0]; | |
function *program(pid) { | |
const incoming = queues[pid]; | |
const outgoing = queues[(pid + 1) % 2]; | |
const registers = new Proxy({ | |
p: pid | |
},{ | |
get: (target,name)=>target.hasOwnProperty(name) ? target[name] : 0 | |
}); | |
const valueOf = x=>isNaN(x) ? registers[x] : Number(x); | |
function instruction(x, y) { | |
this.x = x; | |
this.y = y; | |
this.offset = 1; | |
} | |
const fn = { | |
snd: function(x) { | |
instruction.call(this, x); | |
this.exec = ()=>{ | |
outgoing.push(valueOf(x)); | |
} | |
}, | |
set: function(x, y) { | |
instruction.call(this, x, y); | |
this.exec = ()=>{ | |
registers[x] = valueOf(y); | |
} | |
}, | |
add: function(x, y) { | |
instruction.call(this, x, y); | |
this.exec = ()=>{ | |
registers[x] += valueOf(y) | |
} | |
}, | |
mul: function(x, y) { | |
instruction.call(this, x, y); | |
this.exec = ()=>{ | |
registers[x] *= valueOf(y) | |
} | |
}, | |
mod: function(x, y) { | |
instruction.call(this, x, y); | |
this.exec = ()=>{ | |
registers[x] %= valueOf(y) | |
} | |
}, | |
rcv: function(x) { | |
instruction.call(this, x); | |
this.exec = ()=>{ | |
registers[x] = incoming.shift(); | |
} | |
}, | |
jgz: function(x, y) { | |
instruction.call(this, x, y); | |
this.exec = ()=>{ | |
this.offset = valueOf(x) > 0 ? valueOf(y) : 1; | |
} | |
}, | |
} | |
const instructions = input.split("\n").map(function(line) { | |
const words = line.split(" "); | |
return new fn[words[0]](...words.splice(1)); | |
}); | |
for (let i = 0; i >= 0 && i < instructions.length; i += instructions[i].offset) { | |
const instruction = instructions[i]; | |
switch (instruction.constructor.name) { | |
case "snd": | |
++counts[pid]; | |
break; | |
case "rcv": | |
while (incoming.length === 0) { | |
yield; | |
} | |
break; | |
} | |
instruction.exec(); | |
} | |
} | |
const programs = [program(0), program(1)]; | |
let done = false; | |
duet: while (!done) { | |
programs.forEach(function(program, pid) { | |
const previousCount = counts[pid]; | |
done |= program.next().done; | |
const count = counts[pid]; | |
done |= (count === previousCount); | |
}); | |
} | |
return counts[1]; | |
} | |
function solveYear2017Day19Part1(input) { | |
const lines = input.split("\n"); | |
function charAt(x, y) { | |
return lines[y].charAt(x) || " "; | |
} | |
let y = 0; | |
let x = lines[y].indexOf("|"); | |
let dx = 0; | |
let dy = 1; | |
const letters = []; | |
while (true) { | |
let char; | |
while ((char = charAt(x + dx, y + dy)) != " ") { | |
if (char.match(/[A-Z]/)) { | |
letters.push(char); | |
} | |
x += dx; | |
y += dy; | |
} | |
if (charAt(x, y) === "+") { | |
if (charAt(x + dy, y - dx) !== " ") { | |
[dx,dy] = [dy, -dx]; | |
continue; | |
} else if (charAt(x - dy, y + dx) !== " ") { | |
[dx,dy] = [-dy, dx]; | |
continue; | |
} | |
} | |
break; | |
} | |
return letters.join(""); | |
} | |
function solveYear2017Day19Part2(input) { | |
const lines = input.split("\n"); | |
function charAt(x, y) { | |
return lines[y].charAt(x) || " "; | |
} | |
let y = 0; | |
let x = lines[y].indexOf("|"); | |
let dx = 0; | |
let dy = 1; | |
let steps = 1; | |
while (true) { | |
let char; | |
while ((char = charAt(x + dx, y + dy)) != " ") { | |
x += dx; | |
y += dy; | |
++steps; | |
} | |
if (charAt(x, y) === "+") { | |
if (charAt(x + dy, y - dx) !== " ") { | |
[dx,dy] = [dy, -dx]; | |
continue; | |
} else if (charAt(x - dy, y + dx) !== " ") { | |
[dx,dy] = [-dy, dx]; | |
continue; | |
} | |
} | |
break; | |
} | |
return steps; | |
} | |
function solveYear2017Day20Part1(input) { | |
const particles = input.split("\n").map(function(line, index) { | |
const [p,v,a] = line.split(", ").map(function(s) { | |
return s.slice(3, -1).split(",").map(Number); | |
}); | |
return { | |
p, | |
v, | |
a | |
}; | |
}); | |
const mds = particles.map(({a})=>a.reduce((m,a)=>m + Math.abs(a), 0)); | |
return mds.indexOf(Math.min(...mds)); | |
} | |
function solveYear2017Day20Part2(input) { | |
const particles = input.split("\n").map(function(line, index) { | |
const [p,v,a] = line.split(", ").map(function(s) { | |
return s.slice(3, -1).split(",").map(Number); | |
}); | |
return { | |
p, | |
v, | |
a | |
}; | |
}); | |
function quadraticRoots(a, b, c) { | |
const x = []; | |
if (a === 0) { | |
if (b !== 0) { | |
x.push(-c / b); | |
} | |
} else { | |
const bSquared = b * b; | |
const fourAC = 4 * a * c; | |
const twoA = 2 * a; | |
if (bSquared === fourAC) { | |
x.push(-b / twoA); | |
} else if (bSquared > fourAC) { | |
const squareRoot = Math.sqrt(bSquared - fourAC); | |
x.push((-b + squareRoot) / twoA); | |
x.push((-b - squareRoot) / twoA); | |
} | |
} | |
return x; | |
} | |
function qp(a, b, c) { | |
return (-b + Math.sqrt(b * b - 4 * a * c)) / (2 * a); | |
} | |
const intersectionsByTime = new Map(); | |
for (let i = 0; i < particles.length; i++) { | |
const {p: p_i, v: v_i, a: a_i} = particles[i]; | |
for (let j = i + 1; j < particles.length; j++) { | |
const {p: p_j, v: v_j, a: a_j} = particles[j]; | |
function abc(k) { | |
const a = (a_i[k] - a_j[k]) / 2; | |
const b = (v_i[k] + a_i[k] / 2) - (v_j[k] + a_j[k] / 2); | |
const c = p_i[k] - p_j[k]; | |
return [a, b, c]; | |
} | |
const times = quadraticRoots(...abc(0)).filter(Number.isInteger).filter(n=>n > 0); | |
for (const t of times) { | |
if ([1, 2].every(function(k) { | |
const [a,u,s] = abc(k); | |
return -s === u * t + a * t * t; | |
})) { | |
const intersection = { | |
i, | |
j | |
}; | |
if (intersectionsByTime.has(t)) { | |
intersectionsByTime.get(t).push(intersection); | |
} else { | |
intersectionsByTime.set(t, [intersection]); | |
} | |
} | |
} | |
} | |
} | |
const times = Array.from(intersectionsByTime.keys()).sort((a,b)=>a - b); | |
const survivedIndices = new Set(Object.keys(particles).map(Number)); | |
for (const time of times) { | |
const intersections = intersectionsByTime.get(time); | |
const toDelete = new Set(); | |
for ({i, j} of intersections) { | |
if (survivedIndices.has(i) && survivedIndices.has(j)) { | |
toDelete.add(i); | |
toDelete.add(j); | |
} | |
} | |
for (const index of toDelete) { | |
survivedIndices.delete(index); | |
} | |
} | |
return survivedIndices.size; | |
} | |
function solveYear2017Day21Part1(input, {iterations=5}={}) { | |
const Matrix = { | |
from(matrix) { | |
const result = []; | |
for (const array of matrix) { | |
result.push(Array.from(array)); | |
} | |
return result; | |
}, | |
parse(string) { | |
return string.split("/").map(l=>l.split("").map(c=>c === "#" ? 1 : 0)); | |
}, | |
stringify(matrix) { | |
return matrix.map(a=>a.map(e=>e ? "#" : ".").join("")).join("/"); | |
}, | |
rotate(matrix) { | |
matrix.reverse(); | |
for (let i = 0; i < matrix.length; i++) { | |
for (let j = 0; j < i; j++) { | |
[matrix[i][j],matrix[j][i]] = [matrix[j][i], matrix[i][j]]; | |
} | |
} | |
return matrix; | |
}, | |
flip(matrix) { | |
return matrix.reverse(); | |
} | |
} | |
const rules = {}; | |
for (const line of input.split("\n")) { | |
const [pattern,output] = line.split(" => ").map(Matrix.parse); | |
for (let i = 0; i < 4; i++) { | |
Matrix.rotate(pattern); | |
rules[pattern] = output; | |
Matrix.flip(pattern); | |
rules[pattern] = output; | |
Matrix.flip(pattern); | |
} | |
} | |
let image = Matrix.parse(".#./..#/###"); | |
for (let iteration = 0; iteration < iterations; iteration++) { | |
const n = 2 + image.length % 2; | |
let matrix = []; | |
for (let i = 0; i < image.length / n; i++) { | |
const array = []; | |
for (let j = 0; j < image.length / n; j++) { | |
const square = []; | |
for (let k = n * i; k < n * i + n; k++) { | |
square.push(image[k].slice(n * j, n * j + n)); | |
} | |
array.push(square); | |
} | |
matrix.push(array); | |
} | |
matrix = matrix.map(array=>array.map(square=>rules[square])); | |
image = []; | |
for (let i = 0; i < matrix.length; i++) { | |
const array = matrix[i]; | |
for (let j = 0; j < array[0].length; j++) { | |
image.push(array.reduce((l,square)=>l.concat(square[j]), [])); | |
} | |
} | |
} | |
return image.reduce((n,pixels)=>n + pixels.reduce((n,pixel)=>pixel ? n + 1 : n, 0), 0); | |
} | |
function solveYear2017Day21Part2(input) { | |
return solveYear2017Day21Part1(input, { | |
iterations: 18 | |
}); | |
} | |
function solveYear2017Day22Part1(input) { | |
const infected = new Set(); | |
const isInfected = (x,y)=>infected.has(`${x},${y}`); | |
const infect = (x,y)=>infected.add(`${x},${y}`); | |
const clean = (x,y)=>infected.delete(`${x},${y}`); | |
input.split("\n").forEach(function(line, i, lines) { | |
const y = -i + Math.trunc(lines.length / 2); | |
line.split("").forEach(function(char, j, chars) { | |
const x = j - Math.trunc(chars.length / 2); | |
if (char === "#") { | |
infect(x, y); | |
} | |
}); | |
}); | |
let x = 0; | |
let y = 0; | |
let dx = 0; | |
let dy = 1; | |
const turnRight = ()=>[dx,dy] = [dy, -dx]; | |
const turnLeft = ()=>[dx,dy] = [-dy, dx]; | |
const moveForward = ()=>[x,y] = [x + dx, y + dy]; | |
let infections = 0; | |
for (let burst = 0; burst < 10000; burst++) { | |
if (isInfected(x, y)) { | |
turnRight(); | |
clean(x, y); | |
} else { | |
turnLeft(); | |
infect(x, y); | |
++infections; | |
} | |
moveForward(); | |
} | |
return infections; | |
} | |
function solveYear2017Day22Part2(input) { | |
const unclean = new Map(); | |
const state = (x,y)=>unclean.get(`${x},${y}`) || "clean"; | |
const weaken = (x,y)=>unclean.set(`${x},${y}`, "weakened"); | |
const infect = (x,y)=>unclean.set(`${x},${y}`, "infected"); | |
const flag = (x,y)=>unclean.set(`${x},${y}`, "flagged"); | |
const clean = (x,y)=>unclean.delete(`${x},${y}`); | |
input.split("\n").forEach(function(line, i, lines) { | |
const y = -i + Math.trunc(lines.length / 2); | |
line.split("").forEach(function(char, j, chars) { | |
const x = j - Math.trunc(chars.length / 2); | |
if (char === "#") { | |
infect(x, y); | |
} | |
}); | |
}); | |
let x = 0; | |
let y = 0; | |
let dx = 0; | |
let dy = 1; | |
const turnRight = ()=>[dx,dy] = [dy, -dx]; | |
const turnLeft = ()=>[dx,dy] = [-dy, dx]; | |
const turnAround = ()=>[dx,dy] = [-dx, -dy]; | |
const moveForward = ()=>[x,y] = [x + dx, y + dy]; | |
let infections = 0; | |
for (let burst = 0; burst < 10000000; burst++) { | |
switch (state(x, y)) { | |
case "clean": | |
turnLeft(); | |
weaken(x, y); | |
break; | |
case "weakened": | |
infect(x, y); | |
++infections; | |
break; | |
case "infected": | |
turnRight(); | |
flag(x, y); | |
break; | |
case "flagged": | |
turnAround(); | |
clean(x, y); | |
break; | |
} | |
moveForward(); | |
} | |
return infections; | |
} | |
function solveYear2017Day23Part1(input) { | |
const registers = new Proxy({},{ | |
get: (target,name)=>target.hasOwnProperty(name) ? target[name] : 0 | |
}); | |
const valueOf = x=>isNaN(x) ? registers[x] : Number(x); | |
function instruction(x, y) { | |
this.x = x; | |
this.y = y; | |
this.toString = ()=>`${this.constructor.name} ${x} ${y} (${valueOf(x)} ${valueOf(y)})`; | |
} | |
const fn = { | |
set: function(x, y) { | |
instruction.call(this, x, y); | |
this.exec = ()=>{ | |
registers[x] = valueOf(y); | |
this.offset = 1; | |
} | |
}, | |
sub: function(x, y) { | |
instruction.call(this, x, y); | |
this.exec = ()=>{ | |
registers[x] -= valueOf(y); | |
this.offset = 1; | |
} | |
}, | |
mul: function(x, y) { | |
instruction.call(this, x, y); | |
this.exec = ()=>{ | |
registers[x] *= valueOf(y); | |
this.offset = 1; | |
} | |
}, | |
jnz: function(x, y) { | |
instruction.call(this, x, y); | |
this.exec = ()=>{ | |
this.offset = valueOf(x) ? valueOf(y) : 1; | |
} | |
}, | |
} | |
const instructions = input.split("\n").map(function(line) { | |
const words = line.split(" "); | |
return new fn[words[0]](...words.splice(1)); | |
}); | |
let count = 0; | |
for (let i = 0; i >= 0 && i < instructions.length; i += instructions[i].offset) { | |
const instruction = instructions[i]; | |
instruction.exec(); | |
if (instruction.constructor.name === "mul") { | |
++count; | |
} | |
} | |
return count; | |
} | |
function solveYear2017Day24Part1(input) { | |
const components = input.split("\n").map(line=>line.split("/").map(Number)); | |
const queue = [{ | |
port: 0, | |
strength: 0, | |
visited: [] | |
}]; | |
let max = 0; | |
while (queue.length) { | |
const {port, strength, visited} = queue.pop(); | |
components.forEach(function(component, index) { | |
const indexOfPort = component.indexOf(port); | |
if (indexOfPort !== -1 && !visited.includes(index)) { | |
const [startPort,endPort] = component; | |
const bridge = { | |
port: indexOfPort ? startPort : endPort, | |
strength: strength + startPort + endPort, | |
visited: [...visited, index] | |
}; | |
if (bridge.strength > max) { | |
max = bridge.strength; | |
} | |
queue.push(bridge); | |
} | |
}); | |
} | |
return max; | |
} | |
function solveYear2017Day24Part2(input) { | |
const components = input.split("\n").map(line=>line.split("/").map(Number)); | |
const queue = [{ | |
port: 0, | |
strength: 0, | |
visited: [] | |
}]; | |
let maxLength = 0; | |
let maxStrength = 0; | |
while (queue.length) { | |
const {port, strength, visited} = queue.pop(); | |
components.forEach(function(component, index) { | |
const indexOfPort = component.indexOf(port); | |
if (indexOfPort !== -1 && !visited.includes(index)) { | |
const [startPort,endPort] = component; | |
const bridge = { | |
port: indexOfPort ? startPort : endPort, | |
strength: strength + startPort + endPort, | |
visited: [...visited, index] | |
}; | |
if (bridge.visited.length > maxLength) { | |
maxLength = bridge.visited.length; | |
maxStrength = bridge.strength; | |
} else if (bridge.visited.length === maxLength) { | |
if (bridge.strength > maxStrength) { | |
maxStrength = bridge.strength; | |
} | |
} | |
queue.push(bridge); | |
} | |
}); | |
} | |
return maxStrength; | |
} | |
function solveYear2017Day25Part1(input) { | |
const tape = {}; | |
let cursor = 0; | |
let state = "A"; | |
for (let n = 0; n < 12964419; n++) { | |
switch (state) { | |
case "A": | |
if (!tape[cursor]) { | |
tape[cursor] = 1; | |
cursor++; | |
state = "B"; | |
} else { | |
tape[cursor] = 0; | |
cursor++; | |
state = "F"; | |
} | |
break; | |
case "B": | |
if (!tape[cursor]) { | |
tape[cursor] = 0; | |
cursor--; | |
state = "B"; | |
} else { | |
tape[cursor] = 1; | |
cursor--; | |
state = "C"; | |
} | |
break; | |
case "C": | |
if (!tape[cursor]) { | |
tape[cursor] = 1; | |
cursor--; | |
state = "D"; | |
} else { | |
tape[cursor] = 0; | |
cursor++; | |
state = "C"; | |
} | |
break; | |
case "D": | |
if (!tape[cursor]) { | |
tape[cursor] = 1; | |
cursor--; | |
state = "E"; | |
} else { | |
tape[cursor] = 1; | |
cursor++; | |
state = "A"; | |
} | |
break; | |
case "E": | |
if (!tape[cursor]) { | |
tape[cursor] = 1; | |
cursor--; | |
state = "F"; | |
} else { | |
tape[cursor] = 0; | |
cursor--; | |
state = "D"; | |
} | |
break; | |
case "F": | |
if (!tape[cursor]) { | |
tape[cursor] = 1; | |
cursor++; | |
state = "A"; | |
} else { | |
tape[cursor] = 0; | |
cursor--; | |
state = "E"; | |
} | |
break; | |
} | |
} | |
let count = 0; | |
for (const bit in tape) { | |
if (tape[bit]) { | |
count++; | |
} | |
} | |
return count; | |
} | |
function solveYear2018Day1Part1(input) { | |
return eval(input); | |
} | |
function solveYear2018Day1Part2(input) { | |
const changes = input.split("\n").map(Number); | |
let frequency = 0; | |
const seen = new Set([frequency]); | |
while (true) { | |
for (const change of changes) { | |
frequency += change; | |
if (seen.has(frequency)) { | |
return frequency; | |
} else { | |
seen.add(frequency); | |
} | |
} | |
} | |
} | |
function solveYear2018Day2Part1(input) { | |
const lines = input.split("\n"); | |
let twosCount = 0; | |
let threesCount = 0; | |
for (const line of lines) { | |
const map = new Map(); | |
for (const char of line) { | |
const count = map.get(char) || 0; | |
map.set(char, count + 1); | |
} | |
const counts = new Set(map.values()); | |
if (counts.has(2)) { | |
twosCount += 1; | |
} | |
if (counts.has(3)) { | |
threesCount += 1; | |
} | |
} | |
return twosCount * threesCount; | |
} | |
function solveYear2018Day2Part2(input) { | |
const ids = input.split("\n").sort(); | |
function pairwise(iterable) { | |
const iterator = iterable[Symbol.iterator](); | |
return { | |
*[Symbol.iterator]() { | |
let a = iterator.next(); | |
let b = iterator.next(); | |
while (!a.done && !b.done) { | |
yield[a.value, b.value]; | |
a = b; | |
b = iterator.next() | |
} | |
} | |
}; | |
} | |
function findIndexOfSingleDiff(a, b) { | |
let indexOfDiff = -1; | |
for (let i = 0; i < a.length; i++) { | |
if (a[i] !== b[i]) { | |
if (indexOfDiff !== -1) { | |
return -1; | |
} | |
indexOfDiff = i; | |
} | |
} | |
return indexOfDiff; | |
} | |
for (const [a,b] of pairwise(ids)) { | |
const index = findIndexOfSingleDiff(a, b); | |
if (index !== -1) { | |
return `${a.substring(0, index)}${a.substring(index + 1)}` | |
} | |
} | |
} | |
function solveYear2018Day3Part1(input) { | |
const regExp = /^#(\d+) @ (\d+),(\d+): (\d+)x(\d+)$/; | |
const claims = input.split("\n").map(function(line) { | |
const [,id,left,top,width,height] = regExp.exec(line).map(Number); | |
return { | |
id, | |
left, | |
right: left + width - 1, | |
top, | |
bottom: top + height - 1, | |
width, | |
height | |
}; | |
}); | |
const squares = Array.from({ | |
length: 1000 | |
}, function() { | |
return Array(1000); | |
}); | |
let conflicted = 0; | |
for (const {id, left, right, top, bottom} of claims) { | |
for (let x = left; x <= right; x++) { | |
for (let y = top; y <= bottom; y++) { | |
switch (squares[x][y]) { | |
case undefined: | |
squares[x][y] = id; | |
break; | |
case "X": | |
break; | |
default: | |
squares[x][y] = "X"; | |
conflicted++; | |
break; | |
} | |
} | |
} | |
} | |
return conflicted; | |
} | |
function solveYear2018Day3Part2(input) { | |
const regExp = /^#(\d+) @ (\d+),(\d+): (\d+)x(\d+)$/; | |
const claims = input.split("\n").map(function(line) { | |
const [,id,left,top,width,height] = regExp.exec(line).map(Number); | |
return { | |
id, | |
left, | |
right: left + width - 1, | |
top, | |
bottom: top + height - 1, | |
width, | |
height | |
}; | |
}); | |
const squares = Array.from({ | |
length: 1000 | |
}, function() { | |
return Array(1000); | |
}); | |
for (const {id, left, right, top, bottom} of claims) { | |
for (let x = left; x <= right; x++) { | |
for (let y = top; y <= bottom; y++) { | |
switch (squares[x][y]) { | |
case undefined: | |
squares[x][y] = id; | |
break; | |
case "X": | |
break; | |
default: | |
squares[x][y] = "X"; | |
break; | |
} | |
} | |
} | |
} | |
unconflictedClaimSearch: for (const {id, left, right, top, bottom} of claims) { | |
for (let x = left; x <= right; x++) { | |
for (let y = top; y <= bottom; y++) { | |
switch (squares[x][y]) { | |
case 'X': | |
continue unconflictedClaimSearch; | |
} | |
} | |
} | |
return id; | |
} | |
} | |
function solveYear2018Day16Part1(input) { | |
const [samplesInput,testInput] = input.split("\n\n\n\n"); | |
function addr(a, b, c) { | |
this[c] = this[a] + this[b]; | |
} | |
function addi(a, b, c) { | |
this[c] = this[a] + b; | |
} | |
function mulr(a, b, c) { | |
this[c] = this[a] * this[b]; | |
} | |
function muli(a, b, c) { | |
this[c] = this[a] * b; | |
} | |
function banr(a, b, c) { | |
this[c] = this[a] & this[b]; | |
} | |
function bani(a, b, c) { | |
this[c] = this[a] & b; | |
} | |
function borr(a, b, c) { | |
this[c] = this[a] | this[b]; | |
} | |
function bori(a, b, c) { | |
this[c] = this[a] | b; | |
} | |
function setr(a, _, c) { | |
this[c] = this[a]; | |
} | |
function seti(a, _, c) { | |
this[c] = a; | |
} | |
function gtir(a, b, c) { | |
this[c] = a > this[b] ? 1 : 0; | |
} | |
function gtri(a, b, c) { | |
this[c] = this[a] > b ? 1 : 0; | |
} | |
function gtrr(a, b, c) { | |
this[c] = this[a] > this[b] ? 1 : 0; | |
} | |
function eqir(a, b, c) { | |
this[c] = a === this[b] ? 1 : 0; | |
} | |
function eqri(a, b, c) { | |
this[c] = this[a] === b ? 1 : 0; | |
} | |
function eqrr(a, b, c) { | |
this[c] = this[a] === this[b] ? 1 : 0; | |
} | |
const ops = [addr, addi, mulr, muli, banr, bani, borr, bori, setr, seti, gtir, gtri, gtrr, eqir, eqri, eqrr]; | |
let count = 0; | |
for (const sampleInput of samplesInput.split("\n\n")) { | |
const [beforeLine,instructionLine,afterLine] = sampleInput.split("\n"); | |
const registersBefore = JSON.parse(beforeLine.substring("Before: ".length)); | |
const [opcode,a,b,c] = instructionLine.split(" ").map(Number); | |
const registersAfter = JSON.parse(afterLine.substring("After: ".length)); | |
if (ops.filter(function(op) { | |
const registers = registersBefore.slice(); | |
op.call(registers, a, b, c); | |
return registers.toString() === registersAfter.toString(); | |
}).length >= 3) { | |
count++; | |
} | |
} | |
return count; | |
} | |
function solveYear2018Day16Part2(input) { | |
const [samplesInput,testInput] = input.split("\n\n\n\n"); | |
function addr(a, b, c) { | |
this[c] = this[a] + this[b]; | |
} | |
function addi(a, b, c) { | |
this[c] = this[a] + b; | |
} | |
function mulr(a, b, c) { | |
this[c] = this[a] * this[b]; | |
} | |
function muli(a, b, c) { | |
this[c] = this[a] * b; | |
} | |
function banr(a, b, c) { | |
this[c] = this[a] & this[b]; | |
} | |
function bani(a, b, c) { | |
this[c] = this[a] & b; | |
} | |
function borr(a, b, c) { | |
this[c] = this[a] | this[b]; | |
} | |
function bori(a, b, c) { | |
this[c] = this[a] | b; | |
} | |
function setr(a, _, c) { | |
this[c] = this[a]; | |
} | |
function seti(a, _, c) { | |
this[c] = a; | |
} | |
function gtir(a, b, c) { | |
this[c] = a > this[b] ? 1 : 0; | |
} | |
function gtri(a, b, c) { | |
this[c] = this[a] > b ? 1 : 0; | |
} | |
function gtrr(a, b, c) { | |
this[c] = this[a] > this[b] ? 1 : 0; | |
} | |
function eqir(a, b, c) { | |
this[c] = a === this[b] ? 1 : 0; | |
} | |
function eqri(a, b, c) { | |
this[c] = this[a] === b ? 1 : 0; | |
} | |
function eqrr(a, b, c) { | |
this[c] = this[a] === this[b] ? 1 : 0; | |
} | |
const ops = [addr, addi, mulr, muli, banr, bani, borr, bori, setr, seti, gtir, gtri, gtrr, eqir, eqri, eqrr]; | |
const opCandidatesByOpcode = new Map(); | |
for (const sampleInput of samplesInput.split("\n\n")) { | |
const [beforeLine,instructionLine,afterLine] = sampleInput.split("\n"); | |
const registersBefore = JSON.parse(beforeLine.substring("Before: ".length)); | |
const [opcode,a,b,c] = instructionLine.split(" ").map(Number); | |
const registersAfter = JSON.parse(afterLine.substring("After: ".length)); | |
const opCandidates = new Set(ops.filter(function(op) { | |
const registers = registersBefore.slice(); | |
op.call(registers, a, b, c); | |
return registers.toString() === registersAfter.toString(); | |
})); | |
if (opCandidatesByOpcode.has(opcode)) { | |
const existingOpCandidates = opCandidatesByOpcode.get(opcode); | |
for (const existingOpCandidate of existingOpCandidates) { | |
if (!opCandidates.has(existingOpCandidate)) { | |
existingOpCandidates.delete(existingOpCandidate); | |
} | |
} | |
} else { | |
opCandidatesByOpcode.set(opcode, opCandidates); | |
} | |
} | |
const opsByOpcode = new Map(); | |
opsByOpCodeLoading: while (opsByOpcode.size < opCandidatesByOpcode.size) { | |
for (const [opcode,opCandidates] of opCandidatesByOpcode) { | |
if (opCandidates.size === 1) { | |
const op = opCandidates.values().next().value; | |
opsByOpcode.set(opcode, op); | |
for (const opCandidates of opCandidatesByOpcode.values()) { | |
opCandidates.delete(op); | |
} | |
continue opsByOpCodeLoading; | |
} | |
} | |
} | |
const registers = Array(4).fill(0); | |
const instructions = testInput.split("\n").map(line=>line.split(" ").map(Number)); | |
for (const [opcode,a,b,c] of instructions) { | |
const op = opsByOpcode.get(opcode); | |
op.call(registers, a, b, c); | |
} | |
return registers[0]; | |
} | |
function solveYear2018Day19Part1(input) { | |
function addr(a, b, c) { | |
this[c] = this[a] + this[b]; | |
} | |
function addi(a, b, c) { | |
this[c] = this[a] + b; | |
} | |
function mulr(a, b, c) { | |
this[c] = this[a] * this[b]; | |
} | |
function muli(a, b, c) { | |
this[c] = this[a] * b; | |
} | |
function banr(a, b, c) { | |
this[c] = this[a] & this[b]; | |
} | |
function bani(a, b, c) { | |
this[c] = this[a] & b; | |
} | |
function borr(a, b, c) { | |
this[c] = this[a] | this[b]; | |
} | |
function bori(a, b, c) { | |
this[c] = this[a] | b; | |
} | |
function setr(a, _, c) { | |
this[c] = this[a]; | |
} | |
function seti(a, _, c) { | |
this[c] = a; | |
} | |
function gtir(a, b, c) { | |
this[c] = a > this[b] ? 1 : 0; | |
} | |
function gtri(a, b, c) { | |
this[c] = this[a] > b ? 1 : 0; | |
} | |
function gtrr(a, b, c) { | |
this[c] = this[a] > this[b] ? 1 : 0; | |
} | |
function eqir(a, b, c) { | |
this[c] = a === this[b] ? 1 : 0; | |
} | |
function eqri(a, b, c) { | |
this[c] = this[a] === b ? 1 : 0; | |
} | |
function eqrr(a, b, c) { | |
this[c] = this[a] === this[b] ? 1 : 0; | |
} | |
const ops = { | |
addr, | |
addi, | |
mulr, | |
muli, | |
banr, | |
bani, | |
borr, | |
bori, | |
setr, | |
seti, | |
gtir, | |
gtri, | |
gtrr, | |
eqir, | |
eqri, | |
eqrr | |
}; | |
const registers = Array(6).fill(0); | |
const [ipLine,...instructionLines] = input.split("\n"); | |
const ipIndex = Number(ipLine.slice("#ip ".length)); | |
const instructions = instructionLines.map(function(line) { | |
const [opname,...args] = line.split(" "); | |
const op = ops[opname]; | |
const [a,b,c] = args.map(Number); | |
return [op, a, b, c]; | |
}); | |
let ip = registers[ipIndex]; | |
for (let ip = registers[ipIndex]; ip in instructions; ip = ++registers[ipIndex]) { | |
const [op,a,b,c] = instructions[ip]; | |
// const before = `[${registers.join(", ")}]`; | |
op.call(registers, a, b, c); | |
// const after = `[${registers.join(", ")}]`; | |
// console.debug(`ip=${ip} ${before} ${op.name} ${a} ${b} ${c} ${after}`); | |
} | |
return registers[0]; | |
} | |
function solveYear2018Day19Part2(input) { | |
return "https://www.wolframalpha.com/input/?i=sum+of+factors+10551367"; | |
function addr(a, b, c) { | |
this[c] = this[a] + this[b]; | |
} | |
function addi(a, b, c) { | |
this[c] = this[a] + b; | |
} | |
function mulr(a, b, c) { | |
this[c] = this[a] * this[b]; | |
} | |
function muli(a, b, c) { | |
this[c] = this[a] * b; | |
} | |
function banr(a, b, c) { | |
this[c] = this[a] & this[b]; | |
} | |
function bani(a, b, c) { | |
this[c] = this[a] & b; | |
} | |
function borr(a, b, c) { | |
this[c] = this[a] | this[b]; | |
} | |
function bori(a, b, c) { | |
this[c] = this[a] | b; | |
} | |
function setr(a, _, c) { | |
this[c] = this[a]; | |
} | |
function seti(a, _, c) { | |
this[c] = a; | |
} | |
function gtir(a, b, c) { | |
this[c] = a > this[b] ? 1 : 0; | |
} | |
function gtri(a, b, c) { | |
this[c] = this[a] > b ? 1 : 0; | |
} | |
function gtrr(a, b, c) { | |
this[c] = this[a] > this[b] ? 1 : 0; | |
} | |
function eqir(a, b, c) { | |
this[c] = a === this[b] ? 1 : 0; | |
} | |
function eqri(a, b, c) { | |
this[c] = this[a] === b ? 1 : 0; | |
} | |
function eqrr(a, b, c) { | |
this[c] = this[a] === this[b] ? 1 : 0; | |
} | |
const ops = { | |
addr, | |
addi, | |
mulr, | |
muli, | |
banr, | |
bani, | |
borr, | |
bori, | |
setr, | |
seti, | |
gtir, | |
gtri, | |
gtrr, | |
eqir, | |
eqri, | |
eqrr | |
}; | |
const registers = Array(6).fill(0); | |
registers[0] = 1; | |
const [ipLine,...instructionLines] = input.split("\n"); | |
const ipIndex = Number(ipLine.slice("#ip ".length)); | |
const instructions = instructionLines.map(function(line) { | |
const [opname,...args] = line.split(" "); | |
const op = ops[opname]; | |
const [a,b,c] = args.map(Number); | |
return [op, a, b, c]; | |
}); | |
let ip = registers[ipIndex]; | |
for (let ip = registers[ipIndex]; ip in instructions; ip = ++registers[ipIndex]) { | |
const [op,a,b,c] = instructions[ip]; | |
const before = `[${registers.join(", ")}]`; | |
op.call(registers, a, b, c); | |
const after = `[${registers.join(", ")}]`; | |
console.debug(`ip=${ip} ${before} ${op.name} ${a} ${b} ${c} ${after}`); | |
} | |
return registers[0]; | |
} | |
function solveYear2018Day20Part1(input) { | |
class EncodedMap extends Map { | |
constructor(iterable, {stringify: encode, parse: decode}=JSON) { | |
super(iterable); | |
this.encode = encode; | |
this.decode = decode; | |
} | |
entries() { | |
const iterator = super.entries(); | |
return { | |
next() { | |
const {value: [key,value], done} = iterator.next(); | |
return { | |
value: [this.decode(value), value], | |
done | |
}; | |
} | |
} | |
} | |
forEach(callback, thisArg) { | |
return super.forEach((value,key,map)=>callback(this.decode(value), key, map), thisArg); | |
} | |
get(key) { | |
return super.get(this.encode(key)); | |
} | |
has(key) { | |
return super.has(this.encode(key)); | |
} | |
keys() { | |
const iterator = super.keys(); | |
return { | |
next() { | |
const {value: key, done} = iterator.next(); | |
return { | |
value: this.decode(key), | |
done | |
} | |
} | |
} | |
} | |
set(key, value) { | |
return super.set(this.encode(key), value); | |
} | |
} | |
let position = [0, 0]; | |
const distances = new Map([[`${position}`, 0]]); | |
const stack = []; | |
for (const char of input) { | |
switch (char) { | |
case "^": | |
case "$": | |
break; | |
case "(": | |
stack.push(position); | |
break; | |
case "|": | |
position = stack[stack.length - 1]; | |
break; | |
case ")": | |
position = stack.pop(); | |
break; | |
default: | |
{ | |
let[x,y] = position; | |
switch (char) { | |
case "N": | |
y += 1; | |
break; | |
case "S": | |
y -= 1; | |
break; | |
case "E": | |
x += 1; | |
break; | |
case "W": | |
x -= 1; | |
break; | |
} | |
const distanceTraveled = distances.get(`${position}`) + 1; | |
const currentDistance = distances.get(`${[x, y]}`) || Infinity; | |
const distance = Math.min(currentDistance, distanceTraveled); | |
distances.set(`${[x, y]}`, distance); | |
position = [x, y]; | |
} | |
break; | |
} | |
} | |
return Math.max(...distances.values()); | |
} | |
function solveYear2018Day20Part2(input) { | |
let position = [0, 0]; | |
const distances = Object.create(null); | |
distances[position] = 0; | |
const stack = []; | |
for (const char of input) { | |
switch (char) { | |
case "^": | |
case "$": | |
break; | |
case "(": | |
stack.push(position); | |
break; | |
case "|": | |
position = stack[stack.length - 1]; | |
break; | |
case ")": | |
position = stack.pop(); | |
break; | |
default: | |
{ | |
let[x,y] = position; | |
switch (char) { | |
case "N": | |
y += 1; | |
break; | |
case "S": | |
y -= 1; | |
break; | |
case "E": | |
x += 1; | |
break; | |
case "W": | |
x -= 1; | |
break; | |
} | |
distances[[x, y]] = Math.min(distances[[x, y]] || Infinity, distances[position] + 1); | |
position = [x, y]; | |
} | |
break; | |
} | |
} | |
return Object.values(distances).filter(distance=>distance >= 1000).length; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment