Day 23
This commit is contained in:
parent
8efeb39931
commit
b107ee7053
71
23/input
Normal file
71
23/input
Normal file
@ -0,0 +1,71 @@
|
||||
#.##..##.#..#.##..##....##..#..#####...#.###.#..##..#..#.#...##..##....
|
||||
##..###.#.#.#..##.##.####.........#...#..#..#.#..#.#....##..###.#.##..#
|
||||
#.......###....#.#.##.#.#.#.##..###...###..##.....#...#.##.##.......##.
|
||||
...##.#......#.#.#..#.###..#.###....#....#.###.##....####....##....##..
|
||||
.#...##..###...##.#.#..#...####.#.##.#.#..#.##.###.###.#.##.##..#.#...#
|
||||
#..##....##.#..##.##...###..##.#...##...#####...#####.##..#.###....#.#.
|
||||
###....#....#.##.####.###.#..####..##..##..#..#.##.#######.##....###...
|
||||
###..###.....###..##..##....#......#.#.##...####.######..###.###....###
|
||||
#.#.###.###.....###.####.#.####...#.#.###.#...#.##..##.##.#..####..#...
|
||||
####.##...#....##.##.#.#....##.###....#.#..#.....##...##.#...###.##.#.#
|
||||
...#.#..####.###...###.#....###...##.####..#.######.##.##..#.#..##...#.
|
||||
#####......#.####.#####...#...#..#..#.#.#.#.#.#.#.#.##.#..#.###.#....#.
|
||||
#..#.#.#..#...#.#.##..#.######.##..#.###...#.#.#...#.####..##..##..#.#.
|
||||
..#.#..###....#.##.##....####.#########..#.########..##....#..#..##..#.
|
||||
.#.#.#...##...##.#.#..#..#####..###....#..#...####.##.####.###.##..##..
|
||||
.##.####..#.#######..#.#######..##..###....#.#..#..##.#..#.#..###.....#
|
||||
#....#.#####..#.##...###.###....#.#.#.#..#.##.####...#...##..#####.##..
|
||||
...##.###.##...#.##.###.#.###....####.....#.##.##.##.###...###.###.#.##
|
||||
..###...#...##....#.###.....##..####..#.###.####..##.###....##.#....##.
|
||||
...#..##..#..##.###.#....###....#..##..#...##.#..##.#.####...##.##..###
|
||||
######.......####..#..#.#####.......#####..#.#..##..#......#.#.#.#####.
|
||||
.#...#..#.##.###..#.#.#..####.#.########.#.###..####.#..#.#..###.#####.
|
||||
...####.#..#..#.##...#.#####.########.##..##....#####.#.##..######.#.##
|
||||
.....#..##.#.....#..#.#.##..######..####.#..#....##.....###.#.#..##..#.
|
||||
..##.##..##.#.#.##...##.##...#..##.....#..#..#.#.#.....#.#.##.###...###
|
||||
##.#..#.#.####.##....#...##.#...#...#..#.##..#...##.....#.#.##.#####...
|
||||
...#..##..##...#..###....#..#.###..####...#.#..##.###.##......###.#.#.#
|
||||
..##.#.#.##..###.....#..##.#....#....#....#.##..#.#.####.#....##..#..##
|
||||
.##..##..#.#.....###..#.#..#.##.#.#.#..#..#.##.#.###...#..#..##.#....##
|
||||
......#...######....###.##..#.###.####.##.##...#.###...####.##..#..#...
|
||||
#..##.#.###.##......####...#.#.##.#.#....##.##..#.#.....####...#..###..
|
||||
..##...#.##..#.....#######.#.#.###.#.##...####..#.#....##.###..##.#.###
|
||||
...####..#..##.########..#####.##..##...#..##..##..#...###.###....#.###
|
||||
.###.#..#.##.#..###.#.##.#.#...#.#.#.##..##.#....###.#..#.....#..##..#.
|
||||
...##.##...#..#.####.....#.##....####.#.###..##...#..#.####...##..##.##
|
||||
###...##....##..##.#...##......#...##.##.#.....##..##.#..#.##......#..#
|
||||
.......#.######...#####....#...#####.#####...##..#..#.#.#..........#.#.
|
||||
#######.#...#.#..#..#..##..#.####..#.##..###..###.##.#...#.#..#.####.##
|
||||
.#..#......#.#....###.#..##..####.#..#.#..##..#####.#....##.#####.#.#.#
|
||||
.#.###.###..#..#.#.#.#..##.#......###.##.#....#######.#..#.#####.....##
|
||||
#.####..###.#..###.#.#...##.##....###.#.#.#.###..#...#...#.##.###...#..
|
||||
#..##..##.##..##....###..######....#.#####.##..#...#....#.#.###.###....
|
||||
#.###..##.##..#.....##...#..#..#####.#.##..##..#.#...#.....##.#..#.##.#
|
||||
##...#...#.##..####..#..#.###....#...#.....#.#.#.###...###...#####.#.##
|
||||
.#.###.....#.#..#.###########.######..#########.##.##..#.#.#...#..##.##
|
||||
##.#################.#.##.##....####.....#..#.#.##.###.##..#..#.##..#.#
|
||||
.##.####.#.#..##.##.#.#..#.###.#..#..#.####....#.###.####.#.#..##..####
|
||||
##....###.#.####.#.#.............##.....###.##.#.###.####...#####.##.#.
|
||||
...##.#.#.#####.####.##.#..##.###.###.####.#.#.....#.#.#...#####..####.
|
||||
######.#....#...#.#.######.#.#....#.##..#..#..#..#.......#..#.##.#.#...
|
||||
...#..#....#.#.#...###.####..##.#.#..#.#.#.####.#..###...###.######...#
|
||||
#.#.###......##...#...##....###......#.###...#...###..#..####..##...#.#
|
||||
#..##.....#........###.##..#.#.#.#.##..#.##.#..###.##.#.####..###.##.#.
|
||||
.##....#..##.###.#.#.#..#..###..#..#####.##....#..#####.#.##..#.##.###.
|
||||
.#.##.###.####.#.#..#.###.###.#.......####.##...#..##.#.##.##..#.###...
|
||||
#.##...#####.#...#.#.##..###.#.##.###########..#...#..#.#.###.#.##..#.#
|
||||
##...#...#.###.#..##..#...##....#...#.#....###.###.#.#..#...#.#.#.#.###
|
||||
#.#.######.##.#....#.....#..##...#.#####...##.##...#..###.#...##.#..##.
|
||||
##.#######.....#....#.###..#..#.###.###..#.....####....#.####..#.....#.
|
||||
#..#..##..##.#.##......#....#.#.....#......#...##.###..#.#.###.......##
|
||||
#..#.#..######.#.......##..#...#....#####.#...#.##...#...###..####.##..
|
||||
.....#.....#.#.##..###.###.##..#.##.##..#.#####..##.##..###..###..#.###
|
||||
...#.###.#.#.#.##...##.##...#..#..#..####.#.##.#...#.#..##.#.#######.##
|
||||
.####.####..#.####...#...#.#..##...##.##..#....#.#.###.###..#####...##.
|
||||
..##.#.###.####.#####...#......#.#.###...###..##.##.###.####.###.#..#.#
|
||||
#.##..####.#.#..#.##..#.##.#.##.#..###.####.#.#.#.##..#.....##.#.#...#.
|
||||
.##...#.#.#####.###.#...###.#......#####.....#.#######.##.#..##...###..
|
||||
##.#.#####......####.####...#####....#..####.#.#.####...####.###.###.##
|
||||
#.#.#.####..##.##.##.#.##.#.#####.##...#....##..##...#.######.....#..##
|
||||
.#.....#...###.#.#.###.#..#...###...##.......####...####.###..#....#...
|
||||
..##.##..#......###...##.....##.#..#...###.##.#.##.##...#.#...#.#..#...
|
200
23/solution.mjs
Normal file
200
23/solution.mjs
Normal file
@ -0,0 +1,200 @@
|
||||
import { readFileSync } from 'node:fs';
|
||||
|
||||
const input = readFileSync('input', 'utf-8');
|
||||
|
||||
export class InfiniteGrid {
|
||||
constructor() {
|
||||
this.ox = null;
|
||||
this.oy = null;
|
||||
this.rows = [];
|
||||
}
|
||||
|
||||
get height() {
|
||||
return this.rows.length;
|
||||
}
|
||||
|
||||
get width() {
|
||||
return this.rows[0]?.length ?? 0;
|
||||
}
|
||||
|
||||
get(x, y) {
|
||||
return this.rows[y - (this.oy ?? y)]?.[x - (this.ox ?? x)];
|
||||
}
|
||||
|
||||
set(x, y, v) {
|
||||
this.expandToFit(x, y);
|
||||
|
||||
const ax = x - this.ox;
|
||||
const ay = y - this.oy;
|
||||
|
||||
this.rows[ay][ax] = v;
|
||||
}
|
||||
|
||||
expandToFit(x, y) {
|
||||
if (this.ox === null) this.ox = x;
|
||||
if (this.oy === null) this.oy = y;
|
||||
|
||||
const left = Math.max(0, this.ox - x);
|
||||
const up = Math.max(0, this.oy - y);
|
||||
const right = Math.max(0, (x - this.ox + 1) - this.width);
|
||||
const down = Math.max(0, (y - this.oy + 1) - this.height);
|
||||
|
||||
if (up || right || down || left) {
|
||||
this.rows = [
|
||||
...new Array(up).fill(new Array(this.width + left + right).fill()),
|
||||
...this.rows.map(row =>
|
||||
[...new Array(left), ...row, ...new Array(right)]
|
||||
),
|
||||
...new Array(down).fill(new Array(this.width + left + right).fill())
|
||||
];
|
||||
}
|
||||
|
||||
this.ox -= left;
|
||||
this.oy -= up;
|
||||
}
|
||||
|
||||
getBounds() {
|
||||
return {
|
||||
minX: this.ox,
|
||||
maxX: this.ox + (this.rows[0]?.length ?? 1) - 1,
|
||||
minY: this.oy,
|
||||
maxY: this.oy + (this.rows.length || 1) - 1
|
||||
};
|
||||
}
|
||||
|
||||
printDefined() {
|
||||
console.log(this.rows
|
||||
.map(row => row
|
||||
.map(cell => cell ? '#' : '.')
|
||||
.join('')
|
||||
)
|
||||
.join('\n')
|
||||
);
|
||||
}
|
||||
|
||||
countEmpty() {
|
||||
return this.rows.reduce(
|
||||
(total, row) => total + row.reduce(
|
||||
(rowTotal, cell) => rowTotal + Number(!cell),
|
||||
0
|
||||
),
|
||||
0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class Elf {
|
||||
constructor(grid) {
|
||||
this.grid = grid;
|
||||
this.pos = undefined;
|
||||
}
|
||||
|
||||
moveTo(x, y) {
|
||||
if (this.pos) {
|
||||
this.grid.set(...this.pos, undefined);
|
||||
}
|
||||
this.pos = [x, y];
|
||||
this.grid.set(...this.pos, this);
|
||||
}
|
||||
|
||||
proposePosition(directions) {
|
||||
if (!this.pos) throw new Error('Elf is not on the grid');
|
||||
|
||||
const [x, y] = this.pos;
|
||||
const N = this.grid.get(x, y - 1);
|
||||
const NE = this.grid.get(x + 1, y - 1);
|
||||
const E = this.grid.get(x + 1, y);
|
||||
const SE = this.grid.get(x + 1, y + 1);
|
||||
const S = this.grid.get(x, y + 1);
|
||||
const SW = this.grid.get(x - 1, y + 1);
|
||||
const W = this.grid.get(x - 1, y);
|
||||
const NW = this.grid.get(x - 1, y - 1);
|
||||
|
||||
if (!(N || NE || E || SE || S || SW || W || NW)) {
|
||||
// Don't move
|
||||
return;
|
||||
}
|
||||
|
||||
for (const direction of directions) {
|
||||
if (direction === 'N' && !(NW || N || NE)) {
|
||||
return [x, y - 1];
|
||||
} else if (direction === 'E' && !(NE || E || SE)) {
|
||||
return [x + 1, y];
|
||||
} else if (direction === 'S' && !(SW || S || SE)) {
|
||||
return [x, y + 1];
|
||||
} else if (direction === 'W' && !(NW || W || SW)) {
|
||||
return [x - 1, y];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const elfPositions = input
|
||||
.split('\n')
|
||||
.map(line => line.trim())
|
||||
.filter(line => !!line)
|
||||
.flatMap((line, y) => line
|
||||
.split('')
|
||||
.map((c, x) => {
|
||||
if (c === '#') {
|
||||
return [x, y];
|
||||
}
|
||||
})
|
||||
.filter(coords => !!coords)
|
||||
);
|
||||
|
||||
const grid = new InfiniteGrid();
|
||||
const elves = [];
|
||||
for (const pos of elfPositions) {
|
||||
const elf = new Elf(grid);
|
||||
elves.push(elf);
|
||||
elf.moveTo(...pos);
|
||||
}
|
||||
const directions = ['N', 'S', 'W', 'E'];
|
||||
let round = 0;
|
||||
|
||||
function processRound() {
|
||||
const propositions = elves.flatMap(elf => {
|
||||
const pos = elf.proposePosition(directions);
|
||||
if (!pos) return [];
|
||||
return [{elf, x: pos[0], y: pos[1]}];
|
||||
});
|
||||
|
||||
propositions.sort((p1, p2) => (p1.x - p2.x) || (p1.y - p2.y));
|
||||
const validPropositions = propositions
|
||||
.reduce((groups, proposition) => {
|
||||
if (groups.length) {
|
||||
const lastGroup = groups[groups.length - 1];
|
||||
const {x: lastX, y: lastY} = lastGroup[0];
|
||||
if (proposition.x === lastX && proposition.y === lastY) {
|
||||
lastGroup.push(proposition);
|
||||
return groups;
|
||||
}
|
||||
}
|
||||
|
||||
groups.push([proposition]);
|
||||
return groups;
|
||||
}, [])
|
||||
.filter(group => group.length === 1)
|
||||
.flat();
|
||||
|
||||
const moved = validPropositions.length;
|
||||
|
||||
for (const proposition of validPropositions) {
|
||||
proposition.elf.moveTo(proposition.x, proposition.y);
|
||||
}
|
||||
|
||||
// Reorder directions
|
||||
directions.push(directions.shift());
|
||||
|
||||
round++;
|
||||
return moved;
|
||||
}
|
||||
|
||||
do {
|
||||
processRound();
|
||||
} while (round <= 10)
|
||||
console.log('The number of empty ground tiles is:', grid.countEmpty());
|
||||
|
||||
while (processRound() !== 0) {};
|
||||
console.log('The number of rounds to completion is:', round);
|
Loading…
Reference in New Issue
Block a user