jsadvent/solutions/2020/11.js

133 lines
3.4 KiB
JavaScript

const { Glib, Vector, twodee } = require('../../lib');
const STATE = {
EMPTY: 'L',
FLOOR: '.',
OCCUPIED: '#',
NONE: 'X',
};
const step1 = (input) => {
let changes = 0n;
const output = input.glibEntries
.map(([pts, state]) => {
switch (state) {
case STATE.EMPTY:
if (
Vector.fromString(pts)
.neighbors()
.map((pt) => pt.string)
.lookupInMap(input, true)
.filter((neighborState) => neighborState === STATE.OCCUPIED)
.length === 0n
) {
changes++;
return [pts, STATE.OCCUPIED];
}
return [pts, STATE.EMPTY];
case STATE.OCCUPIED:
if (
Vector.fromString(pts)
.neighbors()
.map((pt) => pt.string)
.lookupInMap(input, true)
.filter((neighborState) => neighborState === STATE.OCCUPIED)
.length >= 4n
) {
changes++;
return [pts, STATE.EMPTY];
}
return [pts, STATE.OCCUPIED];
case STATE.FLOOR:
return [pts, STATE.FLOOR];
default:
console.log(pts, state);
throw new Error('invalid state');
}
})
.toMap();
return [output, changes];
};
const visibleNeighbor = (point, direction, state) => {
let next = point.add(direction);
while (true) {
const nextString = next.string;
if (!state.has(nextString)) {
return state.NONE;
}
const found = state.get(nextString);
if (found !== STATE.FLOOR) {
return found;
}
next = next.add(direction);
}
};
const step2 = (input) => {
let changes = 0n;
const output = input.glibEntries
.map(([pts, state]) => {
const pt = Vector.fromString(pts);
switch (state) {
case STATE.EMPTY:
if (
twodee.ORIGIN.neighbors()
.map((direction) => visibleNeighbor(pt, direction, input))
.filter((neighborState) => neighborState === STATE.OCCUPIED)
.length === 0n
) {
changes++;
return [pts, STATE.OCCUPIED];
}
return [pts, STATE.EMPTY];
case STATE.OCCUPIED:
if (
twodee.ORIGIN.neighbors()
.map((direction) => visibleNeighbor(pt, direction, input))
.filter((neighborState) => neighborState === STATE.OCCUPIED)
.length >= 5n
) {
changes++;
return [pts, STATE.EMPTY];
}
return [pts, STATE.OCCUPIED];
case STATE.FLOOR:
return [pts, STATE.FLOOR];
default:
console.log(pts, state);
throw new Error('invalid state');
}
})
.toMap();
return [output, changes];
};
const solve = (input, stepFn) => {
let state = Glib.fromLines(input)
.flatMap((line, y) =>
Glib.fromIterable(line).map((cell, x) => [new Vector(x, y).string, cell]),
)
.toMap();
// only run 1k iterations, it's a fairly simple automota
// I wonder it it's possible to make a glider...
for (let i = 0n; i < 1000n; i++) {
const [newState, changes] = stepFn(state);
if (changes === 0n) {
return state.glibValues.filter((e) => e === STATE.OCCUPIED).length;
}
state = newState;
}
throw new Error('too many iterations');
};
module.exports = {
1: (input) => solve(input, step1),
2: (input) => solve(input, step2),
};