From bc6c2a94262990a6d95156c121a6fdacfa93b3d1 Mon Sep 17 00:00:00 2001 From: Ben Ashton Date: Tue, 20 Dec 2022 16:22:09 -0700 Subject: [PATCH] Day 17 --- 17/input | 1 + 17/solution.mjs | 290 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 291 insertions(+) create mode 100644 17/input create mode 100644 17/solution.mjs diff --git a/17/input b/17/input new file mode 100644 index 0000000..b871a08 --- /dev/null +++ b/17/input @@ -0,0 +1 @@ +>>><<<>>>><<<>>>><<<<>>><<<>><<<<><<<<>><<<<><<<><>>>><<<>>><<<<>>><>>>><<<>>>><>>><>>><<<<>>>><<>>><>>><>>>><<<<>>>><<<>>><>><<<>>><<<>>>><<<>>><>>>><<>>>><<<<>>><<>>>><<<>>>><>>><<<>><<>>>><<>>>><><<<>><<<>>>><><>>>><<><<<<>>>><<<>>>><<<><>>><<<>>>><<<>>><<<>><<<<>><<<<><<<>><<><>>><<<<>>>><<<<>><<>>>><<<<>><<<<>><<<<><<<>><<<>><<<>><<>><<>>><<<<>>><<<<>><<<><<<>><>>>><<<<>>><><<<<>><<<<><<><<<>>>><<<<>><>><<<<>>><<<>>>><<<>>><<<><<><<<>>>><<<<><><<<>>><<<<>>>><<<<>>><<<>>>><<<<><<<>>><<>><<<><>>>><<<<>>>><<<>><<<>>><<<><<<><<<<>>>><<>>>><<<>>>><><>>>><<>>>><<<>><>>>><<<<>>><<<><>>><<<><<<<>>><<<><<<>>><>>><<<>>>><>>><<<>><><>><<<<>><>>><>>>><<>><<<>><<>>><<>>>><<<<>>>><<<<>>>><<<>>><<>>>><<><<>>><<>>><<<<>>><<>><>>>><><><<<<>>>><<<<>><<<<><<<<>>>><<<>>><<><<<>>>><<><><<>>><<>><<<>>><>><<<>><<<<>>><><<>><<<>>><<<<>><>>><<>><>>><<<><>><<>>>><>>><<>>><<<<>><<<<>>>><>>><<<><<<<>>><<>>><>>><<<<>>>><<<<>><<<>>>><<>>><>>><>>><<<>><<<<>>><<<<>>>><>>><>>>><<<<><<><<<<>>>><>><>>>><<<><<<>>><>>><<<<><>>><<<>><<<>>><<<>>>><>>><>>>><<>><<>>><<<<>>>><><<<<>><<<>><<>>><>><><<>><<>>>><<<<>>>><<<>>><<>><>>><<<<><<<<>><<>>>><<<<>>>><<<>><><<<<>>>><><<<><<<<>>>><>>>><<<>>><<<<>>>><<<>>>><<>>>><<><<>><<<<>><<>>>><<<><<>><<<<>>><<<>>><<>>><<<>>>><<>>>><<>>><<<<>>><<<>>>><<>>>><<<<>>><<<>><<<>><<><<<<>><>><>><<<><<>>>><<<<><>>>><<<<><<>>><<>>>><<>>><>>><><<><<<<>>>><<>>>><<<>><<>>>><<<>>><<<>>><<<><<<<>><<<>><<<<><<>>><<<>>><<<>><<<>>>><<><>><<<><<<<>><<>><<<>><<<<>><<<>>>><>><<>>>><<<><<>>>><<<>>>><>>><<<>>>><<<<>>><<<><<>>><<<>>><<>><<>>>><<<<>>><<<><<<><>><>>><<<<><<<<><<<<>><<<<>>><<<<><<><<>>><<<<>><<<>><><>>>><>><<<<>><<>>>><><>>><><<>>><>><<<<>><>>><>><<<<><<<>>><>><<<>>>><><>>><<<>>>><<><><<<<>>><<>><<<>><<><<<<>>>><<>><>>><<>>><<>>>><<<>>><<>>>><<<<>>>><<<<>><<<<>>>><<<<>>><<<><<<>>><>>>><>>>><<<><<<<>>><><<<<>>>><>><<>>>><<<<>>><<>>><><<<<>>><<<<>>>><<<<>>>><<><>>>><<><<>>><<><<<<>>>><<<<>><<<><>>>><>>>><<>>><<<<><><<>>><<>>><><><><>>><<><<>>><>>><<<<>>>><><<<>>>><>>><<<>>><<<>>>><<<>>>><<>>><>>>><<>><<<>>><<<>><<<<><<>>>><<<<>>><<<<>>><>>><<<<>><<<<>><<<<>><<<><<<>>>><<<>>>><>>><<>><<<<><<<>>>><<<>>><<<<>>>><>><<<><<>>>><<>>><<<<>>><>>><<<>><<<<>>>><<<>><<<>>>><>>>><<<><<<<>>>><>>>><<<<>>>><<<<><<>>>><<>>><>>>><<<<>>><>>><>><<<>>><>>>><<<<>><<>>><<<>>>><<>>><<><<<<><<<>><<><<>><<<><<><<<<>><<<<><<><<>>><<<>><<>>>><<>>><<>>>><<<<>>><<<>>><<>>>><<>>>><<<<>>><><>>>><<>>>><<>><<>>><<<>><<<>><>>><<<>><<<>><<<>>><<<<><<<<>>><<<<>>>><<<>>><<>><<>>><<<><<><<>><<<<>><<><<<<>><<<<>>>><>>>><><<<>>>><<<<>>><>><<<>>>><<>>>><>>><<<>><>>>><>><>>>><<<<>>><<><><<<>>><<<<>>>><<<><>><>><<<>>>><>>>><>>>><><<<<>><<<<><><<<>>>><<>>><<<<>>><<<>>>><>>><<><<>>>><<>><<>><<<<>>>><<>>>><><<<<><<><<<<>><<>><<<<><<<><<<<>>>><<<>><<<<>><<<<>>>><<>>><<<>><>>><>>><<>><>>>><><<>><<<><<>>>><<>>><<>>><<>>><<<<>>>><<>>><>><>>><<<><<<>><<>>>><<<<>>>><<<<>>>><<>>><<<>>>><<<<>><<<<>>>><>>>><>>><>>>><<<<>><><<><<<<>>><<<>>><<>>>><>><><<<>>>><<<<>>>><<>><<>><<<><<<<><<<<>><<<<>>>><>>>><>>>><<>>><<<>>><<<>>>><<>><<<>><<<><>>><<>>>><<<><>>>><><<<<><<>><><>><>><<<>><<>>>><<>>><<<><<>>>><<<<>>>><>>>><<<<>>><<<<>>><<><<<<>><>>>><<>>>><>>>><<<>>><>><<<>><<><<<<>><<<>>>><<<<>><<<<>>><<<>>><<<>>>><<<<>>><<<>><<<<>>><<<>>>><>>>><<><>><<>>>><<<<>>><><<<<>>><><>>>><>><<<<>>><<<<>>>><<><<<>>><>>>><<<>><<>>>><<<<>><><<>>><<>>>><>><<<><<>>><<<>>><<<<>><><<><><<<<>><<<<>><<>>><<<>>>><<<<>><<<>><<<>>><<><<<<>>><<<>>><>><>>><>><>><<<<>>>><>><<<<>><<>>>><>>>><>>>><<<<>>><<<<><<>>><>>><<<<>>>><<<>>>><<>>>><<<><<<><<<<><>>>><<<>><<<>>>><<<<>><<>>><<<>>>><<<><<<>>><<><><<>>><<<>><<<<><<<<>>><<><<<>><><>>>><<>><<<<><<<<>><<<><<><<<<>>>><<>>>><<<<>><<<>>><<><>>>><<>><>><<<<>><<<>>>><>><<<<>>><><<<><<>>><>>>><<<<>>><<<><>>><>>>><<<<>>><<>><<>>><<<<><<<<>><<><<><<>><>>><<<>>>><>>><>>>><<<<><<>><>>><<<>>><>>>><<<<>>>><<>>><>>><<<<>>>><<>>>><<<>>><<<>>>><<<>><>>><<>>><<<><<<<>>>><<<>>><<>><<<<>><>>>><<>>><<<<>><<<>>>><<>>>><<>><><<<<>>><<<<>><<<>><<<<>>>><<>>><<><<>>><<>><>><>>>><<<<><<>>><<<<><<<<>><<><<>>><<<>>><<<<>><<<<>>><>><<<<>>><<<>>>><>>><>><<<>>><<>>>><<<<>>>><<>>><<<<>><<><>>><<>>><<<<>>><<<<><<>><<<<><<<>>>><<>>>><>><<<><<<<>>>><<<<>><<<<><<>>>><<<>>>><>>><>><<<<><<<<>>>><<<>>><<<>>>><><>>><<<<><<<<>>>><<<>>><<>>>><<><>><<><<<<>>>><>>>><<<>><<<>><<<<>>><<<<>><<<>><>>><<<>>>><<<<>><<<<>>>><<>>><<<>>>><<<<>>>><<<>><>><<>><><<<<>><<><><<>><<>><<<<>>><<>>>><<<<>>>><<><<<<>>>><<<>><<<<>>>><<<>>><<><>>>><<<>>><>>>><<<<>>>><>><<><<<<>>><<>>><<<<>><<<>>>><<>>>><<<><<<>>>><<<<><<<>><<<<>>><<<>><<<><<<>><>>><<<<>>><<<>>><<<>><<<>>>><<<<>>><<<<>>>><<<<>><<<<><<<>>><><<<>><<<>><<<>><<<>>><<<><<<>>>><<<>><<<<>>>><><<<<>><<<<>>><<<<>><<><<<>>>><>>><><<<<>>><>>><<<<>>>><<<<>>><<<>>>><><<>><><<><<<<><<<<>>><>><>>>><<<<><<<<>><<<><>>>><<>>><<><<>>><<>>>><<<<>>>><<><>>>><<<<><<>><<><<>><<<<>>><<<<>><<<<>>>><>><<><<<>>>><<<>><<>>>><<<><<<<>>>><<<>>><<>><<<>>>><<>><<<<>>>><<<<>><<<>>>><>><<<<><<<>>>><<<><<<>><>>><<>>>><<<<>>><<<><<><>><<><>><<<><><<<><<<<>>><<>><<<><<>><<<><<<>><<<>>><>>>><<<>>>><<<<>>>><<<>><>><<>>><<<><>>><<<>><<<><<>><>>>><><>>>><<<>>><<<>>>><>>><<<<>>><>>>><<<>>>><<>>><<>>>><<>><><>>>><<<>>>><>>><>><<>>><<>>>><>><<>>><<><>>>><<<>><<>>><><<<>><<>>>><<<<>>>><>>><<<<>><>>><<>><<><<<>>><>><<<><<>><<>>><<><><<<<>>>><<<>>><>>>><>><<<>>><<<>>><<<<>>>><><<<<>>><<<<><<<>><<<<>>>><>>>><<>><<<<>>>><<>>><>><<><<<>>><<<>>>><<<<>>><<<>>><>>><<<>>><<<<>><<<><<>>>><><<><<>><>><<<<>>>><>><<>><<<<>>><<>>>><<<>><<<>>><<<>>><<<<>>><<<<>>>><<<<>><>>>><<<<>>>><>>>><>>><<<<><<<<>>><><<>>><<>>>><<<<>><<<<>>><<<>><<<>>>><<<<>>><<<>>>><<<><>>>><>>><<>>>><<<><<<><>>>><<<>>>><<>>>><>>>><<><<<<>><<<<><>>>><<><<<<>>>><>>><<<<>>><<>>>><<<><<<<><><<>>><<<>>><<>><<<>>>><>>>><<<<>>>><<<>>><<<>><<><<<>>>><<<<>><<<>>><>>><>><<<>>>><<<<>>>><<><<<>>>><>>>><<<>>>><<>><<<<>>><<<>>><><><<<<>>>><<<>>>><><<>><<>>>><<<<>>>><<<><<>>>><>>><<<<>><<>><<<>><><<<<>>><><<<>>>><<<><<<>>><<<<>><<<<>>>><<<>>>><<>><<<>>><<<<>>><><<>><<<<>>>><<<<>>><<>>><<<<><>><>>><<<<><>>>><<>><>><<<>>>><<<>>><<>><<><>>>><<<>>>><<<<>>>><<>>>><<<<>>>><<<>>>><<<>><<<>>><>>><>>><>>>><<>>>><<<>>><<<<>>><<>><<<><<<<>><>>><<<>>><<<>>><><<>>><>>>><<<<>>><<>>>><<<>>>><<<<>>><<<<>>>><<<>>><<><<>>><<>>>><<<>>><<><<<>>>><><<<<><><<><<>><>>>><<>>><><<><<<<>>><<<>>><<<<>>>><>><<<<>><<<<>><<><<<>>><>>>><>>>><<<<>>>><<<<><><<<><>>><<<<>><>><><<<<>>><<<><<><<<<>><<><>>>><>>>><<<>>>><<><<>>><<>><<<<>>><<<<>>>><>>>><<<<>><<>>><<<>>>><<<>>>><<<>>>><<<<>>><<<><<<><>>><<<><>>><<<><>>><>><<<>>><<<>>><<<<>>>><<>><<<>><>><<<<>>><<<>>>><<><<<>>>><<<<><><>>>><<>><>>>><<>>><<>>>><<>>>><>>><>>><<<>>><<>>><>><>>>><<<>>><>><>>>><<<>>><<><<<>>>><<<>><<><<<>>><<<<>>><<<<><<<<>>>><<<>><<<<>>><<<<>>><<>><<<<><<<><<<<>>>><<<<><>>>><>>>><<><<<<>><<>><<>>><>>><>>>><<<>>>><>><<<<>>>><<<<>><<<<>><<<>><<<<><>>>><>><<<>>><>><>>><>>><<<<>>><<>><<<>>><<<<>>><<><<<>>><<<>>>><<>>><<<<>><<<<>>><<><<>>><<<<>>><<<>>><<<<>>><<>>><<<>><<<>>>><<<>><<<<>>>><<>><>>>><<>>><>><<<>><<<<>>>><<>><<<<><<<>>>><<<>>><<>><<<>>>><<>>><<<<>><<>><<>><<<<>>>><<<>>><<<<>>>><<<>>><>>>><<<>>>><<>><<<<>><<>>>><<<<><<<>><<<<><<>>>><<<<>>>><<>>><<<<><<<>>>><<<>><<><<<<><><<>>>><><<<<><<<><<<<>><<><<<<><<<<>><<<>><<>><<<<><<>>><<><<<>><<>>><<<>>>><<>><<>><<<<>>><<<<>><<>>>><<<>>><<<<>><<>>><<><><<><<>>>><>><>>><<<><<<<>><<><<>>><<<<><<>>><>>>><<<><<><<>>>><><>>>><<>><<><>>><<><<<<>><<>>>><<>>><<<>>>><<<><>>><<>>>><>><<><<>><<<><<<>><<>><>><><><<>>>><<<>>><>>><<<<>>><<<>>><<<>><>>><<<<>><><<<><>>>><<>>><>>><<<>>><<<>><>>>><<>>><<<><<<>>>><><<<<>>><<<<>><<>><<<><<<<>><<<>>>><<<><>><<<<><<<<>>><<<>>>><<<<><<<>>><>>>><<<<>>><<><<>>>><<><<>><<>><>><<>>>><<<<>>><>>>><<>>>><<><<<>>><>>><<<>>>><<<<>><<<<><<<><<<><<<><<<>>>><<><<><><>><>>><<<>><>>><<<><>>><<>>><<<<><<<>>><<<<>>><<<<>>><<>>>><<<>>>><<<>><<<<><<<<>><<<><<<><<<>><<>>>><<<>><<<><>>><>>><<><<<>>><<<<>><<<>>>><>><<<>><>>><><<<><<<<><<<><<<>>><<><<>>>><<>>><><<<<>>>><<<>>>><<>><<<>><<>>><<><<<>><<>><<>><<<<>><<<<>><<<>>>><>>>><<>>><<<<><<>><<<>><<>>>><<<<>>><>><>><<<>>>><>>><<<>>><<>><<<<>><<><<<><<<<>><<<<><>><<<>>>><<<>>>><<>>><>><<>>>><<<>><<<>>>><><<<><<>><>><<>><<>>>><<>>><<<<><<><>>><><<<>>><<>>><<<>>><<<>>>><>>><<<<>>>><<<>>><<>><<<>>><<<>>><>>>><<><<<<>>>><<<><<<<>>><<<<>>><>><<<>>>><<><<><<<>>>><><<<>><<<<><<<>>><>>><>><<><<>><<<<>>>><>>><><<<<>>><<>><<<>>><><<<>>>><<<<>>><<>><<<><<><<<<>>>><<<>>>><<<>>>><><>><<<>>>><<><>>>><<<<>>>><<<>>>><<>>><<<<>>>><>>><>>><<>>>><<<><<>>>><><<<<>><<<>>>><<><<<<>>>><<>>>><><<<>>>><>><<<>>>><<>>><<>>><><<<>>><<<>><><<<<>>><<>>>><>>><<<>>><<>>>><<>><<<<><<>><<<>><<<<>>><>><<<<>>><<<>>>><>>>><<<>>>><>>><<<<>>><>><<<<><<<>><>>><>>>><<>>>><<>><<<>><<>>><<<>><<<<><<>><<<<>><<<<>><<<><>>>><>><><<<><<><>>><<<<><<<>><<>>><>>><<<<>><<<><<<>><>>>><<<<><><<>><<<<>><<<<>><>>>><><<<><>>><<<<>>>><<<>>><<>>>><<<>><<<>><>><<<><<<<>>><<<>>>><<<<>>>><<<>><<<<>>><>><<<<>><><<<<>><><<<<>><<>><<<<>>><>>>><<<<>>>><>>><>><>>>><<<>>>><><<<><<<>><<<<>>><<<<>><<<>>><<<<><<<>>><<<>>><><>>>><<<><<<<><<<>><<<<>>><<><<<<>><>>><<<<>>><>><>>>><><<<>>>><<><>>>><<><<<>>><<>>><<<<><>>><<><<>>><<<>>><><<<>>><>>><<<<>>>><<<>>>><<>>><<<<>>>><<>><<<<>><<<<><<>><<<<><<<>>>><<<><>>>><<>>>><<<>>>><<<>><<<>>><<>>>><>>><<<<>><<<<>><>>><<<<>><<>>><<<<><<<<>><<<<>>><<>><<><<<>><<>>>><<<<>><<<<>>><>>>><<>><>>>><<<><<<<>>><>>>><<<>><<<<>><<>>><<<>><<><>><<><>>>><>>>><<<<><>>><>><<<<>>>><<<>>>><<<>>>><<<>>>><<<><<<>>><<<>><<<<><<<><<>><<<>>>><<<>>>><<<<><>>><<><<<<>>>><>><<>>>><<>>>><>>><<<>>>><<><<<<>>>><>><><<<<>><>>><>>>><<<>>><<<<>>><<<<><<<>>>><>><<<><>>><<<<>>><>><>>><<<>><>><<><<<>><>>>><<><<<>>>><><<<>>>><<>><<>>>><>><><<<<><<<>>>><<<><<<>><<<<>><<><<>><>>>><<<<>>>><>><<<<>>>><<<<><>>>><<<><<<<><>><<>><<<>>><>><<<<>>><><<<>>><>><<>><<>>>><<<<>>><<<>>>><<<<><>><<<><<<><<><<<><<<<>>>><><><<><<>>><<>>><<>><>>><>>>><<><<<><>>><<<<>><<><<>><<<<>><<>>>><<<>>>><>>><<<>>><<<>>><<<>><>><<<<>>>><<>>>><<<>>>><>><<<>>>><<<>>>><<<>>><<>><<>><<<<><<><>><><<>><<>>>><<<>><>>><><<><<<><<>><<>>><<<>>>><<><>>>><<<<><<>>><><<<<>><<<>><<<<><<><<>>><>><>>>><<>>>><<<>>><<>>>><<<<>>>><<<>>>><>>>><>>><<<><>><<><>><<<<>>><<<<>>>><<<<>>>><>><><<<>>>><<<<>><<>>>><<<<><><<<>>> diff --git a/17/solution.mjs b/17/solution.mjs new file mode 100644 index 0000000..690ce4f --- /dev/null +++ b/17/solution.mjs @@ -0,0 +1,290 @@ +import { readFileSync } from 'node:fs'; + +const input = readFileSync('input', 'utf-8'); + + +const shapePatterns = ` + #### # # # ## + ### # # ## + # ### # + # +`; + +function isTouching(coordA, coordB) { + return ( + (coordA[0] === coordB[0] && Math.abs(coordA[1] - coordB[1]) === 1) || + (coordA[1] === coordB[1] && Math.abs(coordA[0] - coordB[0]) === 1) + ); +} + +function isEqual(coordA, coordB) { + return coordA[0] === coordB[0] && coordA[1] === coordB[1]; +} + +function getAllConnected(coords, coordA) { + const connected = coords.filter(coordB => isTouching(coordA, coordB)); + if (!connected.length) { + return [coordA]; + } + const notConnected = coords.filter(coordC => + !isEqual(coordC, coordA) && + !connected.find(coordD => isEqual(coordC, coordD)) + ); + return [ + coordA, + ...connected + .flatMap(coordE => getAllConnected(notConnected, coordE)) + .filter((coordF, i, connectedCoords) => connectedCoords.findLastIndex( + coordG => isEqual(coordF, coordG) + ) === i) + ]; +} + +class Shape { + constructor(coords, id) { + this.id = id; + + if (!coords.length) { + throw new Error('Empty shape coords'); + } + + // Normalize coords + const minX = coords.reduce((min, [x, _]) => Math.min(min, x), Infinity); + const minY = coords.reduce((min, [_, y]) => Math.min(min, y), Infinity); + + coords = coords.map(([x, y]) => [x - minX, y - minY]); + this.coords = coords; + + this.width = 1 + coords.reduce((max, [x, _]) => Math.max(max, x), 0); + this.height = 1 + coords.reduce((max, [_, y]) => Math.max(max, y), 0); + } +} + +function getShapes(patterns) { + let shapeCoords = patterns + .split('\n') + .flatMap((line, y) => line + .split('') + .flatMap((c, x) => c === '#' ? [[x, y]] : []) + ); + + const shapes = []; + while (shapeCoords.length) { + const shape = getAllConnected(shapeCoords, shapeCoords[0]); + shapeCoords = shapeCoords.filter(coordA => !shape.find(coordB => + isEqual(coordA, coordB) + )); + shapes.push(shape); + } + + return shapes.map((coords, i) => new Shape(coords, i)); +} + + +class Chamber { + constructor(width) { + this.width = width; + this.rows = []; + this.placements = []; + } + + get height() { + return this.rows.length; + } + + get rockCount() { + return this.placements.length; + } + + // Test if a shape will collide with anything at the given coordinates + collides(shape, x, y) { + for (const coord of shape.coords) { + const gX = x + coord[0]; + const gY = y - coord[1]; + + if (gX < 0 || gX > this.width - 1 || gY < 0) { + return true; + } + + if (gY > this.rows.length - 1) { + continue; + } + + if (this.rows[gY][gX] !== ' ') { + return true; + } + } + return false; + } + + // Add a shape at the given coordinates + add(shape, x, y) { + const nRowsAdded = Math.max(0, y + 1 - this.rows.length); + if (nRowsAdded > 0) { + this.rows.push(...new Array(nRowsAdded).fill(' '.repeat(this.width))); + } + + const lastY = this.placements.length ? + this.placements[this.placements.length - 1].y : + 0; + + this.placements.push({ + shapeId: shape.id, + x, + y, + relativeY: y - lastY + }); + + for (const coord of shape.coords) { + const gX = x + coord[0]; + const gY = y - coord[1]; + this.rows[gY] = ( + this.rows[gY].slice(0, gX) + + '#' + + this.rows[gY].slice(gX + 1) + ); + } + } + + print() { + for (let i = this.rows.length - 1; i >= 0; i--) { + console.log(this.rows[i]); + } + } +} + +const shapes = getShapes(shapePatterns); + +function* jetGenerator() { + while (true) { + for (const jet of input.split('').filter(c => /[<>]/.test(c))) { + yield jet === '<' ? -1 : 1; + } + } +} + +function* rockGenerator() { + while (true) { + for (const shape of shapes) { + yield shape; + } + } +} + + +const chamber = new Chamber(7); + +const jets = jetGenerator(); +const rocks = rockGenerator(); + + +function processRock() { + const rock = rocks.next().value; + + let x = 2; + let y = chamber.height + 2 + rock.height; + + while (true) { + const jet = jets.next().value; + if (!chamber.collides(rock, x + jet, y)) { + x += jet; + } + + if (!chamber.collides(rock, x, y - 1)) { + y -= 1; + } else { + chamber.add(rock, x, y); + break; + } + } +} + + +while (chamber.rockCount < 2022) { + processRock(); +} + +console.log( + `The tower will be: ${chamber.height} units tall after 2022 rocks` +); + + +function findRepetition(source, isEqual) { + let halfSize = Math.floor(source.length / 2); + + while (halfSize > 0) { + let skip = false; + for (let i = 0; i < halfSize; i++) { + const first = source[source.length - (2 * halfSize) + i]; + const second = source[source.length - halfSize + i]; + if (!isEqual(first, second)) { + skip = true; + break; + } + } + if (!skip) { + return halfSize; + } + halfSize--; + } +} + +// Add rocks until a period of repetition can be identified +function findPeriodOfRepetition() { + while (true) { + const periodOfRepetition = findRepetition(chamber.placements, (p1, p2) => + p1.shapeId === p2.shapeId && + p1.x === p2.x && + p1.relativeY === p2.relativeY + ); + if (periodOfRepetition !== undefined) { + return periodOfRepetition; + } + // Add 1000 rocks + for (let i = 0; i < 1000; i++) { + processRock(); + } + } +} + +const periodOfRepetition = findPeriodOfRepetition(); +let changeInHeight; + +// Confirm period of repetition +for (let round = 0; round < 5; round++) { + const initialHeight = chamber.height; + + // Add period of repetition rocks + for (let i = 0; i < periodOfRepetition; i++) { + processRock(); + } + + const change = chamber.height - initialHeight; + if (changeInHeight === undefined) { + changeInHeight = change; + } else { + if (changeInHeight !== change) { + throw new Error( + `Unable to confirm period of repetition, expected change in height ` + + `of: ${changeInHeight}, got ${change}` + ); + } + } +} + +const rockTarget = 1000000000000; + +const rocksRemaining = rockTarget - chamber.rockCount; +const multiple = Math.floor(rocksRemaining / periodOfRepetition); +const remainder = rocksRemaining % periodOfRepetition; + +// Add remaining rocks +for (let i = 0; i < remainder; i++) { + processRock(); +} + +const targetRockHeight = chamber.height + multiple * changeInHeight; + +console.log( + `The tower will be: ${targetRockHeight} units tall after ${rockTarget} rocks` +);