Skip to content

Instantly share code, notes, and snippets.

@mfulton26
Last active July 30, 2019 19:44
Show Gist options
  • Save mfulton26/d751b83501161a264c576c0cdadfd33b to your computer and use it in GitHub Desktop.
Save mfulton26/d751b83501161a264c576c0cdadfd33b to your computer and use it in GitHub Desktop.
Advent of Code Solutions
{
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