From 875e5c1680137ca093c47828f108601293ee66ba Mon Sep 17 00:00:00 2001
From: Pascal Syma
Date: Wed, 10 Dec 2025 13:40:27 +0100
Subject: [PATCH] Solve 2025-09
---
2025/09/2025-09.run.xml | 7 ++++
2025/09/index.test.ts | 19 ++++++++++
2025/09/index.ts | 78 +++++++++++++++++++++++++++++++++++++++++
2025/09/run.ts | 12 +++++++
4 files changed, 116 insertions(+)
create mode 100644 2025/09/2025-09.run.xml
create mode 100644 2025/09/index.test.ts
create mode 100644 2025/09/index.ts
create mode 100644 2025/09/run.ts
diff --git a/2025/09/2025-09.run.xml b/2025/09/2025-09.run.xml
new file mode 100644
index 0000000..13b3bc2
--- /dev/null
+++ b/2025/09/2025-09.run.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/2025/09/index.test.ts b/2025/09/index.test.ts
new file mode 100644
index 0000000..25f40c3
--- /dev/null
+++ b/2025/09/index.test.ts
@@ -0,0 +1,19 @@
+import { describe, expect, it } from 'bun:test';
+import { solveFirst, solveSecond } from './index.ts';
+
+describe('2025-09', () => {
+ const testInput = `7,1
+11,1
+11,7
+9,7
+9,5
+2,5
+2,3
+7,3`;
+ it('first', () => {
+ expect(solveFirst(testInput)).toBe(50);
+ });
+ it('second', () => {
+ expect(solveSecond(testInput)).toBe(25);
+ });
+});
diff --git a/2025/09/index.ts b/2025/09/index.ts
new file mode 100644
index 0000000..df50126
--- /dev/null
+++ b/2025/09/index.ts
@@ -0,0 +1,78 @@
+import { uniqueCombinations } from '../../utils/array.ts';
+import type { Coordinate } from '../../utils/coordinates.ts';
+
+export function solveFirst(input: string): number {
+ const reds = input
+ .split('\n')
+ .map((r) => r.split(',').map(Number) as Coordinate);
+
+ const combs = uniqueCombinations(reds)
+ .map(
+ ({ a, b }) => (Math.abs(a[0] - b[0]) + 1) * (Math.abs(a[1] - b[1]) + 1)
+ )
+ .toSorted((a, b) => b - a);
+ return combs[0];
+}
+
+function calcArea(a: Coordinate, b: Coordinate) {
+ return (Math.abs(a[0] - b[0]) + 1) * (Math.abs(a[1] - b[1]) + 1);
+}
+
+export function solveSecond(input: string): number {
+ const reds = input
+ .split('\n')
+ .map((r) => r.split(',').map(Number) as Coordinate);
+
+ const lines: Line[] = [];
+ for (let i = 1; i < reds.length; i++) {
+ lines.push([reds[i - 1], reds[i]]);
+ }
+ lines.push([reds[reds.length - 1], reds[0]]);
+
+ let maxArea = 0;
+
+ for (let i = 0; i < reds.length; i++) {
+ for (let j = i + 1; j < reds.length; j++) {
+ if (reds[i][0] == reds[j][0] || reds[i][1] == reds[j][1]) continue;
+ const rectLines: Line[] = [
+ [reds[i], reds[j]],
+ [
+ [reds[i][0], reds[j][1]],
+ [reds[j][0], reds[i][1]]
+ ]
+ ];
+
+ if (
+ rectLines.some((rline) => lines.some((line) => intersects(rline, line)))
+ ) {
+ continue;
+ }
+
+ maxArea = Math.max(maxArea, calcArea(reds[i], reds[j]));
+ }
+ }
+
+ return maxArea;
+}
+
+/**
+ * Checks for intersection of two lines.
+ * @param abcd Line (a,b)->(c,d)
+ * @param pqrs Line (p,q)->(r,s)
+ *
+ * @see {@link https://stackoverflow.com/a/24392281/11271734|Source}
+ */
+export function intersects(abcd: Line, pqrs: Line) {
+ const [a, b, c, d] = abcd.flat();
+ const [p, q, r, s] = pqrs.flat();
+ const det = (c - a) * (s - q) - (r - p) * (d - b);
+ if (det === 0) {
+ return false;
+ } else {
+ const lambda = ((s - q) * (r - a) + (p - r) * (s - b)) / det;
+ const gamma = ((b - d) * (r - a) + (c - a) * (s - b)) / det;
+ return 0 < lambda && lambda < 1 && 0 < gamma && gamma < 1;
+ }
+}
+
+type Line = [Coordinate, Coordinate];
diff --git a/2025/09/run.ts b/2025/09/run.ts
new file mode 100644
index 0000000..88783cd
--- /dev/null
+++ b/2025/09/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);