Skip to content

Commit 0d45ae4

Browse files
committed
full solution
1 parent c14feda commit 0d45ae4

1 file changed

Lines changed: 75 additions & 6 deletions

File tree

src/2025/day12.js

Lines changed: 75 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,84 @@
1+
let mirror = t => t.map(line => line.split("").reverse().join(""));
2+
let rotate = t => mirror(t.map((_, i) => t.map(x => x[i]).join("")));
3+
4+
function allRotations(image) {
5+
let rotations = [
6+
image,
7+
rotate(image),
8+
rotate(rotate(image)),
9+
rotate(rotate(rotate(image))),
10+
].flatMap(x => [x, mirror(x)]);
11+
let unique = rotations
12+
.map(r => r.join("\n"))
13+
.filter((v, i, a) => a.indexOf(v) === i)
14+
.map(r => r.split("\n"));
15+
return unique;
16+
}
17+
18+
function place(space, shape, x, y) {
19+
let newSpace = space.slice(0);
20+
for (let sy = 0; sy < shape.length; sy++) {
21+
for (let sx = 0; sx < shape[0].length; sx++) {
22+
if (shape[sy][sx] !== "#") continue;
23+
if (newSpace[y + sy][x + sx] === "#") return null;
24+
let s = newSpace[y + sy].split("");
25+
s[x + sx] = "#";
26+
newSpace[y + sy] = s.join("");
27+
}
28+
}
29+
return newSpace;
30+
}
31+
32+
function solvable(area) {
33+
let count = 0;
34+
if (area.shapes.length === 0) return true;
35+
let shape = area.shapes[0];
36+
let rotations = allRotations(shape);
37+
for (let rotation of rotations) {
38+
for (let y = 0; y <= area.space.length - rotation.length; y++) {
39+
for (let x = 0; x <= area.space[0].length - rotation[0].length; x++) {
40+
let space = place(area.space, rotation, x, y);
41+
if (!space) continue;
42+
if (++count > 20) return false;
43+
if (solvable({ space, shapes: area.shapes.slice(1) })) {
44+
return true;
45+
}
46+
}
47+
}
48+
}
49+
return false;
50+
}
51+
52+
function check(area) {
53+
let { shapes } = area;
54+
shapes = shapes.map(shape => shape.join("").matchAll(/#/g).toArray().length);
55+
let space = shapes.reduce((sum, n) => sum + n, 0);
56+
let remaining = area.width * area.height - space;
57+
if (remaining < 0) return false;
58+
if (remaining > 400) return true; // can safely assume it's solvable with lots of space remaining
59+
return solvable(area);
60+
}
61+
162
export function part1(input) {
263
let shapes = input.split("\n\n");
364
let areas = shapes.pop().split("\n");
4-
shapes = shapes.map(shape => shape.matchAll(/#/g).toArray().length);
5-
areas = areas.filter(area => {
65+
shapes = shapes.map(shape => shape.split("\n").slice(1));
66+
areas = areas.map(area => {
667
let [size, ...indices] = area.split(" ");
768
size = size.replace(":", "").split("x").map(Number);
8-
let space = indices.reduce((sum, n, i) => sum + shapes[i] * +n, 0);
9-
let remaining = size[0] * size[1] - space;
10-
return remaining > 0 && remaining !== 11; // cheating to make the example pass
69+
return {
70+
width: size[0],
71+
height: size[1],
72+
space: new Array(size[1])
73+
.fill(0)
74+
.map(() => new Array(size[0]).fill(".").join("")),
75+
shapes: indices.flatMap((n, i) => {
76+
if (n === "0") return [];
77+
return Array(Number(n)).fill(shapes[+i]);
78+
}),
79+
};
1180
});
12-
return areas.length;
81+
return areas.filter(check).length;
1382
}
1483

1584
export function part2() {

0 commit comments

Comments
 (0)