From 7bd85e5f6b18aee729dfe3273ec7c4cc260289df Mon Sep 17 00:00:00 2001 From: Pascal Syma Date: Thu, 19 Dec 2024 15:20:16 +0100 Subject: [PATCH] Solve 2024-18 (using A* lib) --- 2024/18/2024-18.run.xml | 7 ++ 2024/18/index.test.ts | 36 +++++++++ 2024/18/index.ts | 167 ++++++++++++++++++++++++++++++++++++++++ 2024/18/run.ts | 12 +++ bun.lockb | Bin 22479 -> 23246 bytes package.json | 4 + 6 files changed, 226 insertions(+) create mode 100644 2024/18/2024-18.run.xml create mode 100644 2024/18/index.test.ts create mode 100644 2024/18/index.ts create mode 100644 2024/18/run.ts diff --git a/2024/18/2024-18.run.xml b/2024/18/2024-18.run.xml new file mode 100644 index 0000000..c8a06bb --- /dev/null +++ b/2024/18/2024-18.run.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/2024/18/index.test.ts b/2024/18/index.test.ts new file mode 100644 index 0000000..9d033ce --- /dev/null +++ b/2024/18/index.test.ts @@ -0,0 +1,36 @@ +import { describe, expect, it } from 'bun:test'; +import { solveFirst, solveSecond } from './index.ts'; + +describe('2024-18', () => { + const testInput = `5,4 +4,2 +4,5 +3,0 +2,1 +6,3 +2,4 +1,5 +0,6 +3,3 +2,6 +5,1 +1,2 +5,5 +2,5 +6,5 +1,4 +0,4 +6,4 +1,1 +6,1 +1,0 +0,5 +1,6 +2,0`; + it('first', () => { + expect(solveFirst(testInput, 7, 7, 12)).toBe(22); + }); + it('second', () => { + expect(solveSecond(testInput, 7, 7, 12)).toBe('6,1'); + }); +}); diff --git a/2024/18/index.ts b/2024/18/index.ts new file mode 100644 index 0000000..daeee86 --- /dev/null +++ b/2024/18/index.ts @@ -0,0 +1,167 @@ +// @ts-ignore +import { astar, Graph } from 'javascript-astar'; +import { replaceChar } from '../../utils/array.ts'; +import { + type Coordinate, + inBounds, + isCoordinateEqual +} from '../../utils/coordinates.ts'; +import { MultiMap } from '../../utils/multi-map.ts'; +import { PriorityQueue } from '../../utils/queue.ts'; + +function getGraph( + allBytes: [number, number][], + byteCount: number, + height: number, + width: number +): Graph { + const bytes = allBytes.slice(0, byteCount); + + const map = new Array(height) + .fill(null) + .map((_, y) => + new Array(width) + .fill(0) + .map((_, x) => + bytes.findIndex((c) => isCoordinateEqual(c, [x, y])) >= 0 ? 0 : 1 + ) + ); + + return new Graph(map); +} + +export function solveFirst( + input: string, + width = 71, + height = 71, + byteCount = 1024 +): number { + const match = input.matchAll(/^(\d*),(\d*)/gm); + + const allBytes = Array.from( + match, + (m) => m.slice(1, 3).map(Number) as Coordinate + ); + const graph = getGraph(allBytes, byteCount, height, width); + + const start = graph.grid[0][0]; + const end = graph.grid[height - 1][width - 1]; + + const result = astar.search(graph, start, end); + return result.length; +} + +export function solveSecond( + input: string, + width = 71, + height = 71, + byteCount = 1024 +): string { + const match = input.matchAll(/^(\d*),(\d*)/gm); + + const allBytes = Array.from( + match, + (m) => m.slice(1, 3).map(Number) as Coordinate + ); + + // let lastPath: Coordinates = []; + for (let i = byteCount; i < allBytes.length; i++) { + const nextByte = allBytes[i]; + // if ( + // lastPath.length > 0 && + // !lastPath.some((p) => isCoordinateEqual(p, nextByte)) + // ) { + // console.log(lastPath); + // continue; + // } + + const graph = getGraph(allBytes, i + 1, height, width); + const start = graph.grid[0][0]; + + const end = graph.grid[height - 1][width - 1]; + const result = astar.search(graph, start, end); + if (result.length <= 0) { + return nextByte.join(','); + } + // lastPath = result.map((n: GridNode) => [n.x, n.y] as Coordinate); + } + return ''; +} + +export function solveFirstOld( + input: string, + width = 71, + height = 71, + byteCount = 1024 +): number { + const match = input.matchAll(/^(\d*),(\d*)/gm); + + const bytes = Array.from( + match, + (m) => m.slice(1, 3).map(Number) as Coordinate + ).slice(0, byteCount); + + const map = new Array(height) + .fill(null) + .map(() => new Array(width).fill('.').join('') as string); + + bytes.forEach(([x, y]) => replaceChar(map, x, y, '#')); + replaceChar(map, width - 1, height - 1, 'E'); + + console.log(map.join('\n')); + const start = { x: 0, y: 0, score: 0 }; + const possibleOptions = new PriorityQueue(); + + possibleOptions.enqueue(start, 0); + const visited = new Set<`${number}:${number}`>(); + const scores = new MultiMap(); + visited.add(`${start.x}:${start.y}`); + + let i = 0; + while (possibleOptions.size() > 0) { + const el = possibleOptions.dequeue()!!; + + scores.multiSet(el.node.score, el.node.y, el.node.x); + visited.add(`${el.node.x}:${el.node.y}`); + if (map[el.node.y]?.[el.node.x] === 'E') { + // console.log(visited); + return el.node.score; + } + if (possibleOptions.size() % 10_000 === 0) { + console.log(visited.size, possibleOptions.size()); + } + for (let [x, y] of [ + [0, 1], + [0, -1], + [1, 0], + [-1, 0] + ]) { + const nx = el.node.x + x; + const ny = el.node.y + y; + const score = el.node.score + 1; + if (!inBounds(width, height)([nx, ny]) || map[ny]?.[nx] === '#') { + continue; + } + if (visited.has(`${nx}:${ny}`)) { + continue; + } + const existingScore = scores.multiGet(ny, nx) || Number.MAX_SAFE_INTEGER; + if (score < existingScore) { + possibleOptions.enqueue({ x: nx, y: ny, score }, score); + } + } + // console.log('a', el.node, visited.size, possibleOptions.size()); + // return 0; + i++; + + if (i >= 10_000_000) { + visited.forEach((v) => { + const [x, y] = v.split(':').map(Number); + replaceChar(map, x, y, 'O'); + }); + console.log(map.join('\n')); + return 0; + } + } + return 0; +} diff --git a/2024/18/run.ts b/2024/18/run.ts new file mode 100644 index 0000000..88783cd --- /dev/null +++ b/2024/18/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/bun.lockb b/bun.lockb index a847f08356ce8e147a67ba5a426d3bc9e97a2298..24b152fd8a65770e3ecddafa215ae2d243db0332 100755 GIT binary patch delta 4478 zcmdT{dvH|M8NX+>`$m#qYWO3}7-N*UCSwg_lDBEb^+`|jSW)WUzA&h*TD z_q)IEeCM3+ah|`~E6yGi>m51D+-I)12a>lupK^8A+3%h9<@YwH48Jk%{Pjr#vwxYD z66R`>)Kay zc7r4(0B-`10AC9p4&JxnTtZ{1QIceU9&oOF6Wjtm))Z9o7nDB9qc3jnT)_Mb$j71n zBXBn6KxnYtZjD!j1&vrw9+BGnCuni6*UZ6DI@+FW>uT=qJ`XvMx)UEZc?3KP{FEkt z3HEXCtHIeC-O8^_4+&bQyVwJNxxMb9=1qE_rM0>J37Flrw6mjYS+}$wy|M34v_JmT zQpn3l7*c2XU;~>u2@>w+qK4C914l9ra*iNcs;xhVoXsyo*qP7F?k-&08MwJ@&JZ3l~%uC*~8zT?f_EMtpvB>3UIt{8|5(VVR)MYe_Q{*?g4Kaca8(pG@MvQLp zD=IU&^2z(lJ;o$^_r zQlJo8Wpv7+$Y`P3fa^R!aTvKq(?+}eK(6KP5I6{8eEpF4G?3QOB`}Jy1=-spxsD^HvD&$M}3tHrfEfr=u z9PW}^Felh9gKEjkR2JbDUywh-Z77uKaD+=l+c>pNbHM;+;?I2_>=J7^@*Eq|!V%&JB|(#slVS|vN>6F?lUFcsa=P^gM3knn2Mndn%AQ|<@i zaU>36l7vKNJy#9`Z-KnXbw2=Bz&h#Ci{c7<19`+4~jX0sn^yRSmHruWGRcnZ%sq zm#tyuZ25mbp}|PxV>POl{J$r3GHUct`(eY-9X{i0(@@v!UZj{O%lB_$mVHJqV_gha9= zctr>`CiuvlXrb4EOe81z=nzmxqF02`AW*Afp=8A?WNK4;hm}H@gK(UmQ$zBmp{mDKmO|j5b zpad#Q@zKXXTT{G3p}zucPPI@&s#jQPORA5i*(`J$D4C|)d~_4&HJewY(g@J5Gz-m3 z^NKXuo#vxQ(=B94_lgW^Oox9N@DC`9@*CtJRAOHdqp1kv*F(a_y<%#ITPR?(7Fj;QA8Jj`X<7^iC$4c{S)C| z4*UahQdtiC1KOJ7ZQvb5FUF=-A9#xo_-3A5G%K{@%!-=*EuY@J-0*uT{_X4Ezxi_C zLsjO?{iBiF?mS=9v(S0)#*1HmaBO#7RO9;%|5&#_B=pbav@Tbn8#yyX1$lCPqLQ}c zwotV(4%Y^wMZW+Z#c<&R!ah~dtjUq0pXN>eVR(W$ct=Sy4~$MeCBz0Ac3e@L_JvLy zcqi{pIN2u636Ie>xMfxJPF);bEw}fM-U$|Vf}P>%sjo79d*r3fTPD}(TP5#9C7O(T zIc_y|)#@gQ7i zrD6~cV!ozGd}#0nmIKNK@$tq-p&P^}5uZ+c)Zv&@qru*@x9k{41<{I-PHJxc(@kqC z(t9~-xPhpV<#BjCwu|j!yEw8OIX>CgZjLJZz&kv9%*S>p2sdOkx*QFT6i1Asf?I_e zA=bk!Le*y-Tp0Lu(5o8DA+mvzLF_o6|LhnCfSnu<(gTx(e|C@^)kBF&`D#sp z136qvz150Ue}8^5>;Y%169soL&IrvnNq7{)SQ90A3h~aE=}}7bM^~!h z{rR)6UF$;QGBn0S)SqdqW4_bg{+xIPHE@dk`iQoA6s!K|`+4N=M(<30uUM^D-P%p( zJc>9#S3C_?{pnX7e`$015%WrDaoAwYdV08~PJS0t6%#CQjkeb)VkZsNC|3R9=bQa* z!@R!_U;eu1)pWf^>D3>CyZob_Mcb?%BPSA;o9#Pvy?aU;l0PkA@85nG#3g6lC;s`fi<4qCaCdUs70X?3uw?3?|QgROsW$h)@rqi6h016hg3E;iPDt>f&E zP86INeK~Te$zEAG1~v=))BnlhGYU?ciP{D_5ojV zbVS#*1;8cHY0x>)v!KlxNj)&KxqqmC%fRNL!CiwGa{=uJ`h6bQuf)qby!fF{Ky%<| zb^Q+5X^m;AzfE@K&#<;b8`^Y^ z)_>}eW2w#h`yRQR+N{dOG%Vvukh>NZ%AWs2pl+ZU5>Ab()iP;V>N{f2vW$0-!Y+Fz z%Oh~8a9Y&(9S|)MaavT>NUz^Ab|DXJOSLV6$WRhpF`~v=Ao4X+ zhz>d^#YPu_TF~c}urF!^kx{OrkxR8v%ydg1_eo!RvvC<+^dE+x!6%dHma!5Q!-*AL zMl`({miOmq+a^;+ql(C6hGl#iMUzZc7-2mJREH7C#XkaKc0u&4dYR0$)To$QmVPE( z`m&mpCX-o~vc#NY>0i%~zB$YI_s}TFE2~fgsah6<&)qcb=Gndfs!?(LciPW%O?wkU zoeiN~j-wZ9+8ACn4KMaXjS|oblhD?vSFPB=)SRdc!imZue5Px*SJmU8rlvzt2p2{P*b6s8^Py%tIJckwrgfQ`yI_pg?T+>S=h9+P}Cv2^5fOeB4{hdd_Nw-ZVSKEFiXV;)H@7yiE! zxr(#2L-;g0 z^vi)@Oc^o>^fpjaD5lcn@lag$hy3yZkY5_I<5HjPmmg%uRJyzebQNe-PE2LW(VVy( z$??l4Ky##LVO+Ww`sJC0F*Q$a0o?@JkQ>7;e=0XFCv*Mc&xN1BJv0 z$0arFm+j%0%8?g=UI5C;kEvW4%#X{qe80Q~6c)1}E`b8XR}fPLaslW(P-S6E70GBJ z;wwaaKqXREg!qaOUr|hz$t2L*KuyIlRUwZTBfet92UIByC5W#C@s-5XVtEhfD$uIZ zn5veerHHQ-@d4FHPZ{DXLwsd1RV%lEZUSv6kEy7fDo1?fei^8UsRsF31>&oiE%O&W zAO}4jqYW9x*_>E2abVFGlnTm~%ESJX*eG#AB%XuLm^iekUCFbHc1z0=pURh2ORi0< ztPZ8k3OF0ZR~zMx<*h@ScIVUN!>Zw?!fJ6hA9s^+Hz4-8b;@e1aqKxK`#g|Z=N$)v z-FDJhaD2J!Yib+gj=_@egs@002zLpbcl2KCfpC}M#+wVtgM=aZkOBx#1RPVm3GuE% z8hAV6MbLJ82{bp=MUX;B5rn%xE`r(|O?yb=B?pI`wiJS63OjCcH!p!Mh45(LF4P3! zF3t^s#{`cEZoZ6}F)}`KL5|K7;Q6=-G3JkPdRz`{Gn#Xl>lbOFZ`|-mEB$6XjEnm^ zZXz~~q?eqK8zj``hB32^c8r~x*yVtnfu}K>IQq<35wuMJV+ukTAIS(nLJ$sOYShM_OYFuQM){`ZmJkMONuNoauUrBl1;K2oOhDPwo>PaI@c*F zEt}-AmithzueH>uHc_pnENvanz63Lnl=x&wJ-ai%llAy2n8$!iN>A9$(F47pe0>s$KPO)Y<=17`IwLvA9nz0It3 zzYO}+_&Z&HeQGEAYtfG=+)MYmH?9}%8P4cMPc%6)IrD$;5HtJa&zSkH{ncFAy~gL{ zUnzLS$bS(t*Cl6OCr$09e!?T`+atJHf2-XLx!(%8`X4v0xp9LIHozDZZ(Ram~;(P<2z98pAxF`4QxL+%$#@0lCk@!x+?>R5xWCnU4eRP&{x)690iUrvtR z8LoLc)ap?iK`EWOq{+jbfzUbp?=vvz&A)wR+u8Ns`=PE*qXjjZ$dSce=Ka@zQ0|E> zy|12qGW}_iM6aLesKRpA6TJ{}ZY;Q9bJ~*UG!*dUSOQW9Fj8C$~Gz&|UK3 zWZGUcbeBqCRuG!qj}u{Umx(L#;V#zcFT1wtS7*!86_Hx^+v(8az5~V2H#O+09JR^E z{hBg{m!Ero&9RqswXe1+QitT#$@f>7*`FP`FM<^#RrPx^n0LCze%4s-dm~u0S)t&$p8QV diff --git a/package.json b/package.json index d7bb010..4c76cca 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ }, "devDependencies": { "@types/bun": "latest", + "@types/javascript-astar": "^0.0.35", "@types/prompts": "^2.4.9", "p-limit": "^6.1.0", "prettier": "^3.4.0", @@ -21,5 +22,8 @@ }, "peerDependencies": { "typescript": "^5.7.2" + }, + "dependencies": { + "javascript-astar": "^0.4.1" } }