diff --git a/2024/23/2024-23.run.xml b/2024/23/2024-23.run.xml
new file mode 100644
index 0000000..d99eb4d
--- /dev/null
+++ b/2024/23/2024-23.run.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/2024/23/index.test.ts b/2024/23/index.test.ts
new file mode 100644
index 0000000..a1d83f5
--- /dev/null
+++ b/2024/23/index.test.ts
@@ -0,0 +1,43 @@
+import { describe, expect, it } from 'bun:test';
+import { solveFirst, solveSecond } from './index.ts';
+
+describe('2024-23', () => {
+ const testInput = `kh-tc
+qp-kh
+de-cg
+ka-co
+yn-aq
+qp-ub
+cg-tb
+vc-aq
+tb-ka
+wh-tc
+yn-cg
+kh-ub
+ta-co
+de-co
+tc-td
+tb-wq
+wh-td
+ta-ka
+td-qp
+aq-cg
+wq-ub
+ub-vc
+de-ta
+wq-aq
+wq-vc
+wh-yn
+ka-de
+kh-ta
+co-tc
+wh-qp
+tb-vc
+td-yn`;
+ it('first', () => {
+ expect(solveFirst(testInput)).toBe(7);
+ });
+ it('second', () => {
+ expect(solveSecond(testInput)).toBe('co,de,ka,ta');
+ });
+});
diff --git a/2024/23/index.ts b/2024/23/index.ts
new file mode 100644
index 0000000..6041d32
--- /dev/null
+++ b/2024/23/index.ts
@@ -0,0 +1,63 @@
+import { uniqueCombinations } from '../../utils/array.ts';
+
+export function solveFirst(input: string): number {
+ const connections = extractConnections(input);
+
+ const found = new Set();
+ for (let key in connections) {
+ if (!key.startsWith('t')) {
+ continue;
+ }
+ getTriangles(connections, key).forEach((t) => found.add(t));
+ }
+
+ return found.size;
+}
+
+function getTriangles(connections: Record, key: string) {
+ const tripplePairs = uniqueCombinations(connections[key]).filter(({ a, b }) =>
+ connections[a].includes(b)
+ );
+ return tripplePairs.map(({ a, b }) => [key, a, b].toSorted().join(','));
+}
+
+function extractConnections(input: string) {
+ const connections: Record = {};
+ const pairs = input.split('\n').map((r) => r.split('-') as [string, string]);
+
+ pairs.forEach(([a, b]) => {
+ connections[a] = [...(connections[a] || []), b];
+ connections[b] = [...(connections[b] || []), a];
+ });
+ return connections;
+}
+
+export function solveSecond(input: string): string {
+ const connections = extractConnections(input);
+
+ const triples = new Set();
+ for (let key in connections) {
+ getTriangles(connections, key).forEach((t) => triples.add(t));
+ }
+ const triangles = [...triples];
+
+ let maxSize = 0;
+ const triaggs: string[][] = [];
+ for (let key in connections) {
+ const triags = triangles.filter((t) => t.includes(key));
+
+ if (triags.length > maxSize) {
+ maxSize = triags.length;
+ }
+ triaggs.push(triags);
+ }
+ const notInMax = new Set(
+ triaggs
+ .filter((ts) => ts.length < maxSize)
+ .map((ts) => ts.map((t) => t.split(',')))
+ .flat(2)
+ );
+ const allNodes = new Set(Object.keys(connections));
+
+ return [...allNodes.difference(notInMax)].toSorted().join(',');
+}
diff --git a/2024/23/run.ts b/2024/23/run.ts
new file mode 100644
index 0000000..88783cd
--- /dev/null
+++ b/2024/23/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 93f0fd5..d587332 100644
--- a/utils/array.ts
+++ b/utils/array.ts
@@ -115,6 +115,27 @@ export function combinations(arr: ReadonlyArray): { a: E; b: E }[] {
.filter((c) => !!c);
}
+/**
+ * Returns an array with every unique combination of every element in an array.
+ * The combination array will have a length of `n! / ((n-2)! * 2)` for an array of length `n`.
+ * @example
+ * ```typescript
+ * const arr = [0, 1, 2]
+ *
+ * combinations(arr) === [
+ * {a: 0, b: 1},
+ * {a: 0, b: 2},
+ * {a: 1, b: 2}
+ * ]
+ * ```
+ * @param arr
+ */
+export function uniqueCombinations(arr: ReadonlyArray): { a: E; b: E }[] {
+ return arr.flatMap((a, aI) =>
+ arr.flatMap((b, bI) => (a !== b && aI > bI ? [{ a, b }] : []))
+ );
+}
+
/**
* Returns a filter lambda to be used in array.filter() to only allow the
* first occurrence of duplicate values.