Skip to content

Instantly share code, notes, and snippets.

@raisanen
Last active January 5, 2018 14:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save raisanen/ee6eadc4ea244ec771e9660bcb8db084 to your computer and use it in GitHub Desktop.
Save raisanen/ee6eadc4ea244ec771e9660bcb8db084 to your computer and use it in GitHub Desktop.
Solutions for Advent of Code 2017 in ES6

Solutions for Advent of Code 2017 in JavaScript (ES6)

Solutions

License

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

const filterAndSum = (str, filter) => {
var arr = str.split('').map((s) => +s);
arr = arr.filter(filter);
return arr.length ? arr.reduce((a, i) => a + i) : 0;
};
// Part 1:
const part1 = (str) => filterAndSum(str, (n, i, arr) => n === arr[(i + 1) % arr.length]);
// Part 2:
const part2 = (str) => filterAndSum(str, (n, i, arr) => n === arr[(i + (arr.length/2)) % arr.length]);
// Part 1:
const checksum = (str) => {
let result = 0;
str.split(/\n+/g).forEach((l) => {
let nums = l.split(/\s+/g).map((s) => +s.replace(/^\s+|\s+$/g, ''));
let max = nums.reduce((a, n) => Math.max(a, n));
let min = nums.reduce((a, n) => Math.min(a, n));
result += max - min;
});
return result;
};
// Part 2:
const checksum2 = (str) => {
let result = 0;
str.split(/\n+/g).forEach((l) => {
let nums = l.split(/\s+/g).map((s) => +s).sort((a,b) => b-a);
let divRes = 0;
for (let i = 0; i < nums.length - 1; i++) {
for (let j = i + 1; j < nums.length; j++) {
if (nums[i] % nums[j] === 0) {
divRes = nums[i] / nums[j];
break;
}
}
}
result += divRes;
});
return result;
};
const delta = (n) => {
let deltaXY = {x: 0, y: 0},
ceil_root = Math.ceil(Math.sqrt(n));
if (ceil_root % 2 === 0) {
if (n <= (Math.pow(ceil_root, 2) - ceil_root)) {
deltaXY.x = 1;
} else {
deltaXY.y = 1;
}
} else {
if (n <= Math.pow(ceil_root, 2) && n > Math.pow(ceil_root, 2) - ceil_root) {
deltaXY.y = -1;
} else {
deltaXY.x = -1;
}
}
return deltaXY;
};
const part1 = (lim) => {
let x = 0, y = 0;
let res = [''];
for (let i = 1; i <= lim; i++) {
res[i] = {x: x, y: y};
let deltaXY = delta(i);
x += deltaXY.x;
y += deltaXY.y;
}
console.log(`Distance from 1 to ${lim}:`, Math.abs(res[lim].x) + Math.abs(res[lim].y));
};
const part2 = (lim) => {
let x = 0, y = 0;
let grid = [[1]];
for (let i = 1; ; i++) {
if (typeof grid[x] === 'undefined') {
grid[x] = [];
}
grid[x][y] = (() => {
let adjSum = 0;
for (let dx = x-1; dx <= x+1; dx++) {
for (let dy = y-1; dy <= y+1; dy++) {
if (typeof grid[dx] !== 'undefined' && typeof grid[dx][dy] !== 'undefined') {
adjSum += grid[dx][dy];
}
}
}
return adjSum;
})();
if (grid[x][y] >= lim) {
console.log(`First over ${lim}: ${grid[x][y]}`);
console.log(`(iterations: ${i})`);
break;
}
let deltaXY = delta(i);
x += deltaXY.x;
y += deltaXY.y;
}
};
const tsv2lol = (input) => {
return input.split(/\n+/g).map((line) => line.split(/\s+/g));
};
// Part1:
const part1 = (passwords) => {
let lines = tsv2lol(passwords);
return lines.filter((l) => {
let seen = {};
let uniq = l.filter((s) => {
if (typeof seen[s] === 'undefined') {
seen[s] = true;
return true;
}
return false;
});
return uniq.length === l.length;
}).length;
};
// Part2:
const part2 = (passwords) => {
let lines = tsv2lol(passwords);
return lines.filter((l) => {
let seen = {};
let uniq = l.filter((s) => {
let skey = s.split('').sort().join('');
if (typeof seen[skey] === 'undefined') {
seen[skey] = true;
return true;
}
return false;
});
return uniq.length === l.length;
}).length;;
};
const Day05 = {
Part1: (input) => {
let memArr = input.split(/\s+/).map((s) => +s);
for (let ptr = 0, step = 1; ; step++) {
ptr += memArr[ptr]++;
if (ptr < 0 || ptr >= memArr.length) {
return step;
}
}
},
Part2: (input) => {
let memArr = input.split(/\s+/).map((s) => +s);
for (let ptr = 0, step = 1; ; step++) {
ptr += memArr[ptr] >= 3 ? memArr[ptr]-- : memArr[ptr]++;
if (ptr < 0 || ptr >= memArr.length) {
return step;
}
}
}
};
Array.prototype.mkKey = function () {
return this.join('_');
};
Array.prototype.indexOfMaxValue = function () {
return this.reduce((mx, x, i, arr) => x > arr[mx] ? i : mx, 0);
};
String.prototype.toIntArray = function () {
return this.split(/\s+/).map((s) => +s);
};
const Day06 = {
FindPeriod: (input, checkCallback) => {
let inputArr = input.toIntArray();
for(let cycle = 1, seen = {}; ; cycle++) {
let maxInd = inputArr.indexOfMaxValue();
blocks = inputArr[maxInd];
seen[inputArr.mkKey()] = cycle;
inputArr[maxInd] = 0;
for (let ptr = (maxInd+1) % inputArr.length; blocks > 0; blocks--) {
inputArr[ptr]++;
ptr = (ptr + 1) % inputArr.length;
}
let res = checkCallback(inputArr, seen, cycle);
if (res !== false) {
return res;
}
}
return 0;
},
Part1: (input) => {
return Day06.FindPeriod(input, (arr, seen, cycle) => {
if (seen[arr.mkKey()]) {
return cycle;
}
return false;
});
},
Part2: (input) => {
return Day06.FindPeriod(input, (arr, seen, cycle) => {
if (typeof seen[arr.mkKey()] !== 'undefined') {
return (cycle + 1) - seen[arr.mkKey()];
}
return false;
});
}
};
const Day07 = {
parseList: (input) => {
let rows = input.split(/\n+/),
output = [];
for (let i = 0; i < rows.length; i++) {
let matches = rows[i].match(/^([a-z]+) \((\d+)\)/);
let disc = {
name: matches[1],
weight: +matches[2]
}
if (rows[i].match(/->/)) {
disc.children = rows[i].match(/-> (.*)/)[1].split(/,\s+/);
}
output.push(disc);
}
return output;
},
findRoot: (tower, currDisc=null) => {
currDisc = currDisc || tower[0];
for (let i = 0; i < tower.length; i++) {
if (tower[i].children && tower[i].children.indexOf(currDisc.name) >= 0) {
return Day07.findRoot(tower, tower[i]);
}
}
return currDisc;
},
findParent: (disc, tower) => {
for (let i = 0; i < tower.length; i++) {
if (tower[i].children && tower[i].children.indexOf(disc.name) >= 0) {
return tower[i];
}
}
return disc;
},
findDisc: (name, tower) => {
return (tower.filter((d) => d.name === name) || [{}])[0];
},
setTotalWeights: (disc, tower) => {
disc.totalWeight = disc.weight;
if (disc.children) {
for (let i = 0; i < disc.children.length; i++) {
let child = Day07.findDisc(disc.children[i], tower);
child.totalWeight = Day07.setTotalWeights(child, tower);
disc.totalWeight += child.totalWeight;
}
}
return disc.totalWeight;
},
findUnbalancedChild: (root, tower) => {
let children = (root.children || []).map((n) => Day07.findDisc(n, tower)),
maxWeight = children.reduce((a, c) => Math.max(a, c.totalWeight), 0),
minWeight = children.reduce((a, c) => Math.min(a, c.totalWeight), 0xffffffff),
withMax = children.filter((c) => c.totalWeight === maxWeight),
withMin = children.filter((c) => c.totalWeight === minWeight);
if (withMax.length === withMin.length) {
return root;
}
let unbalanced = (withMax.length === 1 ? withMax : withMin)[0];
return Day07.findUnbalancedChild(unbalanced, tower);
},
Part1: (input) => {
return Day07.findRoot(Day07.parseList(input)).name;
},
Part2: (input) => {
let tower = Day07.parseList(input),
root = Day07.findRoot(tower);
Day07.setTotalWeights(root, tower);
let unbalanced = Day07.findUnbalancedChild(root, tower),
parentOfUnbalanced = Day07.findParent(unbalanced, tower),
firstSibling = parentOfUnbalanced.children
.map((n) => Day07.findDisc(n, tower))
.filter((c) => c.totalWeight !== unbalanced.totalWeight)[0],
neededWeight = unbalanced.weight - (unbalanced.totalWeight - firstSibling.totalWeight);
return neededWeight;
}
};
const day8 = (input) => {
const registers = {};
const instructions = input.split(/\n/).map((l) => l.split(/\s+/));
const checks = {
'>': (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 insts = {
'inc': (reg, value) => registers[reg] += value,
'dec': (reg, value) => registers[reg] -= value
};
let maxEver = -1;
const getorupdate = (reg, inst=null, value=0) => {
if (typeof registers[reg] === 'undefined') {
registers[reg] = 0;
}
if (inst !== null) {
insts[inst](reg, value);
}
if (registers[reg] > maxEver) {
maxEver = registers[reg];
}
return registers[reg];
};
instructions.forEach((l) => {
let [regToUpdate, inst, val, dummy, regToCheck, check, valueToCheck] = l,
regToCheckValue = getorupdate(regToCheck);
val = parseInt(val);
valueToCheck = parseInt(valueToCheck);
if (typeof checks[check] !== 'undefined' && checks[check](regToCheckValue, valueToCheck)){
getorupdate(regToUpdate, inst, val);
}
});
console.log('A:', Object.values(registers).reduce((a, c) => Math.max(a,c)), 'B:', maxEver);
};
const day9 = (input) => {
const chars = input.split('');
let groupN = 0,
score = 0,
layer = 0,
inGarbage = false,
inEscape = false,
numGarbage = 0;
for (let i = 0; i < chars.length; i++) {
if (!inEscape) {
if (chars[i] === '!') {
inEscape = true;
} else if (!inGarbage) {
if (chars[i] === '{') {
groupN++;
layer++;
score += layer;
} else if (chars[i] === '}') {
layer--;
} else if (chars[i] === '<') {
inGarbage = true;
}
} else if (chars[i] === '>') {
inGarbage = false;
} else {
numGarbage++;
}
} else {
inEscape = false;
}
}
console.log('A:', score, ', B:', numGarbage);
};
Array.prototype.reverseSegment = function (startIdx, length) {
let endIdx = startIdx + length,
subarr = this.slice(startIdx, endIdx <= this.length ? endIdx : this.length),
firstSubLength = subarr.length;
if (endIdx > this.length) {
subarr = subarr.concat(this.slice(0, length - firstSubLength));
}
subarr = subarr.reverse();
for (let i = startIdx, j = 0; i < endIdx; i++, j++) {
this[i % this.length] = subarr[j];
}
return this;
};
const createList = (len) => Array.apply(null, {length: len}).map(Function.call, Number);
const part1 = (len, input) => {
let list = createList(len),
inp = input.split(/,\s*/).map(Number),
skip = 0,
pos = 0;
inp.forEach((n) => {
list.reverseSegment(pos, n);
pos = (pos + n + skip++) % list.length;
});
return list[0] * list[1];
};
const part2 = (input) => {
let list = createList(256),
inp = input.split('').map((c) => c.charCodeAt(0)).concat([17, 31, 73, 47, 23]),
skip = 0,
pos = 0;
for (let i = 0; i < 64; i++) {
inp.forEach((n) => {
list.reverseSegment(pos, n);
pos = (pos + n + skip) % list.length;
skip++;
});
}
let dense = [];
for (let i = 0; i < 256; i += 16) {
dense.push(list.slice(i, i + 16).reduce((a, c) => c ^ a));
}
return dense.map((d) => {
let h = d.toString(16);
return (h.length === 1 ? '0' : '') + h;
}).join('');
};
const day11 = (input) => {
let path = input.split(/,/),
start = [0, 0, 0],
maxDistance = 0;
const directions = {
'n': [ 0, 1, -1],
'nw': [-1, 1, 0],
'ne': [ 1, 0, -1],
's': [ 0, -1, 1],
'sw': [-1, 0, 1],
'se': [ 1, -1, 0]
};
const move = (a, dist) => a.map((n, i) => n + dist[i]);
const dist = (s) => s.map(Math.abs).reduce((a, c) => a + c) / 2;
path.forEach((dir) => {
start = move(start, directions[dir]);
let currDistance = dist(start);
if (currDistance > maxDistance) {
maxDistance = currDistance;
}
});
console.log('A:', dist(start));
console.log('B:', maxDistance);
}
const part1 = (input) => {
let connections = {};
let rows = input.split(/\n+/).forEach(r => {
let [p, cons] = r.split(/\s+<->\s+/);
connections[p] = cons.split(/,\s+/).map(n => n);
});
let seen = [];
const findNeighbours = (p) => {
if (seen.indexOf(p) < 0) {
seen.push(p);
}
connections[p].forEach(c => {
if (seen.indexOf(c) < 0){
findNeighbours(c);
}
});
}
findNeighbours('0');
console.log('A:', seen.length);
};
const part2 = (input) => {
let connections = {};
let rows = input.split(/\n+/).forEach(r => {
let [p, cons] = r.split(/\s+<->\s+/);
connections[p] = cons.split(/,\s+/).map(n => n);
});
let groups = {};
const findNeighbours = (g, p) => {
if (groups[g].indexOf(p) < 0) {
groups[g].push(p);
}
connections[p].forEach(c => {
if (groups[g].indexOf(c) < 0){
findNeighbours(g, c);
}
});
}
for (var k in connections) {
let alreadyGrouped = Object.values(groups).filter(a => a.indexOf(k) >= 0).length;
if (!alreadyGrouped) {
groups[k] = [];
findNeighbours(k, k);
}
}
console.log('B:', Object.values(groups).length);
};
const part1 = (input) => {
let fireWall = {},
severity = 0;
input.split(/\n+/).forEach(l => {
let [k, r] = l.split(/:\s+/).map(Number);
fireWall[k] = {range: r, pos: 0, dir: 1};
maxLayer = k;
});
const tick = () => {
for (let k in fireWall) {
if (fireWall.hasOwnProperty(k)) {
if (fireWall[k].pos === 0) {
fireWall[k].dir = 1;
} else if (fireWall[k].pos === fireWall[k].range - 1) {
fireWall[k].dir = -1;
}
fireWall[k].pos += fireWall[k].dir;
}
}
};
for (let pos = 0; pos <= maxLayer; pos++) {
if (fireWall[pos] && fireWall[pos].pos === 0) {
severity += pos * fireWall[pos].range;
}
tick();
}
console.log('Severity:', severity);
};
const part2 = (input) => {
const fireWall = input.split(/\n+/).map(l => l.split(/:\s+/).map(Number));
const isCaught = (delay, [layer, range]) => (delay + layer) % (2 * (range - 1)) === 0;
for (let delay = 0; ; delay++) {
let anyCaught = false;
for (let i = 0; i < fireWall.length; i++) {
if (isCaught(delay, fireWall[i])) {
anyCaught = true;
break;
}
}
if (!anyCaught) {
console.log('Min delay:', delay);
break;
}
}
};
Array.prototype.reverseSegment = function (startIdx, length) {
let endIdx = startIdx + length,
subarr = this.slice(startIdx, endIdx <= this.length ? endIdx : this.length),
firstSubLength = subarr.length;
if (endIdx > this.length) {
subarr = subarr.concat(this.slice(0, length - firstSubLength));
}
subarr = subarr.reverse();
for (let i = startIdx, j = 0; i < endIdx; i++, j++) {
this[i % this.length] = subarr[j];
}
return this;
};
Array.prototype.unique = function () { return [...new Set(this)]; };
Array.prototype.numUnique = function () { return this.unique().length; };
const createList = (len) => Array.apply(null, {length: len}).map(Function.call, Number);
const zeroPad4 = (input) => ('000' + input).slice(-4);
const zeroPad2 = (input) => ('0' + input).slice(-2);
const knottedHash = (input) => {
let list = createList(256),
inp = input.split('').map((c) => c.charCodeAt(0)).concat([17, 31, 73, 47, 23]),
skip = 0,
pos = 0;
for (let i = 0; i < 64; i++) {
inp.forEach((n) => {
list.reverseSegment(pos, n);
pos = (pos + n + skip) % list.length;
skip++;
});
}
let dense = '';
for (let i = 0; i < 256; i += 16) {
dense += zeroPad2(list.slice(i, i + 16).reduce((a, c) => c ^ a).toString(16));
}
return dense;
};
const part1 = (input) => {
let rows = [],
used = 0;
for (let i = 0; i < 128; i++) {
let hash = knottedHash(`${input}-${i}`).split('')
.map(h => zeroPad4(parseInt(h, 16).toString(2)))
.join('');
rows.push(hash);
used += hash.match(/1/g).length;
}
console.log('A:', used);
};
const part2 = (input) => {
let table = [],
regions = {};
for (let i = 0; i < 128; i++) {
let cols = knottedHash(`${input}-${i}`).split('')
.map(h => zeroPad4(parseInt(h, 16).toString(2)))
.join('')
.split('');
table.push(cols);
}
const mkKey = (a, b) => `${a}:${b}`,
numRows = table.length,
numCols = table[0].length;
const findNeighbours = (region, row, col) => {
const find = (r) => (rw, cl) => {
let vkey = mkKey(rw, cl);
if (rw < numRows && rw >= 0 && cl < numCols && cl >= 0
&& typeof regions[vkey] === 'undefined'
&& table[rw][cl] !== '0'
) {
regions[vkey] = r;
findNeighbours(r, rw, cl);
}
};
[[row+1, col], [row, col+1], [row-1, col], [row, col-1]]
.forEach(([rr, cc]) => find(region)(rr, cc));
};
for (let row = 0, lastRegionFound = 0; row < numRows; row++) {
for (let col = 0; col < numCols; col++) {
let vkey = mkKey(row, col);
if (typeof regions[vkey] === 'undefined' && table[row][col] !== '0') {
regions[vkey] = ++lastRegionFound;
findNeighbours(lastRegionFound, row, col);
}
}
}
console.log('B:', Object.values(regions).numUnique());
};
const factorA = 16807,
factorB = 48271,
mod = 2147483647,
mask = 0xffff,
next = (cur, factor, m) => (cur = (cur * factor % mod)) % m === 0 ? cur : next(cur, factor, m),
match = (a, b) => (a & mask) === (b & mask);
const findMatches = (startA, startB, modA=1, modB=1, lim=5e6) => {
let currA = startA,
currB = startB,
matchCount = 0;
for (let i = 0; i < lim; i++) {
currA = next(currA, factorA, modA);
currB = next(currB, factorB, modB);
if (match(currA, currB)) {
matchCount++;
}
}
return matchCount;
}
const part1 = (startA, startB) => console.log('A:', findMatches(startA, startB, 1, 1, 40e6));
const part2 = (startA, startB) => console.log('B:', findMatches(startA, startB, 4, 8, 5e6));
const part1 = (input, config='abcdefghijklmnop') => {
let programs = config.split(''); //
const dance = input.split(',');
const moves = {
's': a => {
let n = +a;
programs = programs.slice(-n).concat(programs.slice(0, programs.length - n));
},
'x': (a, b) => {
let [n1, n2] = [+a, +b];
let t = programs[n1];
programs[n1] = programs[n2];
programs[n2] = t;
},
'p': (a, b) => {
moves.x(programs.indexOf(a), programs.indexOf(b));
}
}
for (let i = 0; i < dance.length; i++) {
let [d, mov, a, b] = dance[i].match(/([sxp])(\w+)\/?(\w+)?/);
moves[mov](a, b);
}
return programs.join('');
};
const findPeriod = (input) => {
const starting = 'abcdefghijklmnop';
let newperm = starting;
for (let i = 1; ; i++) {
newperm = part1(input, newperm);
if (newperm === starting) {
return i;
}
}
};
const part2 = (input) => {
const starting = 'abcdefghijklmnop';
let period = findPeriod(input),
realN = 1e9 % period,
newperm = starting;
for (let i = 0; i < realN; i++) {
newperm = part1(input, newperm);
}
return newperm;
};
const part1 = (stepSize=3) => {
let mem = [0], n = 0;
for (let i = 1; i <= 2017; i++) {
let insertAt = (n) % mem.length;
mem.splice(insertAt + 1, 0, i);
n = mem.indexOf(i) + stepSize;
}
console.log('A:', mem[(n - stepSize + 1) % mem.length]);
};
const part2 = (stepSize) => {
let mem = [0], n = 0, lastA = 0;
for (let i = 1; i <= 5e7; i++) {
let insertAt = (n) % i;
n = (insertAt + 1 + stepSize);
if (insertAt + 1 === 1) {
lastA = i;
}
}
console.log('B:', 5e7, lastA);
}
const part1 = (input) => {
let registers = {},
lastSound = 0,
ptr = 0,
i = 0;
const code = input.split(/\n+/).map(l => l.split(/\s+/));
const regorn = (x) => {
return x.match && x.match(/^[a-z]$/) ? getreg(x) : +x;
};
const getreg = (r) => {
if (typeof registers[r] === 'undefined') {
registers[r] = 0;
}
return registers[r];
};
const setreg = (r, v) => registers[r] = regorn(v);
const ops = {
'snd': (x) => lastSound = regorn(x),
'set': (r, x) => setreg(r, x),
'add': (r, x) => setreg(r, getreg(r) + regorn(x)),
'mul': (r, x) => setreg(r, getreg(r) * regorn(x)),
'mod': (r, x) => setreg(r, getreg(r) % regorn(x)),
'rcv': (r) => getreg(r),
'jgz': (r, y) => {
if (getreg(r) > 0) {
ptr += regorn(y);
} else {
ptr++;
}
}
};
for (ptr = 0; ptr < code.length && i < 1e5; i++) {
let op = code[ptr],
res = ops[op[0]](op[1], op[2]);
if (op[0] === 'rcv' && res !== 0) {
console.log('A:', lastSound);
return;
}
if (op[0] !== 'jgz') {
ptr++;
}
}
};
class Prg {
registers = {}
ptr = 0
queue = []
code = []
id = 0
sent = 0
sibling = 0
constructor(id, input) {
this.id = id;
this.code = input.split(/\n+/).map(l => l.trim().split(/\s+/));
}
setSibling(sibling) {
this.sibling = sibling;
}
isStalled() {
return this.code[this.ptr][0] === 'rcv' && this.queue.length <= 0;
}
isDone() {
return this.ptr >= this.code.length - 1;
}
isStalledOrDone() {
return this.isDone() || this.isStalled();
}
step() {
const regorn = (x) => {
return x.match && x.match(/^[a-z]$/) ? getreg(x) : +x;
};
const getreg = (r) => {
if (typeof this.registers[r] === 'undefined') {
this.registers[r] = r === 'p' ? this.id : 0;
}
return this.registers[r];
};
const setreg = (r, v) => this.registers[r] = regorn(v);
const ops = {
'snd': (x) => {
this.sibling.queue.push(regorn(x));
this.ptr++
this.sent++;
},
'set': (r, x) => { setreg(r, x); this.ptr++ },
'add': (r, x) => { setreg(r, getreg(r) + regorn(x)); this.ptr++ },
'mul': (r, x) => { setreg(r, getreg(r) * regorn(x)); this.ptr++ },
'mod': (r, x) => { setreg(r, getreg(r) % regorn(x)); this.ptr++ },
'rcv': (r) => {
if (this.queue.length > 0) {
this.registers[r] = this.queue.shift();
this.ptr++
}
},
'jgz': (r, y) => {
if (regorn(r) > 0) {
this.ptr += regorn(y);
} else {
this.ptr++;
}
}
}
ops[this.code[this.ptr][0]](this.code[this.ptr][1], this.code[this.ptr][2]);
}
}
const part2 = (input) => {
const programs = [new Prg(0, input), new Prg(1, input)];
programs[0].setSibling(programs[1]);
programs[1].setSibling(programs[0]);
do {
programs.forEach(p => {
if (!p.isDone()) {
p.step();
}
})
} while (!programs.reduce((a, b) => a && b.isStalledOrDone(), true));
console.log('B:', programs[1].sent);
};
const day19 = (input) => {
const maze = input.split(/\n+/).map(l => l.split(''));
let pos = {r: 0, c: maze[0].indexOf('|')},
found = '',
dir = {r: 1, c: 0},
steps = -1;
for (; pos.r >= 0 && pos.r < maze.length && pos.c >= 0 && pos.c < maze[pos.r].length; steps++) {
let curCell = maze[pos.r][pos.c];
if (curCell === '+') {
if (dir.r === 0) {
if (pos.r > 0 && maze[pos.r - 1][pos.c].match(/[A-Z\|]/)) {
dir = { r: -1, c: 0};
} else if (pos.r < maze.length && maze[pos.r + 1][pos.c].match(/[A-Z\|]/)) {
dir = { r: +1, c: 0};
}
} else {
if (pos.c > 0 && maze[pos.r][pos.c - 1].match(/[A-Z\-]/)) {
dir = { r: 0, c: -1};
} else if (pos.c < maze[pos.r].length && maze[pos.r][pos.c + 1].match(/[A-Z\-]/)) {
dir = { r: 0, c: 1};
}
}
} else if (curCell.match(/[A-Z]/)) {
found += curCell;
}
pos = {r: pos.r + dir.r, c: pos.c + dir.c};
}
console.log('A:', found, 'B:', steps);
}
class Particle {
pos = []
vel = []
acc = []
id = -1
constructor(line, id) {
const parseXYZ = (s) => s.match(/<([^,]+),([^,]+),([^>]+)>/).slice(1).map(Number);
[this.pos, this.vel, this.acc] = line.split(/,\s+/).map(parseXYZ);
this.id = id
}
isSame(b) {
return this.pos[0] === b.pos[0] && this.pos[1] === b.pos[1] && this.pos[2] === b.pos[2];
}
dist() {
return this.pos.reduce((a, c) => Math.abs(a) + Math.abs(c), 0);
}
tick() {
const upd = deltas => (el, idx) => el + deltas[idx];
this.vel = this.vel.map(upd(this.acc))
this.pos = this.pos.map(upd(this.vel));
}
}
const THRESHOLD = 1000; // How many iterations to wait for answer to change
const part1 = (input) => {
let particles = input.split(/\n+/).map(l => new Particle(l)),
lastMinIndex = -1;
const tick = () => particles.forEach(p => p.tick());
for (let ticksSinceMinChanged = 0; ticksSinceMinChanged < THRESHOLD; ticksSinceMinChanged++) {
let distances = particles.map(p => p.dist()),
currMinIndex = distances.indexOf(Math.min(...distances));
if (currMinIndex !== lastMinIndex) {
lastMinIndex = currMinIndex;
ticksSinceMinChanged = 0;
}
tick();
}
console.log('A:', lastMinIndex);
};
const part2 = (input) => {
let particles = input.split(/\n+/).map((l, i) => new Particle(l, i));
const tick = () => particles.forEach(p => p.tick());
for (let ticksSinceCollision = 0; ticksSinceCollision < THRESHOLD; ticksSinceCollision++) {
let remove = [];
particles.forEach(p => {
let cols = particles.filter(b => b.isSame(p) && b.id !== p.id).map(o => o.id);
if (cols.length > 0) {
remove = remove.concat(cols);
remove.push(p.id);
}
});
if (remove.length > 0) {
ticksSinceCollision = 0;
particles = particles.filter(p => remove.indexOf(p.id) === -1);
}
tick();
}
console.log('B:', particles.length);
};
const start = `.#./..#/###`;
const testInput = `../.# => ##./#../...
.#./..#/### => #..#/..../..../#..#`;
const parse = inp => inp.split('/');
const print = (...inp) => inp.forEach(i => i.split('/').forEach(l => console.log(l)));
const rotate = inp => {
let lines = parse(inp).map(l => l.split('')),
output = [],
len = lines.length;
for (let i = 0; i < len; i++) {
for (let j = 0; j < len; j++) {
if (!output[j]) {
output[j] = [];
}
output[j].push(lines[i][j]);
}
}
return output.map(l => l.join('')).join('/');
};
const flipHoriz = inp => inp.split('').reverse().join('');
const flipVert = inp => parse(inp).reverse().join('/');
const processGrid = (rules, numIt) => {
let grid = ['.#.','..#','###'];
const split = () => {
let len = grid.length,
num = len % 2 == 0 ? 2 : 3,
subgrids = [];
for (let i = 0; i < len; i += num) {
for(let j = 0; j < len; j += num) {
let str = '';
for(var k = 0; k < num; k++) {
str += grid[i+k].substring(j, j+num) + '/';
}
subgrids.push(str.substr(0, str.length-1));
}
}
return subgrids;
};
const transform = (inp) => {
let newA = inp;
for (let i = 0; i <= 4; i++) {
if (rules.hasOwnProperty(newA)) {
return rules[newA];
}
newA = flipHoriz(newA);
if (rules.hasOwnProperty(newA)) {
return rules[newA];
}
newA = flipVert(newA);
if (rules.hasOwnProperty(newA)) {
return rules[newA];
}
newA = rotate(newA);
}
return inp;
};
const join = (arr) => {
let newGrid = [],
num = Math.sqrt(arr.length),
strlen = arr[0].match(/\//g).length + 1;
for (let i = 0; i < arr.length; i += num) {
for (let j = 0; j < strlen; j++) {
let str = '';
for(let k = 0; k < num; k++) {
str += arr[i+k].split('/')[j];
}
newGrid.push(str);
}
}
return newGrid;
};
for (let i = 0; i < numIt; i++) {
grid = join(split().map(s => transform(s)));
}
return grid;
};
const solve = (inp) => {
const rules = {};
inp.split(/\n+/).forEach(l => {
let [rule, sub] = l.split('=>').map(s => s.trim());
rules[rule] = sub;
});
console.log('A:', processGrid(rules, 5).join('').replace(/[^#]/g, '').length);
console.log('B:', processGrid(rules, 18).join('').replace(/[^#]/g, '').length);
};
solve(testInput);
const part1 = (inp, numBursts) => {
let grid = inp.split(/\n+/).map(l => l.split('')),
numInfections = 0,
y = Math.floor(grid.length / 2),
x = Math.floor(grid[y].length / 2),
dir = 'n';
console.log(x, y);
const turn = (left, currDir) => {
switch (currDir) {
case 'n': return left ? [x - 1, y, 'w'] : [x + 1, y, 'e'];
case 's': return left ? [x + 1, y, 'e'] : [x - 1, y, 'w'];
case 'w': return left ? [x, y + 1, 's'] : [x, y - 1, 'n'];
case 'e': return left ? [x, y - 1, 'n'] : [x, y + 1, 's'];
}
};
for (let i = 0; i < numBursts; i++) {
if (typeof grid[y] === 'undefined') {
grid[y] = [];
}
if (typeof grid[y][x] === 'undefined') {
grid[y][x] = '.';
}
let wasClean = grid[y][x] === '.';
grid[y][x] = wasClean ? '#' : '.';
numInfections += wasClean ? 1 : 0;
[x, y, dir] = turn(wasClean, dir);
}
console.log('A:', numInfections);
};
const part2 = (inp, numBursts) => {
let grid = inp.split(/\n+/).map(l => l.split('')),
numInfections = 0,
y = Math.floor(grid.length / 2),
x = Math.floor(grid[y].length / 2),
dir = 'n',
rules = {
'.n': () => [x - 1, y, 'w'],
'.s': () => [x + 1, y, 'e'],
'.e': () => [x, y - 1, 'n'],
'.w': () => [x, y + 1, 's'],
'#n': () => [x + 1, y, 'e'],
'#s': () => [x - 1, y, 'w'],
'#e': () => [x, y + 1, 's'],
'#w': () => [x, y - 1, 'n'],
'wn': () => [x, y - 1, 'n'],
'ws': () => [x, y + 1, 's'],
'ww': () => [x - 1, y, 'w'],
'we': () => [x + 1, y, 'e'],
'fn': () => [x, y + 1, 's'],
'fs': () => [x, y - 1, 'n'],
'fw': () => [x + 1, y, 'e'],
'fe': () => [x - 1, y, 'w']
};
for (let i = 0; i < numBursts; i++) {
if (typeof grid[y] === 'undefined') {
grid[y] = [];
}
if (typeof grid[y][x] === 'undefined') {
grid[y][x] = '.';
}
let prevState = grid[y][x];
switch (prevState) {
case '.': grid[y][x] = 'w'; break;
case 'w': grid[y][x] = '#'; numInfections++; break;
case '#': grid[y][x] = 'f'; break;
case 'f': grid[y][x] = '.'; break;
}
[x, y, dir] = rules[prevState + dir]();
}
console.log('B:', numInfections);
};
const part1 = (code) => {
const instructions = code.split(/\n+/).map(l => l.split(/\s+/));
let registers = {},
ptr = 0,
numInst = {};
const getOp = (op) => {
if (op.match(/[a-h]/)) {
if (typeof registers[op] === 'undefined') {
registers[op] = 0;
}
return registers[op];
} else {
return +op;
}
};
const instInvoked = (inst) => {
if (typeof numInst[inst] === 'undefined') {
numInst[inst] = 0;
}
numInst[inst]++;
}
const handleInst = ([inst, opA, opB]) => {
const a = getOp(opA),
b = getOp(opB);
instInvoked(inst);
console.log(`${inst} ${opA} (${a}) ${opB} (${b})`);
switch (inst) {
case 'set': registers[opA] = b; break;
case 'sub': registers[opA] -= b; break;
case 'mul': registers[opA] *= b; break;
case 'jnz':
if (a !== 0) {
ptr--;
ptr += b;
}
break;
}
};
for(let i = 0; ptr < instructions.length; i++) {
handleInst(instructions[ptr]);
ptr++;
}
console.log('A:', numInst.mul);
};
const part2 = () => {
let a=1,d=0,e=0,f=0,g=0,h=0,
b = (79 * 100) + 100000,
c = b + 17000;
do {
f = 1;
e = 2;
for (d = 2; d * d <= b; d++) {
if (b % d === 0) {
f = 0;
break;
}
}
if (f == 0) {
h++;
}
g = b - c;
b += 17;
} while (g != 0);
console.log('B:', h);
};
const parseComponent = a => a.split('/').map(n => +n);
const solve = (inp) => {
let components = inp.split(/\n+/).map(l => {
let [a, b] = parseComponent(l);
return [a, b, l];
}),
starts = components.filter(c => c[0] === 0 || c[1] === 0),
found = [];
const findNext = (curr, used, lastMatch = 0) => {
let match = curr[0] === lastMatch ? curr[1] : curr[0],
next = components.filter(c => (c[0] === match || c[1] === match) && used.indexOf(c[2]) < 0),
currBridge = {bridge: used.join('--'), score: parseComponent(used.join('/')).reduce((a,c) => a+c)};
found.push(currBridge);
next.forEach(n => findNext(n, used.concat(n[2]), match))
};
starts.forEach(s => findNext(s, [s[2]], 0));
/// A:
console.log('A:', found.sort((a,b) => b.score - a.score)[0]);
/// B:
let longestLength = found.map(b => b.bridge.split('/').length)
.sort((a,b) => b - a)[0],
strongestLongest = found.filter(f => f.bridge.split('/').length === longestLength).sort((a, b) => b.score - a.score)[0];
console.log('B:', strongestLongest);
};
const solve = (numSteps) => {
let tape = [],
currState = 'A',
cursor = 0;
const transitions = {
A: {val: [1, 0], state: ['B', 'C'], cursor: [1, -1]},
B: {val: [1, 1], state: ['A', 'D'], cursor: [-1, 1]},
C: {val: [0, 0], state: ['B', 'E'], cursor: [-1, -1]},
D: {val: [1, 0], state: ['A', 'B'], cursor: [1, 1]},
E: {val: [1, 1], state: ['F', 'C'], cursor: [-1, -1]},
F: {val: [1, 1], state: ['D', 'A'], cursor: [1, 1]}
};
for (let i = 0; i < numSteps; i++) {
let currVal = tape[cursor] || 0;
tape[cursor] = transitions[currState].val[currVal];
cursor += transitions[currState].cursor[currVal];
currState = transitions[currState].state[currVal];
};
console.log(Object.values(tape).reduce((a, c) => a + c, 0));
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment