diff --git a/2022/12/part1.js b/2022/12/part1.js new file mode 100644 index 0000000..c78f7d4 --- /dev/null +++ b/2022/12/part1.js @@ -0,0 +1,94 @@ +import * as R from "remeda"; +import Victor from "@a-robu/victor"; + +import { readFile } from "../05/part1.js"; + +const V = (x,y) => new Victor(x,y); + +const readInput = (...args) => + R.pipe( + readFile(...args), + (lines) => lines.split("\n"), + R.compact, // remove last line + R.map((line) => line.split("").map( c => c ==='S' ? '`' : c === 'E' ? '{' : c )) + ); + +export const puzzleInput = readInput(import.meta.url, "input"); +export const sample = readInput(import.meta.url, "sample"); + +export const findStart = (topoMap) => { + let y; + let x = R.findIndex(topoMap, (row) => { + let z = row.indexOf("`"); + if (z === -1) return false; + y = z; + return true; + }); + return V(x,y); +}; + +const directions = [ [0,1], [0,-1],[1,0],[-1,0] ].map( + d => V(...d) +); + +const outOfMap = (maxX,maxY) => (loc) => { + if( Math.min( loc.x, loc.y ) < 0 ) return true; + if( loc.x >= maxX ) return true; + if( loc.y >= maxY ) return true; + return false; +} + +const isReachable = (topoMap,pos) => { + const baseline = topoMap[pos.x][pos.y].charCodeAt(0); + + return (next) => { + return [0,1].includes( + topoMap[next.x][next.y].charCodeAt(0) - baseline + ) + } +} + +function findShortestPath(topoMap) { + + const initial = findStart(topoMap); + initial.steps = 0; + initial.beenThere = []; + + const potentials = [ initial ]; + + let bestSoFar; + + const oom = outOfMap(topoMap.length,topoMap[0].length ); + + let failsafe = 100000; + while( potentials.length > 0 ) { + // if(! failsafe--) return; + const pos = potentials.pop(); // depth-first + //console.log(pos.steps, bestSoFar); + + if( bestSoFar && (bestSoFar <= pos.steps) ) continue; + + if( topoMap[pos.x][pos.y] === '{' ) { + bestSoFar = pos.steps; + continue; + } + + const next = directions.map( + d => d.clone().add(pos) + ).filter( R.isNot(oom )) + .filter( isReachable(topoMap,pos) ) + .filter( next => !pos.beenThere.includes( next.toArray().join(',') ) ); + + next.forEach( n => n.steps = pos.steps + 1 ); + next.forEach( n => n.beenThere = [ + ...pos.beenThere, pos.toArray().join(',') + ] ); + + potentials.push(...next); + } + + return bestSoFar; + +} + +export default findShortestPath; diff --git a/2022/12/part2.js b/2022/12/part2.js new file mode 100644 index 0000000..10fc179 --- /dev/null +++ b/2022/12/part2.js @@ -0,0 +1,4 @@ +import * as R from "remeda"; + + +export default () => {}; diff --git a/2022/12/sample b/2022/12/sample new file mode 100644 index 0000000..86e9cac --- /dev/null +++ b/2022/12/sample @@ -0,0 +1,5 @@ +Sabqponm +abcryxxl +accszExk +acctuvwj +abdefghi diff --git a/2022/12/test.js b/2022/12/test.js new file mode 100644 index 0000000..19deda3 --- /dev/null +++ b/2022/12/test.js @@ -0,0 +1,26 @@ +import { test, expect, describe } from "vitest"; + +import { expectSolution } from "../01/main.js"; +import part1, { findStart, sample, puzzleInput } from "./part1.js"; +import part2 from "./part2.js"; + +describe("part 1", () => { + test( "findStart", () => { + expect( findStart(sample).toArray() ).toEqual( + [0,0] + ) + + }); + test( "sample", async () => { + expect(part1(sample)).toEqual(31); + }); + test.only("solution", () => { + expectSolution(part1(puzzleInput)).toEqual("TODO"); + }); +}); + +describe("part 2", () => { + test.todo("solution", () => { + expectSolution(part2(puzzleInput)).toEqual("TODO"); + }); +});