diff --git a/2024/06/2024-06.run.xml b/2024/06/2024-06.run.xml
new file mode 100644
index 0000000..6dda585
--- /dev/null
+++ b/2024/06/2024-06.run.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/2024/06/index.test.ts b/2024/06/index.test.ts
new file mode 100644
index 0000000..c074600
--- /dev/null
+++ b/2024/06/index.test.ts
@@ -0,0 +1,22 @@
+import { describe, expect, it } from 'bun:test';
+import { solveFirst } from './index.ts';
+
+describe('2024-06', () => {
+ const testInput = `....#.....
+.........#
+..........
+..#.......
+.......#..
+..........
+.#..^.....
+........#.
+#.........
+......#...`;
+ it('first', () => {
+ expect(solveFirst(testInput)).toBe(41);
+ });
+ it('second', () => {
+ // that takes too long
+ // expect(solveSecond(testInput)).toBe(6);
+ });
+});
diff --git a/2024/06/index.ts b/2024/06/index.ts
new file mode 100644
index 0000000..28dad22
--- /dev/null
+++ b/2024/06/index.ts
@@ -0,0 +1,127 @@
+import { sumBy } from '../../utils/array.ts';
+
+export function replace(arr: string[], x: number, y: number, char: string) {
+ arr[y] = arr[y].substring(0, x) + char + arr[y].substring(x + 1);
+}
+
+const directions = [
+ { d: '^', x: 0, y: -1 },
+ { d: '>', x: 1, y: 0 },
+ { d: 'v', x: 0, y: 1 },
+ { d: '<', x: -1, y: 0 }
+] as const;
+
+export function solveFirst(input: string): number {
+ const rows = input.split('\n');
+
+ const columnCount = rows[0].length;
+ const rowCount = rows.length;
+
+ let y = rows.findIndex((r) => r.indexOf('^') >= 0);
+ let x = rows[y].indexOf('^');
+ let direction = 0;
+
+ while (x >= 0 && x < columnCount && y >= 0 && y < rowCount) {
+ const nextX = x + directions[direction].x;
+ const nextY = y + directions[direction].y;
+ if (rows[nextY]?.[nextX] === '#') {
+ direction = (direction + 1) % 4;
+ }
+
+ replace(rows, x, y, 'X');
+ x += directions[direction].x;
+ y += directions[direction].y;
+ }
+ return sumBy(rows, (r) => [...r.matchAll(/X/g)].length);
+}
+
+export function getNextObstacle(
+ rows: string[],
+ startX: number,
+ startY: number,
+ d: number
+): false | { x: number; y: number } {
+ let x = startX;
+ let y = startY;
+
+ while (true) {
+ const nextX = x + directions[d].x;
+ const nextY = y + directions[d].y;
+ const next = rows[nextY]?.[nextX];
+ if (!next) {
+ return false;
+ }
+ if (next === '#') {
+ return { x, y };
+ }
+ x = nextX;
+ y = nextY;
+ }
+}
+
+export function finishes(
+ rows: string[],
+ startX: number,
+ startY: number,
+ d: number
+): boolean {
+ let x = startX;
+ let y = startY;
+
+ let i = 0;
+ do {
+ const next = getNextObstacle(rows, x, y, (d + i) % 4);
+ if (!next) {
+ return true;
+ }
+ x = next.x;
+ y = next.y;
+ i++;
+
+ // TODO: be smarter
+ } while (i < 1_000_000);
+
+ return false;
+}
+
+export function solveRow(
+ rows: string[],
+ row: number,
+ startX: number,
+ startY: number,
+ startDirection: number
+) {
+ let found = 0;
+
+ for (let column = 0; column < rows[0].length; column++) {
+ if ((row === startX && column === startY) || rows[row][column] === '#') {
+ continue;
+ }
+
+ replace(rows, column, row, '#');
+ if (!finishes(rows, startX, startY, startDirection)) {
+ found++;
+ }
+
+ replace(rows, column, row, '.');
+ }
+ return found;
+}
+
+export function solveSecond(input: string): number {
+ const rows = input.split('\n');
+ const rowCount = rows.length;
+
+ const y = rows.findIndex((r) => r.indexOf('^') >= 0);
+ const x = rows[y].indexOf('^');
+ const direction = 0;
+
+ let found = 0;
+
+ for (let row = 0; row < rowCount; row++) {
+ found += solveRow(rows, row, x, y, direction);
+ console.log('row:', row, 'found', found);
+ }
+
+ return found;
+}
diff --git a/2024/06/run.ts b/2024/06/run.ts
new file mode 100644
index 0000000..88783cd
--- /dev/null
+++ b/2024/06/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/2024/06/run2.ts b/2024/06/run2.ts
new file mode 100644
index 0000000..1716d5d
--- /dev/null
+++ b/2024/06/run2.ts
@@ -0,0 +1,29 @@
+import { availableParallelism } from 'os';
+import pLimit from 'p-limit';
+import { join } from 'path';
+import { sumArray } from '../../utils/array.ts';
+
+const workerFile = new URL('worker.ts', import.meta.url).href;
+
+const eva = (i: number) =>
+ new Promise((resolve) => {
+ const worker = new Worker(workerFile);
+
+ worker.postMessage(i);
+ worker.onmessage = (event) => {
+ console.log('row:', i, 'found', event.data);
+ resolve(event.data as number);
+ };
+ });
+
+const input = await Bun.file(join(__dirname, 'input.txt')).text();
+const rowCount = input.split('\n').length;
+
+const work = new Array(rowCount).fill(0).map((_, i) => i);
+
+const limit = pLimit(availableParallelism());
+const solution = await Promise.all(work.map((w) => limit(eva, w)));
+
+console.log(solution);
+
+console.log(sumArray(solution));
diff --git a/2024/06/worker.ts b/2024/06/worker.ts
new file mode 100644
index 0000000..2625c36
--- /dev/null
+++ b/2024/06/worker.ts
@@ -0,0 +1,21 @@
+import { join } from 'path';
+import { solveRow } from './index.ts';
+
+declare var self: Worker;
+
+const input = await Bun.file(join(__dirname, 'input.txt')).text();
+
+self.onmessage = (event) => {
+ const row = event.data as number;
+
+ console.log('Start row', row);
+
+ const rows = input.split('\n');
+
+ const y = rows.findIndex((r) => r.indexOf('^') >= 0);
+ const x = rows[y].indexOf('^');
+ const direction = 0;
+
+ postMessage(solveRow(rows, row, x, y, direction));
+ process.exit();
+};
diff --git a/bun.lockb b/bun.lockb
index 3c72e86..a847f08 100755
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/package.json b/package.json
index 9a7064a..e22b510 100644
--- a/package.json
+++ b/package.json
@@ -15,7 +15,8 @@
"prettier": "^3.4.0",
"prettier-plugin-organize-imports": "^4.1.0",
"prompts": "^2.4.2",
- "replace-in-file": "^8.2.0"
+ "replace-in-file": "^8.2.0",
+ "p-limit": "^6.1.0"
},
"peerDependencies": {
"typescript": "^5.7.2"