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