|
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 | +} |
5 | 45 |
|
6 | 46 | export function part1(input, part2 = false) { |
7 | | - let regionId = 0; |
8 | 47 | 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; |
13 | 50 | for (let y = 0; y < map.length; y++) { |
14 | 51 | 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; |
54 | 57 | } |
55 | 58 | } |
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 | | - } |
73 | 59 | return sum; |
74 | 60 | } |
75 | 61 |
|
|
0 commit comments