Solve 2024-12

Add side-aware coordinate utils
This commit is contained in:
2024-12-12 19:19:44 +01:00
parent 3c9b48b3a6
commit feb1b40408
5 changed files with 266 additions and 3 deletions
+7
View File
@@ -0,0 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="2024-12" type="BunRunConfiguration">
<option name="program" value="2024/12/run.ts" />
<option name="workingDirectory" value="$PROJECT_DIR$" />
<method v="2" />
</configuration>
</component>
+78
View File
@@ -0,0 +1,78 @@
import { describe, expect, it } from 'bun:test';
import { getSides, solveFirst, solveSecond } from './index.ts';
describe('2024-12', () => {
it('first', () => {
expect(
solveFirst(`AAAA
BBCD
BBCC
EEEC`)
).toBe(140);
expect(
solveFirst(`OOOOO
OXOXO
OOOOO
OXOXO
OOOOO`)
).toBe(772);
expect(
solveFirst(`RRRRIICCFF
RRRRIICCCF
VVRRRCCFFF
VVRCCCJFFF
VVVVCJJCFE
VVIVCCJJEE
VVIIICJJEE
MIIIIIJJEE
MIIISIJEEE
MMMISSJEEE`)
).toBe(1930);
});
it('second', () => {
// it takes too long
// so only run while `NODE_ENV=production bun test --coverage`
if (process.env.NODE_ENV === 'production') {
expect(
solveSecond(`EEEEE
EXXXX
EEEEE
EXXXX
EEEEE`)
).toBe(236);
expect(
solveSecond(`AAAA
BBCD
BBCC
EEEC`)
).toBe(80);
expect(
solveSecond(`OOOOO
OXOXO
OOOOO
OXOXO
OOOOO`)
).toBe(436);
expect(
solveSecond(`AAAAAA
AAABBA
AAABBA
ABBAAA
ABBAAA
AAAAAA`)
).toBe(368);
}
});
it('sides', () => {
expect(
getSides([
[0, 0],
[1, 0],
[2, 0],
[0, 1]
])
).toBe(6);
});
});
+113
View File
@@ -0,0 +1,113 @@
import { sumArray } from '../../utils/array.ts';
import {
calculateSides,
type Coordinates,
getAdjacent,
getNeighbouringSides,
isCoordinateEqual
} from '../../utils/coordinates.ts';
function searchNeighbours(
visited: Set<number>,
rows: string[],
char: string,
x: number,
y: number,
found: Coordinates
) {
const position = y * rows.length + x;
if (visited.has(position)) {
return;
}
visited.add(position);
found.push([x, y]);
const { left, top, right, down } = getAdjacent(rows, x, y);
if (left === char) {
searchNeighbours(visited, rows, char, x - 1, y, found);
}
if (top === char) {
searchNeighbours(visited, rows, char, x, y - 1, found);
}
if (right === char) {
searchNeighbours(visited, rows, char, x + 1, y, found);
}
if (down === char) {
searchNeighbours(visited, rows, char, x, y + 1, found);
}
}
function groupChars(input: string) {
const rows = input.split('\n');
const groups: { char: string; coords: Coordinates }[] = [];
const visited = new Set<number>();
for (let y = 0; y < rows.length; y++) {
for (let x = 0; x < rows[y].length; x++) {
const position = y * rows.length + x;
if (visited.has(position)) {
continue;
}
const char = rows[y][x];
const coords: Coordinates = [];
searchNeighbours(visited, rows, char, x, y, coords);
groups.push({ char, coords });
}
}
return groups;
}
function getPerimeter(g: Coordinates): number {
if (g.length === 1) {
return 4;
}
if (g.length === 2) {
return 6;
}
const { uniqueSides } = calculateSides(g);
return uniqueSides.length;
}
export function solveFirst(input: string): number {
const groups = groupChars(input);
return sumArray(groups.map((g) => g.coords.length * getPerimeter(g.coords)));
}
export function solveSecond(input: string): number {
const groups = groupChars(input);
return sumArray(groups.map((g) => g.coords.length * getSides(g.coords)));
}
export function getSides(g: Coordinates): number {
if (g.length === 1) {
return 4;
}
if (g.length === 2) {
return 4;
}
const { uniqueSides } = calculateSides(g);
const visited = new Set<number>();
let sides = 0;
for (let i = 0; i < uniqueSides.length; i++) {
if (visited.has(i)) {
continue;
}
visited.add(i);
sides++;
const { neighbours } = getNeighbouringSides(uniqueSides[i], uniqueSides);
neighbours.forEach((c) =>
visited.add(uniqueSides.findIndex((v) => isCoordinateEqual(v, c)))
);
}
return sides;
}
+12
View File
@@ -0,0 +1,12 @@
import { join } from 'path';
import { solveFirst, solveSecond } from './index.ts';
const input = await Bun.file(join(__dirname, 'input.txt')).text();
const firstAnswer = solveFirst(input);
console.log(firstAnswer);
const secondAnswer = solveSecond(input);
console.log(secondAnswer);