diff --git a/14/input b/14/input new file mode 100644 index 0000000..d1d0249 --- /dev/null +++ b/14/input @@ -0,0 +1,118 @@ +441,111 -> 441,105 -> 441,111 -> 443,111 -> 443,104 -> 443,111 -> 445,111 -> 445,106 -> 445,111 -> 447,111 -> 447,104 -> 447,111 +441,111 -> 441,105 -> 441,111 -> 443,111 -> 443,104 -> 443,111 -> 445,111 -> 445,106 -> 445,111 -> 447,111 -> 447,104 -> 447,111 +454,118 -> 454,122 -> 451,122 -> 451,126 -> 464,126 -> 464,122 -> 458,122 -> 458,118 +440,135 -> 440,136 -> 453,136 -> 453,135 +498,21 -> 502,21 +469,69 -> 473,69 +440,135 -> 440,136 -> 453,136 -> 453,135 +441,111 -> 441,105 -> 441,111 -> 443,111 -> 443,104 -> 443,111 -> 445,111 -> 445,106 -> 445,111 -> 447,111 -> 447,104 -> 447,111 +435,149 -> 435,148 -> 435,149 -> 437,149 -> 437,146 -> 437,149 -> 439,149 -> 439,146 -> 439,149 -> 441,149 -> 441,145 -> 441,149 +473,47 -> 473,42 -> 473,47 -> 475,47 -> 475,45 -> 475,47 -> 477,47 -> 477,39 -> 477,47 -> 479,47 -> 479,45 -> 479,47 -> 481,47 -> 481,42 -> 481,47 -> 483,47 -> 483,46 -> 483,47 -> 485,47 -> 485,39 -> 485,47 +473,47 -> 473,42 -> 473,47 -> 475,47 -> 475,45 -> 475,47 -> 477,47 -> 477,39 -> 477,47 -> 479,47 -> 479,45 -> 479,47 -> 481,47 -> 481,42 -> 481,47 -> 483,47 -> 483,46 -> 483,47 -> 485,47 -> 485,39 -> 485,47 +455,72 -> 455,76 -> 452,76 -> 452,81 -> 464,81 -> 464,76 -> 459,76 -> 459,72 +435,149 -> 435,148 -> 435,149 -> 437,149 -> 437,146 -> 437,149 -> 439,149 -> 439,146 -> 439,149 -> 441,149 -> 441,145 -> 441,149 +473,47 -> 473,42 -> 473,47 -> 475,47 -> 475,45 -> 475,47 -> 477,47 -> 477,39 -> 477,47 -> 479,47 -> 479,45 -> 479,47 -> 481,47 -> 481,42 -> 481,47 -> 483,47 -> 483,46 -> 483,47 -> 485,47 -> 485,39 -> 485,47 +435,149 -> 435,148 -> 435,149 -> 437,149 -> 437,146 -> 437,149 -> 439,149 -> 439,146 -> 439,149 -> 441,149 -> 441,145 -> 441,149 +489,19 -> 493,19 +469,65 -> 473,65 +435,149 -> 435,148 -> 435,149 -> 437,149 -> 437,146 -> 437,149 -> 439,149 -> 439,146 -> 439,149 -> 441,149 -> 441,145 -> 441,149 +449,84 -> 453,84 +481,34 -> 481,32 -> 481,34 -> 483,34 -> 483,27 -> 483,34 -> 485,34 -> 485,32 -> 485,34 -> 487,34 -> 487,26 -> 487,34 +438,158 -> 442,158 +481,34 -> 481,32 -> 481,34 -> 483,34 -> 483,27 -> 483,34 -> 485,34 -> 485,32 -> 485,34 -> 487,34 -> 487,26 -> 487,34 +443,88 -> 447,88 +473,47 -> 473,42 -> 473,47 -> 475,47 -> 475,45 -> 475,47 -> 477,47 -> 477,39 -> 477,47 -> 479,47 -> 479,45 -> 479,47 -> 481,47 -> 481,42 -> 481,47 -> 483,47 -> 483,46 -> 483,47 -> 485,47 -> 485,39 -> 485,47 +470,50 -> 470,52 -> 469,52 -> 469,60 -> 478,60 -> 478,52 -> 474,52 -> 474,50 +445,131 -> 454,131 -> 454,130 +454,118 -> 454,122 -> 451,122 -> 451,126 -> 464,126 -> 464,122 -> 458,122 -> 458,118 +454,118 -> 454,122 -> 451,122 -> 451,126 -> 464,126 -> 464,122 -> 458,122 -> 458,118 +446,86 -> 450,86 +463,65 -> 467,65 +481,34 -> 481,32 -> 481,34 -> 483,34 -> 483,27 -> 483,34 -> 485,34 -> 485,32 -> 485,34 -> 487,34 -> 487,26 -> 487,34 +435,155 -> 439,155 +481,34 -> 481,32 -> 481,34 -> 483,34 -> 483,27 -> 483,34 -> 485,34 -> 485,32 -> 485,34 -> 487,34 -> 487,26 -> 487,34 +457,69 -> 461,69 +473,47 -> 473,42 -> 473,47 -> 475,47 -> 475,45 -> 475,47 -> 477,47 -> 477,39 -> 477,47 -> 479,47 -> 479,45 -> 479,47 -> 481,47 -> 481,42 -> 481,47 -> 483,47 -> 483,46 -> 483,47 -> 485,47 -> 485,39 -> 485,47 +473,47 -> 473,42 -> 473,47 -> 475,47 -> 475,45 -> 475,47 -> 477,47 -> 477,39 -> 477,47 -> 479,47 -> 479,45 -> 479,47 -> 481,47 -> 481,42 -> 481,47 -> 483,47 -> 483,46 -> 483,47 -> 485,47 -> 485,39 -> 485,47 +473,47 -> 473,42 -> 473,47 -> 475,47 -> 475,45 -> 475,47 -> 477,47 -> 477,39 -> 477,47 -> 479,47 -> 479,45 -> 479,47 -> 481,47 -> 481,42 -> 481,47 -> 483,47 -> 483,46 -> 483,47 -> 485,47 -> 485,39 -> 485,47 +455,72 -> 455,76 -> 452,76 -> 452,81 -> 464,81 -> 464,76 -> 459,76 -> 459,72 +495,19 -> 499,19 +473,47 -> 473,42 -> 473,47 -> 475,47 -> 475,45 -> 475,47 -> 477,47 -> 477,39 -> 477,47 -> 479,47 -> 479,45 -> 479,47 -> 481,47 -> 481,42 -> 481,47 -> 483,47 -> 483,46 -> 483,47 -> 485,47 -> 485,39 -> 485,47 +440,135 -> 440,136 -> 453,136 -> 453,135 +435,149 -> 435,148 -> 435,149 -> 437,149 -> 437,146 -> 437,149 -> 439,149 -> 439,146 -> 439,149 -> 441,149 -> 441,145 -> 441,149 +473,47 -> 473,42 -> 473,47 -> 475,47 -> 475,45 -> 475,47 -> 477,47 -> 477,39 -> 477,47 -> 479,47 -> 479,45 -> 479,47 -> 481,47 -> 481,42 -> 481,47 -> 483,47 -> 483,46 -> 483,47 -> 485,47 -> 485,39 -> 485,47 +441,111 -> 441,105 -> 441,111 -> 443,111 -> 443,104 -> 443,111 -> 445,111 -> 445,106 -> 445,111 -> 447,111 -> 447,104 -> 447,111 +455,72 -> 455,76 -> 452,76 -> 452,81 -> 464,81 -> 464,76 -> 459,76 -> 459,72 +454,118 -> 454,122 -> 451,122 -> 451,126 -> 464,126 -> 464,122 -> 458,122 -> 458,118 +470,50 -> 470,52 -> 469,52 -> 469,60 -> 478,60 -> 478,52 -> 474,52 -> 474,50 +435,149 -> 435,148 -> 435,149 -> 437,149 -> 437,146 -> 437,149 -> 439,149 -> 439,146 -> 439,149 -> 441,149 -> 441,145 -> 441,149 +473,47 -> 473,42 -> 473,47 -> 475,47 -> 475,45 -> 475,47 -> 477,47 -> 477,39 -> 477,47 -> 479,47 -> 479,45 -> 479,47 -> 481,47 -> 481,42 -> 481,47 -> 483,47 -> 483,46 -> 483,47 -> 485,47 -> 485,39 -> 485,47 +455,72 -> 455,76 -> 452,76 -> 452,81 -> 464,81 -> 464,76 -> 459,76 -> 459,72 +472,67 -> 476,67 +473,47 -> 473,42 -> 473,47 -> 475,47 -> 475,45 -> 475,47 -> 477,47 -> 477,39 -> 477,47 -> 479,47 -> 479,45 -> 479,47 -> 481,47 -> 481,42 -> 481,47 -> 483,47 -> 483,46 -> 483,47 -> 485,47 -> 485,39 -> 485,47 +470,50 -> 470,52 -> 469,52 -> 469,60 -> 478,60 -> 478,52 -> 474,52 -> 474,50 +439,91 -> 439,94 -> 435,94 -> 435,98 -> 444,98 -> 444,94 -> 443,94 -> 443,91 +473,47 -> 473,42 -> 473,47 -> 475,47 -> 475,45 -> 475,47 -> 477,47 -> 477,39 -> 477,47 -> 479,47 -> 479,45 -> 479,47 -> 481,47 -> 481,42 -> 481,47 -> 483,47 -> 483,46 -> 483,47 -> 485,47 -> 485,39 -> 485,47 +495,14 -> 506,14 -> 506,13 +429,155 -> 433,155 +481,34 -> 481,32 -> 481,34 -> 483,34 -> 483,27 -> 483,34 -> 485,34 -> 485,32 -> 485,34 -> 487,34 -> 487,26 -> 487,34 +470,50 -> 470,52 -> 469,52 -> 469,60 -> 478,60 -> 478,52 -> 474,52 -> 474,50 +473,47 -> 473,42 -> 473,47 -> 475,47 -> 475,45 -> 475,47 -> 477,47 -> 477,39 -> 477,47 -> 479,47 -> 479,45 -> 479,47 -> 481,47 -> 481,42 -> 481,47 -> 483,47 -> 483,46 -> 483,47 -> 485,47 -> 485,39 -> 485,47 +455,72 -> 455,76 -> 452,76 -> 452,81 -> 464,81 -> 464,76 -> 459,76 -> 459,72 +439,91 -> 439,94 -> 435,94 -> 435,98 -> 444,98 -> 444,94 -> 443,94 -> 443,91 +473,47 -> 473,42 -> 473,47 -> 475,47 -> 475,45 -> 475,47 -> 477,47 -> 477,39 -> 477,47 -> 479,47 -> 479,45 -> 479,47 -> 481,47 -> 481,42 -> 481,47 -> 483,47 -> 483,46 -> 483,47 -> 485,47 -> 485,39 -> 485,47 +441,111 -> 441,105 -> 441,111 -> 443,111 -> 443,104 -> 443,111 -> 445,111 -> 445,106 -> 445,111 -> 447,111 -> 447,104 -> 447,111 +445,131 -> 454,131 -> 454,130 +452,86 -> 456,86 +455,88 -> 459,88 +473,47 -> 473,42 -> 473,47 -> 475,47 -> 475,45 -> 475,47 -> 477,47 -> 477,39 -> 477,47 -> 479,47 -> 479,45 -> 479,47 -> 481,47 -> 481,42 -> 481,47 -> 483,47 -> 483,46 -> 483,47 -> 485,47 -> 485,39 -> 485,47 +441,114 -> 441,115 -> 455,115 +473,47 -> 473,42 -> 473,47 -> 475,47 -> 475,45 -> 475,47 -> 477,47 -> 477,39 -> 477,47 -> 479,47 -> 479,45 -> 479,47 -> 481,47 -> 481,42 -> 481,47 -> 483,47 -> 483,46 -> 483,47 -> 485,47 -> 485,39 -> 485,47 +460,67 -> 464,67 +470,50 -> 470,52 -> 469,52 -> 469,60 -> 478,60 -> 478,52 -> 474,52 -> 474,50 +481,34 -> 481,32 -> 481,34 -> 483,34 -> 483,27 -> 483,34 -> 485,34 -> 485,32 -> 485,34 -> 487,34 -> 487,26 -> 487,34 +492,21 -> 496,21 +435,149 -> 435,148 -> 435,149 -> 437,149 -> 437,146 -> 437,149 -> 439,149 -> 439,146 -> 439,149 -> 441,149 -> 441,145 -> 441,149 +439,91 -> 439,94 -> 435,94 -> 435,98 -> 444,98 -> 444,94 -> 443,94 -> 443,91 +470,50 -> 470,52 -> 469,52 -> 469,60 -> 478,60 -> 478,52 -> 474,52 -> 474,50 +441,111 -> 441,105 -> 441,111 -> 443,111 -> 443,104 -> 443,111 -> 445,111 -> 445,106 -> 445,111 -> 447,111 -> 447,104 -> 447,111 +473,47 -> 473,42 -> 473,47 -> 475,47 -> 475,45 -> 475,47 -> 477,47 -> 477,39 -> 477,47 -> 479,47 -> 479,45 -> 479,47 -> 481,47 -> 481,42 -> 481,47 -> 483,47 -> 483,46 -> 483,47 -> 485,47 -> 485,39 -> 485,47 +492,17 -> 496,17 +455,72 -> 455,76 -> 452,76 -> 452,81 -> 464,81 -> 464,76 -> 459,76 -> 459,72 +481,34 -> 481,32 -> 481,34 -> 483,34 -> 483,27 -> 483,34 -> 485,34 -> 485,32 -> 485,34 -> 487,34 -> 487,26 -> 487,34 +481,34 -> 481,32 -> 481,34 -> 483,34 -> 483,27 -> 483,34 -> 485,34 -> 485,32 -> 485,34 -> 487,34 -> 487,26 -> 487,34 +454,118 -> 454,122 -> 451,122 -> 451,126 -> 464,126 -> 464,122 -> 458,122 -> 458,118 +466,67 -> 470,67 +470,50 -> 470,52 -> 469,52 -> 469,60 -> 478,60 -> 478,52 -> 474,52 -> 474,50 +466,63 -> 470,63 +481,34 -> 481,32 -> 481,34 -> 483,34 -> 483,27 -> 483,34 -> 485,34 -> 485,32 -> 485,34 -> 487,34 -> 487,26 -> 487,34 +481,34 -> 481,32 -> 481,34 -> 483,34 -> 483,27 -> 483,34 -> 485,34 -> 485,32 -> 485,34 -> 487,34 -> 487,26 -> 487,34 +486,21 -> 490,21 +455,72 -> 455,76 -> 452,76 -> 452,81 -> 464,81 -> 464,76 -> 459,76 -> 459,72 +439,91 -> 439,94 -> 435,94 -> 435,98 -> 444,98 -> 444,94 -> 443,94 -> 443,91 +481,34 -> 481,32 -> 481,34 -> 483,34 -> 483,27 -> 483,34 -> 485,34 -> 485,32 -> 485,34 -> 487,34 -> 487,26 -> 487,34 +473,47 -> 473,42 -> 473,47 -> 475,47 -> 475,45 -> 475,47 -> 477,47 -> 477,39 -> 477,47 -> 479,47 -> 479,45 -> 479,47 -> 481,47 -> 481,42 -> 481,47 -> 483,47 -> 483,46 -> 483,47 -> 485,47 -> 485,39 -> 485,47 +441,111 -> 441,105 -> 441,111 -> 443,111 -> 443,104 -> 443,111 -> 445,111 -> 445,106 -> 445,111 -> 447,111 -> 447,104 -> 447,111 +426,158 -> 430,158 +441,111 -> 441,105 -> 441,111 -> 443,111 -> 443,104 -> 443,111 -> 445,111 -> 445,106 -> 445,111 -> 447,111 -> 447,104 -> 447,111 +441,111 -> 441,105 -> 441,111 -> 443,111 -> 443,104 -> 443,111 -> 445,111 -> 445,106 -> 445,111 -> 447,111 -> 447,104 -> 447,111 +441,114 -> 441,115 -> 455,115 +473,47 -> 473,42 -> 473,47 -> 475,47 -> 475,45 -> 475,47 -> 477,47 -> 477,39 -> 477,47 -> 479,47 -> 479,45 -> 479,47 -> 481,47 -> 481,42 -> 481,47 -> 483,47 -> 483,46 -> 483,47 -> 485,47 -> 485,39 -> 485,47 +475,69 -> 479,69 +435,149 -> 435,148 -> 435,149 -> 437,149 -> 437,146 -> 437,149 -> 439,149 -> 439,146 -> 439,149 -> 441,149 -> 441,145 -> 441,149 +454,118 -> 454,122 -> 451,122 -> 451,126 -> 464,126 -> 464,122 -> 458,122 -> 458,118 +463,69 -> 467,69 +432,158 -> 436,158 +439,91 -> 439,94 -> 435,94 -> 435,98 -> 444,98 -> 444,94 -> 443,94 -> 443,91 +454,118 -> 454,122 -> 451,122 -> 451,126 -> 464,126 -> 464,122 -> 458,122 -> 458,118 +439,91 -> 439,94 -> 435,94 -> 435,98 -> 444,98 -> 444,94 -> 443,94 -> 443,91 +435,149 -> 435,148 -> 435,149 -> 437,149 -> 437,146 -> 437,149 -> 439,149 -> 439,146 -> 439,149 -> 441,149 -> 441,145 -> 441,149 +432,152 -> 436,152 +439,91 -> 439,94 -> 435,94 -> 435,98 -> 444,98 -> 444,94 -> 443,94 -> 443,91 +435,149 -> 435,148 -> 435,149 -> 437,149 -> 437,146 -> 437,149 -> 439,149 -> 439,146 -> 439,149 -> 441,149 -> 441,145 -> 441,149 +473,47 -> 473,42 -> 473,47 -> 475,47 -> 475,45 -> 475,47 -> 477,47 -> 477,39 -> 477,47 -> 479,47 -> 479,45 -> 479,47 -> 481,47 -> 481,42 -> 481,47 -> 483,47 -> 483,46 -> 483,47 -> 485,47 -> 485,39 -> 485,47 +441,111 -> 441,105 -> 441,111 -> 443,111 -> 443,104 -> 443,111 -> 445,111 -> 445,106 -> 445,111 -> 447,111 -> 447,104 -> 447,111 +495,14 -> 506,14 -> 506,13 +435,149 -> 435,148 -> 435,149 -> 437,149 -> 437,146 -> 437,149 -> 439,149 -> 439,146 -> 439,149 -> 441,149 -> 441,145 -> 441,149 +449,88 -> 453,88 +441,111 -> 441,105 -> 441,111 -> 443,111 -> 443,104 -> 443,111 -> 445,111 -> 445,106 -> 445,111 -> 447,111 -> 447,104 -> 447,111 diff --git a/14/solution.mjs b/14/solution.mjs new file mode 100644 index 0000000..05b64fb --- /dev/null +++ b/14/solution.mjs @@ -0,0 +1,171 @@ +import { readFileSync } from 'node:fs'; + +const input = readFileSync('input', 'utf-8'); + +function inclusiveRange(from, to) { + const difference = to - from; + const distance = Math.abs(difference); + const add = difference / (distance || 1); + return new Array(distance + 1).fill().map((_, i) => from + i * add) +} + +const rockCoords = input + .split('\n') + .filter(Boolean) + .flatMap(path => path + .split(' -> ') + .map(coordinates => coordinates + .split(',') + .map(coordinate => parseInt(coordinate)) + ) + // Separate into pairs of coordinates that represent a line + .flatMap((coord, i, coords) => i === 0 ? [] : [[coords[i - 1], coord]]) + // Fill in gaps between coordinates, will include duplicates + .flatMap(([from, to]) => [ + ...inclusiveRange(from[0], to[0]).map(x => [x, from[1]]), + ...inclusiveRange(from[1], to[1]).map(y => [from[0], y]) + ]) + ); + +class InfinitePage { + constructor() { + this.ox = null; + this.oy = null; + this.lines = []; + } + + get(x, y) { + return this.lines[y - (this.oy ?? y)]?.[x - (this.ox ?? x)] || ' '; + } + + set(x, y, v) { + const c = v?.length ? v[0] : ' '; + + if (this.ox === null) this.ox = x; + if (this.oy === null) this.oy = y; + + const height = this.lines.length; + const width = this.lines[0]?.length ?? 0; + + const expandLeft = Math.max(0, this.ox - x); + const expandUp = Math.max(0, this.oy - y); + const expandRight = Math.max(0, (x - this.ox + 1) - width); + const expandDown = Math.max(0, (y - this.oy + 1) - height); + + this.expand(expandUp, expandRight, expandDown, expandLeft); + + const ax = x - this.ox; + const ay = y - this.oy; + + const line = this.lines[ay]; + this.lines[ay] = line.slice(0, ax) + c + line.slice(ax + 1); + } + + expand(up, right, down, left) { + const width = this.lines[0]?.length ?? 0; + + if (up + right + down + left > 0) { + this.lines = [ + ...new Array(up).fill(' '.repeat(width)), + ...this.lines, + ...new Array(down).fill(' '.repeat(width)) + ].map(line => ' '.repeat(left) + line + ' '.repeat(right)); + } + + this.ox -= left; + this.oy -= up; + } + + print() { + console.log(this.lines.join('\n')); + } + + getBounds() { + return { + minX: this.ox, + maxX: this.ox + (this.lines[0]?.length ?? 1) - 1, + minY: this.oy, + maxY: this.oy + (this.lines.length || 1) - 1 + }; + } +} + +function getCave() { + const cave = new InfinitePage(); + for (const coord of rockCoords) { + cave.set(...coord, '#'); + } + return cave; +} + +// Sand simulation +function nextSandPos(x, y, canMoveTo) { + const fallPriority = [ + {x: 0, y: 1}, + {x: -1, y: 1}, + {x: 1, y: 1} + ]; + for (const fall of fallPriority) { + const nx = x + fall.x; + const ny = y + fall.y; + + if (canMoveTo(nx, ny)) { + return [nx, ny]; + } + } +} + +function addUnitOfSand(cave, canMoveTo) { + let x = 500; + let y = 0; + while (true) { + let nextPos = nextSandPos(x, y, canMoveTo); + if (!nextPos) { + cave.set(x, y, 'o'); + break; + } + ([x, y] = nextPos); + } +}; + +class EndSimulationError extends Error {} +function simulateSand(cave, canMoveTo) { + let sandCount = 0; + while (true) { + try { + addUnitOfSand(cave, canMoveTo); + sandCount++; + } catch (err) { + if (!(err instanceof EndSimulationError)) { + throw err; + } + break; + } + } + return sandCount; +} + +const cave1 = getCave(); +const bounds = cave1.getBounds(); +const count1 = simulateSand( + cave1, + (x, y) => { + if (x < bounds.minX || x > bounds.maxX || y < 0 || y > bounds.maxY) { + throw new EndSimulationError(); + } + return cave1.get(x, y) === ' '; + } +); +console.log(`First simulation ended after ${count1} units of sand`); + +const cave2 = getCave(); +const count2 = simulateSand( + cave2, + (x, y) => { + if (cave2.get(500, 0) === 'o') { + throw new EndSimulationError(); + } + return y < bounds.maxY + 2 && cave2.get(x, y) === ' '; + } +) +console.log(`Second simulation ended after ${count2} units of sand`);