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