From 62baa825f23966f973b942f21fa4e29b035704b9 Mon Sep 17 00:00:00 2001 From: Pascal Syma Date: Fri, 6 Dec 2024 21:05:01 +0100 Subject: [PATCH] Solve 2024-06 (using bruteforce) --- 2024/06/2024-06.run.xml | 7 +++ 2024/06/index.test.ts | 22 +++++++ 2024/06/index.ts | 127 ++++++++++++++++++++++++++++++++++++++++ 2024/06/run.ts | 12 ++++ 2024/06/run2.ts | 29 +++++++++ 2024/06/worker.ts | 21 +++++++ bun.lockb | Bin 21776 -> 22479 bytes package.json | 3 +- 8 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 2024/06/2024-06.run.xml create mode 100644 2024/06/index.test.ts create mode 100644 2024/06/index.ts create mode 100644 2024/06/run.ts create mode 100644 2024/06/run2.ts create mode 100644 2024/06/worker.ts 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 3c72e86e25f79f197aba032766007fe21c59b5ba..a847f08356ce8e147a67ba5a426d3bc9e97a2298 100755 GIT binary patch delta 1972 zcmeH|?{8C87{~9q-3BXcyWN=Ww$2qcw|3ZeZP~isuH9H$96w@)N{S}T08SWDCt*vr zDpE0GVg?SMHwGv1#mJ_~B6tJJ3nE}NW?~T32*gAd4N*y!$XrawoIc;%+c*M$fG>QK zPrm0o=eg&cd+vRnGyJ}|_<3O!NPx_@$l9otPdKpJ>GyPmqrmwLs<-VEyOu9*t zqiFUEL~l40r}%HuvB@3Q z?&-vz&6@(|J)0g$osN9gCAzI~#7??*omynWVE@y+e0XRnwaZoGAK?A)7l zrp~sZcmKw3f8Y51hLdlNPgTCLe&;Ur)UNA?R=)6BX~#hRhk=5hQn{C=u52DZHEbQZ zuw`WP^yOazE4n=D?2^~NJd)_T#lMq~=8NW88)cf{-9EO16&wCIIblKzO$QMER=nSG7gXR1lm zV;O7PNN`wo}lUQpw+l!vX{kT(beSfc^b5*T6X5yvR6;`3Xw&Zk4Jqp z*>11M-b07IPaLd0841Y(yN78cVr6oZLiU)=es|bQ{sxcF?`cjc)ETqY+#QgeN5KbR z>s&)au{QcT)@Du{u3%CtkIxj=8keNk?KN6%efyri9jU?I?R~xO-TmGD-82=qm;c-4 W=mmprA00|m)02-a(w03sC;kDKkS4VN delta 1601 zcmeH{O-NKx6vy9t4w{qBS2_;mM_^9#tVSJY#u;ZEC!MjvRbdP$Sc?p7<01kTb1Vql z1P-^L3@RujS`_&T>0{xlO+;3>Y!^|%;38a@X8r$fo-vZprez0y^MB{u!@YCwJ@>qM zC{Nv&r@ZRyw0dd$i?jMf_HnWK!)#w)G|~T}BjLQd@_Ko(;8gcSkEB~Tld4e`Lyv}U z%k^c5SR`p;2|wGReyb#vK+TAQi8=Vi&{eB;Ot~q~n$}9hm_4d|w}@xd@?_IBlh zRkS){%Dh#KI%2X(Jat5l6k!5Vkef*Vw&R<&l`@ZihL*3g_)%6d$Wa%d?gBEXG_(pz z%hy8qwR$wC3cl+MpUQbWfb*z;rmHw#UXf<@em%BXnSB6Iy~a3|`HhB8lyp0ZQ3r+tX;Kc2^w^=zshY`emm6*T+-+=eML?ciy#&tfyN{dP+r7?Un-~qozbiEfve~TExNnl=!S#w3+%(CNWv) z(H0sqX0wY02OA5Eg=Cq?wyNp%pE+YV0P@S1J~zreuyi>VGL&(j@x4*TCis3M#!_bf zJ!8o$Mva@J=bC-7-TvKY2S*2nPKz56wT@NT0XjhpunWOw=t0wYSj%+0DPgOfJ)6eDm-ab8&vy#ZIx_Hlk%> z1BJqt+^H;C#Dk=(a-+`{4@F;oJv#kdk;emGU(oB9=B(mm(iPlj$eD)T%kC#_VI=q( zy-hxEXw_)RcV1l^xpn5