index.js (3760B)
1 const fs = require('fs'); 2 3 const lines = fs.readFileSync('input', 'utf-8') 4 // const lines = fs.readFileSync('sample', 'utf-8') 5 .split('\n') 6 7 const elves = []; 8 for(let y=0; y<lines.length; y++) { 9 const line = lines[y]; 10 for(let x=0; x<line.length; x++) { 11 if (line.charAt(x) == '#') { 12 elves.push({ 13 x, 14 y, 15 }); 16 } 17 } 18 } 19 20 function adjacent(grid, origin) { 21 const neighbours = []; 22 for(let y=origin.y-1; y<=origin.y+1; y++) { 23 if (!grid[y]) continue; 24 for(let x=origin.x-1; x<=origin.x+1; x++) { 25 if (y == origin.y && x == origin.x) continue; 26 if (grid[y][x]) neighbours.push(grid[y][x]); 27 } 28 } 29 return neighbours; 30 } 31 32 let step1 = 0; 33 const moves = ['N','S','W','E']; 34 35 const test = { 36 N: origin => subject => subject.y < origin.y, 37 S: origin => subject => subject.y > origin.y, 38 W: origin => subject => subject.x < origin.x, 39 E: origin => subject => subject.x > origin.x, 40 }; 41 42 function drawmap(elves) { 43 let output = '\n'; 44 let minx = Infinity; 45 let miny = Infinity; 46 let maxx = -Infinity; 47 let maxy = -Infinity; 48 for(const elf of elves) { 49 if (elf.x < minx) minx = elf.x; 50 if (elf.y < miny) miny = elf.y; 51 if (elf.x > maxx) maxx = elf.x; 52 if (elf.y > maxy) maxy = elf.y; 53 } 54 for(let y=miny; y<=maxy; y++) { 55 for(let x=minx; x<=maxx; x++) { 56 if (elves.find(elf => elf.x == x && elf.y == y)) { 57 output += '#'; 58 } else { 59 output += ' '; 60 } 61 } 62 output += '\n'; 63 } 64 process.stdout.write(output); 65 } 66 67 const dirdiff = { 68 N: [ 0, -1], 69 S: [ 0, 1], 70 W: [-1, 0], 71 E: [ 1, 0], 72 }; 73 74 // drawmap(elves); 75 76 const grid = []; 77 for(const elf of elves) { 78 grid[elf.y] = grid[elf.y] || []; 79 grid[elf.y][elf.x] = elf; 80 } 81 82 (async () => { 83 let proposals = []; 84 let rounds = 0; 85 do { 86 proposals = []; 87 88 // stage 1, make proposals 89 for(const elf of elves) { 90 // Only make a proposal if neighbours are found 91 const neighbours = adjacent(grid, elf); 92 if (!neighbours.length) continue; 93 for(const direction of moves) { 94 if (neighbours.find(test[direction](elf))) continue; 95 proposals.push({ 96 elf, 97 direction, 98 x: elf.x + dirdiff[direction][0], 99 y: elf.y + dirdiff[direction][1], 100 }); 101 break; 102 } 103 } 104 105 // stage 2, count proposals per location 106 let positions = []; 107 for(const proposal of proposals) { 108 if (!positions[proposal.y]) positions[proposal.y] = []; 109 positions[proposal.y][proposal.x] = (positions[proposal.y][proposal.x]||0) + 1; 110 } 111 112 // stage 3, move the elves 113 for(const proposal of proposals) { 114 if (positions[proposal.y][proposal.x] > 1) continue; 115 grid[proposal.elf.y][proposal.elf.x] = false; 116 grid[proposal.y] = grid[proposal.y] || []; 117 grid[proposal.y][proposal.x] = proposal.elf; 118 proposal.elf.x = proposal.x; 119 proposal.elf.y = proposal.y; 120 } 121 122 // stage 4, moves 123 moves.push(moves.shift()); 124 125 // Round counter 126 rounds++; 127 128 // if (rounds % 1e1 == 0) { 129 // drawmap(elves); 130 // console.log(proposals.length); 131 // } 132 133 if (rounds == 10) { 134 // Find area to check 135 let minx = Infinity; 136 let miny = Infinity; 137 let maxx = -Infinity; 138 let maxy = -Infinity; 139 for(const elf of elves) { 140 if (elf.x < minx) minx = elf.x; 141 if (elf.y < miny) miny = elf.y; 142 if (elf.x > maxx) maxx = elf.x; 143 if (elf.y > maxy) maxy = elf.y; 144 } 145 146 // Calculate empty area 147 const width = maxx - minx + 1; 148 const height = maxy - miny + 1; 149 const area = (width * height) - elves.length; 150 console.log({ area }); 151 } 152 153 } while(proposals.length); 154 155 156 console.log({ elves: elves.length, rounds }); 157 158 })();