Skip to content

Commit 74280f1

Browse files
committed
add examples and refactor
1 parent ceb7892 commit 74280f1

File tree

2 files changed

+105
-65
lines changed

2 files changed

+105
-65
lines changed

src/2024/day12.js

Lines changed: 51 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,61 @@
1-
// AAAA
2-
// BBCD
3-
// BBCC
4-
// EEEC
1+
function countSides(walls) {
2+
let sides = 0;
3+
walls.forEach(cells => {
4+
const points = [...cells].sort((a, b) => a - b);
5+
for (let i = 0; i < points.length; i++) {
6+
if (points[i] + 1 !== points[i + 1]) sides++;
7+
}
8+
});
9+
return sides;
10+
}
11+
12+
function walk(map, x, y) {
13+
const queue = [{ x, y }];
14+
const cells = new Set([`${x},${y}`]);
15+
const walls = new Map();
16+
let perimeter = 0;
17+
while (queue.length > 0) {
18+
const p = queue.shift();
19+
const neighbors = [
20+
{ x: p.x - 1, y: p.y },
21+
{ x: p.x + 1, y: p.y },
22+
{ x: p.x, y: p.y - 1 },
23+
{ x: p.x, y: p.y + 1 },
24+
];
25+
neighbors.forEach(o => {
26+
if (map[o.y]?.[o.x] === map[y][x]) {
27+
if (!cells.has(`${o.x},${o.y}`)) {
28+
cells.add(`${o.x},${o.y}`);
29+
queue.push(o);
30+
}
31+
} else {
32+
perimeter++;
33+
if (o.x === p.x) {
34+
const wall = `h,${p.y},${o.y}`;
35+
walls.set(wall, (walls.get(wall) || new Set()).add(p.x));
36+
} else {
37+
const wall = `v,${p.x},${o.x}`;
38+
walls.set(wall, (walls.get(wall) || new Set()).add(p.y));
39+
}
40+
}
41+
});
42+
}
43+
return { cells, perimeter, sides: countSides(walls) };
44+
}
545

646
export function part1(input, part2 = false) {
7-
let regionId = 0;
847
const map = input.split("\n").map(line => line.split(""));
9-
const cell2region = new Map();
10-
const region2cells = new Map();
11-
const region2walls = new Map();
12-
const cell2perimeter = new Map();
48+
let visited = new Set();
49+
let sum = 0;
1350
for (let y = 0; y < map.length; y++) {
1451
for (let x = 0; x < map[y].length; x++) {
15-
if (cell2region.has(`${x},${y}`)) continue;
16-
const walls = new Map();
17-
regionId++;
18-
region2walls.set(regionId, walls);
19-
region2cells.set(regionId, new Set());
20-
let currentRegion = map[y][x];
21-
const queue = [{ x, y }];
22-
while (queue.length > 0) {
23-
const p = queue.shift();
24-
cell2region.set(`${p.x},${p.y}`, regionId);
25-
region2cells.get(regionId).add(`${p.x},${p.y}`);
26-
const neighbors = [
27-
{ x: p.x - 1, y: p.y },
28-
{ x: p.x + 1, y: p.y },
29-
{ x: p.x, y: p.y - 1 },
30-
{ x: p.x, y: p.y + 1 },
31-
];
32-
neighbors.forEach(o => {
33-
if (map[o.y]?.[o.x] === currentRegion) {
34-
if (!cell2region.has(`${o.x},${o.y}`)) {
35-
cell2region.set(`${o.x},${o.y}`, regionId);
36-
queue.push(o);
37-
}
38-
} else {
39-
const perimeter = cell2perimeter.get(`${p.x},${p.y}`) || 0;
40-
cell2perimeter.set(`${p.x},${p.y}`, perimeter + 1);
41-
42-
if (o.x === p.x) {
43-
let wall = `horizontal,${p.y},${o.y}`;
44-
if (!walls.has(wall)) walls.set(wall, new Set());
45-
walls.get(wall).add(p.x);
46-
} else {
47-
let wall = `vertical,${p.x},${o.x}`;
48-
if (!walls.has(wall)) walls.set(wall, new Set());
49-
walls.get(wall).add(p.y);
50-
}
51-
}
52-
});
53-
}
52+
if (visited.has(`${x},${y}`)) continue;
53+
const { cells, perimeter, sides } = walk(map, x, y);
54+
visited = visited.union(cells);
55+
if (!part2) sum += cells.size * perimeter;
56+
else sum += cells.size * sides;
5457
}
5558
}
56-
let sum = 0;
57-
for (const regionId of region2cells.keys()) {
58-
const cells = region2cells.get(regionId);
59-
const area = cells.size;
60-
let perimeter = 0;
61-
cells.forEach(cell => (perimeter += cell2perimeter.get(cell) || 0));
62-
const walls = region2walls.get(regionId);
63-
let sides = 0;
64-
walls.forEach(cells => {
65-
const points = [...cells].sort((a, b) => a - b);
66-
for (let i = 0; i < points.length; i++) {
67-
if (points[i] + 1 !== points[i + 1]) sides++;
68-
}
69-
});
70-
if (!part2) sum += area * perimeter;
71-
else sum += area * sides;
72-
}
7359
return sum;
7460
}
7561

src/2024/day12.spec.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,27 @@ describe("day12 2024", () => {
77
describe("part1", () => {
88
test("it should work for part 1 examples", () => {
99
expect(part1(["AAAA", "BBCD", "BBCC", "EEEC"].join("\n"))).toEqual(140);
10+
11+
expect(
12+
part1(["OOOOO", "OXOXO", "OOOOO", "OXOXO", "OOOOO"].join("\n")),
13+
).toEqual(772);
14+
15+
expect(
16+
part1(
17+
[
18+
"RRRRIICCFF",
19+
"RRRRIICCCF",
20+
"VVRRRCCFFF",
21+
"VVRCCCJFFF",
22+
"VVVVCJJCFE",
23+
"VVIVCCJJEE",
24+
"VVIIICJJEE",
25+
"MIIIIIJJEE",
26+
"MIIISIJEEE",
27+
"MMMISSJEEE",
28+
].join("\n"),
29+
),
30+
).toEqual(1930);
1031
});
1132

1233
test("it should work for part 1 input", () => {
@@ -17,6 +38,39 @@ describe("day12 2024", () => {
1738
describe("part2", () => {
1839
test("it should work for part 2 examples", () => {
1940
expect(part2(["AAAA", "BBCD", "BBCC", "EEEC"].join("\n"))).toEqual(80);
41+
42+
expect(
43+
part2(["OOOOO", "OXOXO", "OOOOO", "OXOXO", "OOOOO"].join("\n")),
44+
).toEqual(436);
45+
46+
expect(
47+
part2(["EEEEE", "EXXXX", "EEEEE", "EXXXX", "EEEEE"].join("\n")),
48+
).toEqual(236);
49+
50+
expect(
51+
part2(
52+
["AAAAAA", "AAABBA", "AAABBA", "ABBAAA", "ABBAAA", "AAAAAA"].join(
53+
"\n",
54+
),
55+
),
56+
).toEqual(368);
57+
58+
expect(
59+
part2(
60+
[
61+
"RRRRIICCFF",
62+
"RRRRIICCCF",
63+
"VVRRRCCFFF",
64+
"VVRCCCJFFF",
65+
"VVVVCJJCFE",
66+
"VVIVCCJJEE",
67+
"VVIIICJJEE",
68+
"MIIIIIJJEE",
69+
"MIIISIJEEE",
70+
"MMMISSJEEE",
71+
].join("\n"),
72+
),
73+
).toEqual(1206);
2074
});
2175

2276
test("it should work for part 2 input", () => {

0 commit comments

Comments
 (0)