diff --git a/2024/11/2024-11.run.xml b/2024/11/2024-11.run.xml
new file mode 100644
index 0000000..7a6d177
--- /dev/null
+++ b/2024/11/2024-11.run.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/2024/11/index.test.ts b/2024/11/index.test.ts
new file mode 100644
index 0000000..11571ba
--- /dev/null
+++ b/2024/11/index.test.ts
@@ -0,0 +1,19 @@
+import { describe, expect, it } from 'bun:test';
+import { solve, solveFirstSlow } from './index.ts';
+
+describe('2024-11', () => {
+ const testInput = `125 17`;
+ it('first slow', () => {
+ // it takes too long
+ // so only run while `NODE_ENV=production bun test --coverage`
+ if (process.env.NODE_ENV === 'production') {
+ expect(solveFirstSlow(testInput)).toBe(55312);
+ }
+ });
+ it('first', () => {
+ expect(solve(testInput, 25)).toBe(55312);
+ });
+ it('second', () => {
+ expect(solve(testInput, 75)).toBeGreaterThan(55312);
+ });
+});
diff --git a/2024/11/index.ts b/2024/11/index.ts
new file mode 100644
index 0000000..2a2a1e4
--- /dev/null
+++ b/2024/11/index.ts
@@ -0,0 +1,73 @@
+import { sumArray } from '../../utils/array.ts';
+import { MultiMap } from '../../utils/multi-map.ts';
+
+export function solveFirstSlow(input: string): number {
+ const stones = input.split(' ');
+
+ for (let i = 0; i < 25; i++) {
+ let j = 0;
+ while (j < stones.length) {
+ const stone = stones[j];
+ if (stone === '0') {
+ stones[j] = '1';
+ j++;
+ continue;
+ }
+ if (stone.length % 2 === 0) {
+ const secondStone = stone.substring(stone.length / 2);
+ stones.splice(j + 1, 0, String(Number(secondStone)));
+ stones[j] = stone.substring(0, stone.length / 2);
+ j += 2;
+ continue;
+ }
+
+ stones[j] = String(Number(stone) * 2024);
+ j++;
+ }
+ }
+
+ return stones.length;
+}
+
+const lookup = new MultiMap();
+
+function splits(stone: string, times: number): number {
+ const lookedUp = lookup.multiGet(times, stone);
+ if (lookedUp !== undefined) {
+ return lookedUp;
+ }
+
+ if (times <= 0) {
+ const result = 1;
+ lookup.multiSet(result, times, stone);
+ return result;
+ }
+ if (stone === '0') {
+ const result = splits('1', times - 1);
+ lookup.multiSet(result, times, stone);
+ return result;
+ }
+ if (stone.length % 2 === 0) {
+ const secondStone = stone.substring(stone.length / 2);
+ const firstStone = stone.substring(0, stone.length / 2);
+ const result =
+ splits(firstStone, times - 1) +
+ splits(String(Number(secondStone)), times - 1);
+
+ lookup.multiSet(result, times, stone);
+ return result;
+ }
+
+ const result = splits(String(Number(stone) * 2024), times - 1);
+
+ lookup.multiSet(result, times, stone);
+ return result;
+}
+
+export function solve(input: string, iterations: number): number {
+ const stones = input.split(' ');
+
+ const count = stones.map((stone) => splits(stone, iterations));
+
+ return sumArray(count);
+}
diff --git a/2024/11/run.ts b/2024/11/run.ts
new file mode 100644
index 0000000..1490124
--- /dev/null
+++ b/2024/11/run.ts
@@ -0,0 +1,12 @@
+import { join } from 'path';
+import { solve } from './index.ts';
+
+const input = await Bun.file(join(__dirname, 'input.txt')).text();
+
+const firstAnswer = solve(input, 25);
+
+console.log(firstAnswer);
+
+const secondAnswer = solve(input, 75);
+
+console.log(secondAnswer);