diff --git a/2025/08/2025-08.run.xml b/2025/08/2025-08.run.xml new file mode 100644 index 0000000..64de728 --- /dev/null +++ b/2025/08/2025-08.run.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/2025/08/index.test.ts b/2025/08/index.test.ts new file mode 100644 index 0000000..9f61e45 --- /dev/null +++ b/2025/08/index.test.ts @@ -0,0 +1,31 @@ +import { describe, expect, it } from 'bun:test'; +import { solveFirst, solveSecond } from './index.ts'; + +describe('2025-08', () => { + const testInput = `162,817,812 +57,618,57 +906,360,560 +592,479,940 +352,342,300 +466,668,158 +542,29,236 +431,825,988 +739,650,466 +52,470,668 +216,146,977 +819,987,18 +117,168,530 +805,96,715 +346,949,466 +970,615,88 +941,993,340 +862,61,35 +984,92,344 +425,690,689`; + it('first', () => { + expect(solveFirst(testInput, 10)).toBe(40); + }); + it('second', () => { + expect(solveSecond(testInput)).toBe(25272); + }); +}); diff --git a/2025/08/index.ts b/2025/08/index.ts new file mode 100644 index 0000000..3967f18 --- /dev/null +++ b/2025/08/index.ts @@ -0,0 +1,51 @@ +import { multBy, uniqueIndexCombinations } from '../../utils/array.ts'; +import { euclideanDistanceSqrtless } from '../../utils/coordinates.ts'; + +export function solveFirst(input: string, count = 1000): number { + const junctions = input + .split('\n') + .map((row) => row.split(',').map(Number) as [number, number, number]); + + const edges = uniqueIndexCombinations(junctions) + .map( + ({ aI, bI }) => + [aI, bI, euclideanDistanceSqrtless(junctions[aI], junctions[bI])] as [ + number, + number, + number + ] + ) + .toSorted((a, b) => a[2] - b[2]); + + const circuits = junctions.map((_, i) => [i]); + + for (let i = 0; i < edges.length; i++) { + const [u, v] = edges[i]; + const circuitU = circuits.find((c) => c.includes(u))!; + const circuitV = circuits.find((c) => c.includes(v))!; + + if (i === count) + return multBy( + circuits.toSorted((a, b) => b.length - a.length).slice(0, 3), + (e) => e.length + ); + + // already in same circuit, ignore + if (circuitU === circuitV) continue; + + // merge v into u + circuitU.push(...circuitV); + circuits.splice(circuits.indexOf(circuitV), 1); + + // end condition for second + if (circuits.length === 1) { + return junctions[u][0] * junctions[v][0]; + } + } + + return -1; +} + +export function solveSecond(input: string): number { + return solveFirst(input, Number.MAX_SAFE_INTEGER); +} diff --git a/2025/08/run.ts b/2025/08/run.ts new file mode 100644 index 0000000..88783cd --- /dev/null +++ b/2025/08/run.ts @@ -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); diff --git a/utils/array.ts b/utils/array.ts index d587332..8a5def1 100644 --- a/utils/array.ts +++ b/utils/array.ts @@ -135,6 +135,13 @@ export function uniqueCombinations(arr: ReadonlyArray): { a: E; b: E }[] { arr.flatMap((b, bI) => (a !== b && aI > bI ? [{ a, b }] : [])) ); } +export function uniqueIndexCombinations( + arr: ReadonlyArray +): { aI: number; bI: number }[] { + return arr.flatMap((a, aI) => + arr.flatMap((b, bI) => (a !== b && aI > bI ? [{ aI, bI }] : [])) + ); +} /** * Returns a filter lambda to be used in array.filter() to only allow the diff --git a/utils/coordinates.ts b/utils/coordinates.ts index 2c5eab3..91f396f 100644 --- a/utils/coordinates.ts +++ b/utils/coordinates.ts @@ -1,4 +1,4 @@ -import { sumBy } from './array.ts'; +import { sumArray, sumBy } from './array.ts'; export const Sides = { TOP: 0, @@ -167,3 +167,13 @@ export function calculateVariance( coords.length ); } + +// TODO: add docs and tests + +export function euclideanDistanceSqrtless(a: number[], b: number[]): number { + return sumArray(a.map((d, i) => Math.pow(d - b[i], 2))); +} + +export function euclideanDistance(a: number[], b: number[]): number { + return Math.sqrt(euclideanDistanceSqrtless(a, b)); +}