-
Notifications
You must be signed in to change notification settings - Fork 0
/
22.mjs
127 lines (104 loc) · 3.21 KB
/
22.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import { readInput } from "./utils.mjs";
const input = readInput(import.meta);
const insortDescByMaxZ = (arr, el) => {
arr.push(el);
for (let i = arr.length - 1; i > 0 && arr[i][2][1] > arr[i - 1][2][1]; i--) {
let tmp = arr[i];
arr[i] = arr[i - 1];
arr[i - 1] = tmp;
}
return arr;
};
const liesOn = ([a1, a2], [b1, b2]) => {
const [p1, p2] = [Math.max(a1, b1), Math.min(a2, b2)];
return p2 > p1;
};
const settleBricks = (input) => {
const lowestZ = 1;
const fallingBlocks = input
.split("\n")
.map((line) => {
const [[x1, y1, z1], [x2, y2, z2]] = line
.split("~")
.map((pos) => pos.split(",").map(Number));
return [
// assuming [min-max] segments for all blocks, converting to [-----)
[x1, x2 + 1],
[y1, y2 + 1],
[z1, z2 + 1],
];
})
.sort(([, , [lZ1]], [, , [lZ2]]) => lZ1 - lZ2); // sort ascending
const settledBlocks = [];
const holds = {};
const heldBy = {};
while (fallingBlocks.length) {
const fBlock = fallingBlocks.shift(); // Retrieve lowest block
let settlingZ = lowestZ;
const matchingSBlockKeys = [];
for (
let i = 0;
i < settledBlocks.length && settledBlocks[i][2][1] >= settlingZ;
i++
) {
const sBlock = settledBlocks[i];
if (liesOn(fBlock[0], sBlock[0]) && liesOn(fBlock[1], sBlock[1])) {
// intersects x and y
settlingZ = sBlock[2][1]; // upper z of settled block
matchingSBlockKeys.push(JSON.stringify(sBlock));
}
}
fBlock[2] = [settlingZ, settlingZ + fBlock[2][1] - fBlock[2][0]];
const fBlockKey = JSON.stringify(fBlock);
matchingSBlockKeys.forEach((sBlockKey) => {
(heldBy[fBlockKey] ??= []).push(sBlockKey);
(holds[sBlockKey] ??= []).push(fBlockKey);
});
insortDescByMaxZ(settledBlocks, fBlock);
}
return { settledBlocks, holds, heldBy };
};
const solve1 = (input) => {
const { settledBlocks, holds, heldBy } = settleBricks(input);
let result = 0;
for (const block of settledBlocks) {
const blockKey = JSON.stringify(block);
if (
!(blockKey in holds) ||
holds[blockKey].every((heldBlockKey) => heldBy[heldBlockKey].length > 1)
) {
result += 1;
}
}
return result;
};
const calcFallenBlocks = (_blockKey, holds, heldBy) => {
const removedBlocks = new Set([_blockKey]);
const toRemoveBlocks = new Set([_blockKey]);
while (toRemoveBlocks.size) {
const blockKey = toRemoveBlocks.values().next().value;
toRemoveBlocks.delete(blockKey);
if (
blockKey in heldBy &&
heldBy[blockKey].every((heldByKey) => removedBlocks.has(heldByKey))
) {
// if all that held this were removed
removedBlocks.add(blockKey);
}
if (blockKey in holds) {
// add to toRemove set every block that was held by this one
holds[blockKey].forEach((heldKey) => toRemoveBlocks.add(heldKey));
}
}
return removedBlocks.size - 1;
};
const solve2 = (input) => {
const { settledBlocks, holds, heldBy } = settleBricks(input);
let result = 0;
for (const block of settledBlocks) {
result += calcFallenBlocks(JSON.stringify(block), holds, heldBy);
}
return result;
};
console.log(solve1(input));
console.log(solve2(input));