Skip to content

Commit

Permalink
add examples and refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
shahata committed Dec 12, 2024
1 parent ceb7892 commit 74280f1
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 65 deletions.
116 changes: 51 additions & 65 deletions src/2024/day12.js
Original file line number Diff line number Diff line change
@@ -1,75 +1,61 @@
// AAAA
// BBCD
// BBCC
// EEEC
function countSides(walls) {
let sides = 0;
walls.forEach(cells => {
const points = [...cells].sort((a, b) => a - b);
for (let i = 0; i < points.length; i++) {
if (points[i] + 1 !== points[i + 1]) sides++;
}
});
return sides;
}

function walk(map, x, y) {
const queue = [{ x, y }];
const cells = new Set([`${x},${y}`]);
const walls = new Map();
let perimeter = 0;
while (queue.length > 0) {
const p = queue.shift();
const neighbors = [
{ x: p.x - 1, y: p.y },
{ x: p.x + 1, y: p.y },
{ x: p.x, y: p.y - 1 },
{ x: p.x, y: p.y + 1 },
];
neighbors.forEach(o => {
if (map[o.y]?.[o.x] === map[y][x]) {
if (!cells.has(`${o.x},${o.y}`)) {
cells.add(`${o.x},${o.y}`);
queue.push(o);
}
} else {
perimeter++;
if (o.x === p.x) {
const wall = `h,${p.y},${o.y}`;
walls.set(wall, (walls.get(wall) || new Set()).add(p.x));
} else {
const wall = `v,${p.x},${o.x}`;
walls.set(wall, (walls.get(wall) || new Set()).add(p.y));
}
}
});
}
return { cells, perimeter, sides: countSides(walls) };
}

export function part1(input, part2 = false) {
let regionId = 0;
const map = input.split("\n").map(line => line.split(""));
const cell2region = new Map();
const region2cells = new Map();
const region2walls = new Map();
const cell2perimeter = new Map();
let visited = new Set();
let sum = 0;
for (let y = 0; y < map.length; y++) {
for (let x = 0; x < map[y].length; x++) {
if (cell2region.has(`${x},${y}`)) continue;
const walls = new Map();
regionId++;
region2walls.set(regionId, walls);
region2cells.set(regionId, new Set());
let currentRegion = map[y][x];
const queue = [{ x, y }];
while (queue.length > 0) {
const p = queue.shift();
cell2region.set(`${p.x},${p.y}`, regionId);
region2cells.get(regionId).add(`${p.x},${p.y}`);
const neighbors = [
{ x: p.x - 1, y: p.y },
{ x: p.x + 1, y: p.y },
{ x: p.x, y: p.y - 1 },
{ x: p.x, y: p.y + 1 },
];
neighbors.forEach(o => {
if (map[o.y]?.[o.x] === currentRegion) {
if (!cell2region.has(`${o.x},${o.y}`)) {
cell2region.set(`${o.x},${o.y}`, regionId);
queue.push(o);
}
} else {
const perimeter = cell2perimeter.get(`${p.x},${p.y}`) || 0;
cell2perimeter.set(`${p.x},${p.y}`, perimeter + 1);

if (o.x === p.x) {
let wall = `horizontal,${p.y},${o.y}`;
if (!walls.has(wall)) walls.set(wall, new Set());
walls.get(wall).add(p.x);
} else {
let wall = `vertical,${p.x},${o.x}`;
if (!walls.has(wall)) walls.set(wall, new Set());
walls.get(wall).add(p.y);
}
}
});
}
if (visited.has(`${x},${y}`)) continue;
const { cells, perimeter, sides } = walk(map, x, y);
visited = visited.union(cells);
if (!part2) sum += cells.size * perimeter;
else sum += cells.size * sides;
}
}
let sum = 0;
for (const regionId of region2cells.keys()) {
const cells = region2cells.get(regionId);
const area = cells.size;
let perimeter = 0;
cells.forEach(cell => (perimeter += cell2perimeter.get(cell) || 0));
const walls = region2walls.get(regionId);
let sides = 0;
walls.forEach(cells => {
const points = [...cells].sort((a, b) => a - b);
for (let i = 0; i < points.length; i++) {
if (points[i] + 1 !== points[i + 1]) sides++;
}
});
if (!part2) sum += area * perimeter;
else sum += area * sides;
}
return sum;
}

Expand Down
54 changes: 54 additions & 0 deletions src/2024/day12.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,27 @@ describe("day12 2024", () => {
describe("part1", () => {
test("it should work for part 1 examples", () => {
expect(part1(["AAAA", "BBCD", "BBCC", "EEEC"].join("\n"))).toEqual(140);

expect(
part1(["OOOOO", "OXOXO", "OOOOO", "OXOXO", "OOOOO"].join("\n")),
).toEqual(772);

expect(
part1(
[
"RRRRIICCFF",
"RRRRIICCCF",
"VVRRRCCFFF",
"VVRCCCJFFF",
"VVVVCJJCFE",
"VVIVCCJJEE",
"VVIIICJJEE",
"MIIIIIJJEE",
"MIIISIJEEE",
"MMMISSJEEE",
].join("\n"),
),
).toEqual(1930);
});

test("it should work for part 1 input", () => {
Expand All @@ -17,6 +38,39 @@ describe("day12 2024", () => {
describe("part2", () => {
test("it should work for part 2 examples", () => {
expect(part2(["AAAA", "BBCD", "BBCC", "EEEC"].join("\n"))).toEqual(80);

expect(
part2(["OOOOO", "OXOXO", "OOOOO", "OXOXO", "OOOOO"].join("\n")),
).toEqual(436);

expect(
part2(["EEEEE", "EXXXX", "EEEEE", "EXXXX", "EEEEE"].join("\n")),
).toEqual(236);

expect(
part2(
["AAAAAA", "AAABBA", "AAABBA", "ABBAAA", "ABBAAA", "AAAAAA"].join(
"\n",
),
),
).toEqual(368);

expect(
part2(
[
"RRRRIICCFF",
"RRRRIICCCF",
"VVRRRCCFFF",
"VVRCCCJFFF",
"VVVVCJJCFE",
"VVIVCCJJEE",
"VVIIICJJEE",
"MIIIIIJJEE",
"MIIISIJEEE",
"MMMISSJEEE",
].join("\n"),
),
).toEqual(1206);
});

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

0 comments on commit 74280f1

Please sign in to comment.