219 lines
5.2 KiB
TypeScript
219 lines
5.2 KiB
TypeScript
import { DayFunc } from "..";
|
|
|
|
const blocks = [
|
|
[["@", "@", "@", "@"]],
|
|
[
|
|
[".", "@", "."],
|
|
["@", "@", "@"],
|
|
[".", "@", "."],
|
|
],
|
|
[
|
|
[".", ".", "@"],
|
|
[".", ".", "@"],
|
|
["@", "@", "@"],
|
|
],
|
|
[["@"], ["@"], ["@"], ["@"]],
|
|
[
|
|
["@", "@"],
|
|
["@", "@"],
|
|
],
|
|
];
|
|
|
|
function PrintGrid(grid: string[][]) {
|
|
for (let i = grid.length - 1; i >= 0; i--) {
|
|
for (let j = 0; j < grid[0].length; j++) {
|
|
process.stdout.write(grid[i][j]);
|
|
}
|
|
process.stdout.write("\n");
|
|
}
|
|
process.stdout.write("++++++++++++++++++++++++++++\n");
|
|
}
|
|
|
|
function MoveDown(
|
|
grid: string[][],
|
|
block: string[][],
|
|
[x, y]: [number, number]
|
|
): boolean {
|
|
// Moving through the floor.
|
|
if (y - block.length + 1 === 0) return false;
|
|
for (let i = block.length - 1; i >= 0; i--) {
|
|
for (let j = 0; j < block[0].length; j++) {
|
|
if (block[i][j] === "@" && grid[y - i - 1][j + x] === "#") {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// No collision. Clear block.
|
|
for (let i = block.length - 1; i >= 0; i--) {
|
|
for (let j = 0; j < block[0].length; j++) {
|
|
if (block[i][j] === "@") {
|
|
grid[y - i][j + x] = ".";
|
|
}
|
|
}
|
|
}
|
|
y--;
|
|
for (let i = block.length - 1; i >= 0; i--) {
|
|
for (let j = 0; j < block[0].length; j++) {
|
|
if (block[i][j] === "@") {
|
|
grid[y - i][j + x] = "@";
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function MoveSides(
|
|
grid: string[][],
|
|
block: string[][],
|
|
[x, y]: [number, number],
|
|
unit: -1 | 1
|
|
): boolean {
|
|
// Goes off the sides
|
|
if (x + unit < 0 || x + block[0].length + unit > grid[0].length) return false;
|
|
for (let i = block.length - 1; i >= 0; i--) {
|
|
for (let j = 0; j < block[0].length; j++) {
|
|
if (block[i][j] === "@" && grid[y - i][j + x + unit] === "#") {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// No collision. Clear block.
|
|
for (let i = block.length - 1; i >= 0; i--) {
|
|
for (let j = 0; j < block[0].length; j++) {
|
|
if (block[i][j] === "@") {
|
|
grid[y - i][j + x] = ".";
|
|
}
|
|
}
|
|
}
|
|
x += unit;
|
|
for (let i = block.length - 1; i >= 0; i--) {
|
|
for (let j = 0; j < block[0].length; j++) {
|
|
if (block[i][j] === "@") {
|
|
grid[y - i][j + x] = "@";
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function SettleBlock(
|
|
grid: string[][],
|
|
block: string[][],
|
|
[x, y]: [number, number]
|
|
) {
|
|
for (let i = block.length - 1; i >= 0; i--) {
|
|
for (let j = 0; j < block[0].length; j++) {
|
|
if (block[i][j] === "@") {
|
|
grid[y - i][j + x] = "#";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function* BlockGen(start = 0, end = Infinity, step = 1) {
|
|
for (let i = start; i < end; i += step) {
|
|
yield { block: blocks[i % blocks.length]!, index: i % blocks.length };
|
|
}
|
|
}
|
|
|
|
function CalcHeight(grid: string[][]) {
|
|
let e = 0;
|
|
for (let i = grid.length - 1; i >= 0; i--) {
|
|
if (grid[i].some((j) => j === "#")) {
|
|
break;
|
|
}
|
|
e++;
|
|
}
|
|
return grid.length - e;
|
|
}
|
|
|
|
export const Day17: DayFunc = (input) => {
|
|
const parsed = input.trim().split("");
|
|
const gen = BlockGen();
|
|
|
|
const grid: string[][] = [];
|
|
let jet = 0;
|
|
let part1: number;
|
|
let addedOnHeight = 0;
|
|
|
|
const depthMap: Record<string, {height: number; index: number}> = {};
|
|
|
|
for (let i = 0; i < 1e12; i++) {
|
|
if (i === 2022) {
|
|
part1 = CalcHeight(grid);
|
|
}
|
|
|
|
const g = gen.next().value;
|
|
if (!g) return;
|
|
const block = g.block;
|
|
|
|
// Not right, not necessarily the top row.
|
|
let emptyRows = 0;
|
|
let rock = -1;
|
|
for (let c = grid.length - 1; c >= 0; c--) {
|
|
if (grid[c].some((i) => i === "#")) {
|
|
rock = c;
|
|
break;
|
|
}
|
|
emptyRows++;
|
|
}
|
|
if (emptyRows < 3 + block.length) {
|
|
for (let c = 0; c <= 2 + block.length - emptyRows; c++) {
|
|
grid.push([".", ".", ".", ".", ".", ".", "."]);
|
|
}
|
|
}
|
|
const topLeft: [number, number] = [2, rock + 3 + block.length];
|
|
|
|
for (let j = block.length - 1; j >= 0; j--) {
|
|
const newRow = [".", ".", ...block[j]];
|
|
for (let k = 0; k < 5 - block[j].length; k++) {
|
|
newRow.push(".");
|
|
}
|
|
grid[rock === -1 ? 3 - j : block.length - j + rock + 3] = newRow;
|
|
}
|
|
|
|
let movedDown = true;
|
|
do {
|
|
if (parsed[jet % parsed.length] === "<") {
|
|
const moved = MoveSides(grid, block, topLeft, -1);
|
|
if (moved) topLeft[0]--;
|
|
} else {
|
|
const moved = MoveSides(grid, block, topLeft, 1);
|
|
if (moved) topLeft[0]++;
|
|
}
|
|
jet++;
|
|
movedDown = MoveDown(grid, block, topLeft);
|
|
if (movedDown) {
|
|
topLeft[1]--;
|
|
}
|
|
} while (movedDown);
|
|
SettleBlock(grid, block, topLeft);
|
|
|
|
const depth = [0, 0, 0, 0, 0, 0, 0];
|
|
for (let x = 0; x < 7; x++) {
|
|
for (let y = grid.length - 1; y >= 0; y--) {
|
|
if (grid[y][x] === '#') {
|
|
depth[x] = grid.length - y;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
const key = `${g.index},${jet % parsed.length},${JSON.stringify(depth)}`;
|
|
if (key in depthMap) {
|
|
const height = CalcHeight(grid);
|
|
const mapEntry = depthMap[key];
|
|
const diff = height - mapEntry.height;
|
|
const cycleNum = Math.floor((1e12 - i) / (i - mapEntry.index));
|
|
i += cycleNum * (i - mapEntry.index);
|
|
addedOnHeight += diff * cycleNum;
|
|
} else {
|
|
depthMap[key] = { height: CalcHeight(grid), index: i };
|
|
}
|
|
|
|
}
|
|
|
|
return [part1, CalcHeight(grid) + addedOnHeight];
|
|
};
|