Solve 2024-12
Add side-aware coordinate utils
This commit is contained in:
@@ -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>
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
Reference in New Issue
Block a user