From ce848f3f16a5a86355c28b15b4c295f9d1767e99 Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 16 Dec 2024 22:01:40 +0000 Subject: [PATCH] Day 16 so far --- 2024/16/index.ts | 158 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 2024/16/index.ts diff --git a/2024/16/index.ts b/2024/16/index.ts new file mode 100644 index 0000000..0901d12 --- /dev/null +++ b/2024/16/index.ts @@ -0,0 +1,158 @@ +const fs = require('fs'); + +const input = fs.readFileSync(__dirname + '/input.txt', 'utf8'); + +interface Coord { + x: number, + y: number, +}; + +enum Dir { + Up, + Right, + Down, + Left, +}; + +const map: Array> = input.split("\n").map((row: string) => row.split('')); + +const width = map[0].length; +const height = map.length; + +const snakeIndex = input.indexOf('S'); +let snakePos = { x: snakeIndex % (width + 1), y: Math.floor(snakeIndex / height) }; +let snakeDir = Dir.Right + +function get(pos: Coord): string { + return map[pos.y][pos.x]; +} + +function set(pos: Coord, val: string): void { + map[pos.y][pos.x] = val; +} + +function nextDir(dir: Dir): Dir { + const directions = [Dir.Up, Dir.Right, Dir.Down, Dir.Left]; + const i = (directions.indexOf(dir) + 1) % directions.length; + return directions[i]; +} +function prevDir(dir: Dir): Dir { + const directions = [Dir.Up, Dir.Right, Dir.Down, Dir.Left]; + const i = directions.indexOf(dir) - 1; + if (i < 0) { + return directions[directions.length - 1]; + } + return directions[i]; +} + +function printMap() { + const mapClone = map.slice().map((row: Array) => row.slice()); + console.log(mapClone.map((row: Array) => row.join('')).join("\n")); +} + +function nextCoord(pos: Coord, direction: Dir): Coord { + return direction === Dir.Up ? { x: pos.x, y: pos.y - 1 } + : (direction === Dir.Right ? { x: pos.x + 1, y: pos.y } + : (direction === Dir.Down ? { x: pos.x, y: pos.y + 1 } : { x: pos.x - 1, y: pos.y }) + ); +} + +function isDeadEnd(pos: Coord): boolean { + const adjs = [Dir.Up, Dir.Right, Dir.Down, Dir.Left].map((dir) => get(nextCoord(pos, dir))).join(''); + return adjs === '###.' + || adjs === '##.#' + || adjs === '#.##' + || adjs === '.###'; +} + +function isBranch(pos: Coord, dir: Dir): boolean { + const leftDir = prevDir(dir); + const rightDir = nextDir(dir); + const next = nextCoord(pos, dir); + const left = nextCoord(pos, leftDir); + const right = nextCoord(pos, rightDir); + const nextChar = get(next); + const leftChar = get(left); + const rightChar = get(right); + return nextChar === '.' && leftChar === '.' + || nextChar === '.' && rightChar === '.' + || leftChar === '.' && rightChar === '.'; +} + +function fillDeadEnd(pos: Coord): void { + set(pos, '#') + for (let dir of [Dir.Up, Dir.Right, Dir.Down, Dir.Left]) { + const next = nextCoord(pos, dir); + if (get(next) === '.') { + if (isDeadEnd(next)) { + fillDeadEnd(next); + } + } + }; +} + +printMap(); +for (let y = 1; y < height - 1; y++) { + for (let x = 1; x < width - 1; x++) { + const pos = { x, y }; + const char = get(pos); + if (char !== '.') { + continue; + } + if (isDeadEnd(pos)) { + fillDeadEnd(pos); + } + } +} +printMap(); + +let fastest: number|null = null; + +const scoreCache: { [key: string]: [number, Coord, Dir] } = {}; + +const scores: Array = []; + +function getScoresAfterPosition(pos: Coord, dir: Dir, currentScore = 0, path: Array = [], lastBranch: [number, Coord]|null = null): void { + if (fastest !== null && currentScore >= fastest) { + return; + } + const cache = scoreCache[`${pos.x},${pos.y}`]; + if (cache) { + currentScore += cache[0]; + pos = cache[1]; + dir = cache[2]; + } + const branch = isBranch(pos, dir); + if (branch) { + if (lastBranch) { + scoreCache[`${lastBranch[1].x},${lastBranch[1].y}`] = [currentScore - lastBranch[0], pos, dir]; + console.log(scoreCache); + } + lastBranch = [currentScore, pos]; + } + [dir, nextDir(dir), prevDir(dir)].forEach((newDir, i) => { + const next = nextCoord(pos, newDir); + const nextStr = `${next.x},${next.y}`; + if (!path.includes(nextStr)) { + const add = i === 0 ? 1 : 1001; + const score = currentScore + add; + const nextChar = get(next); + if (nextChar === 'E') { + if (fastest === null || score < fastest) { + fastest = score; + } + lastBranch = null; + scores.push(score); + return; + } else if (nextChar === '.') { + getScoresAfterPosition(next, newDir, score, [...path, nextStr], branch ? [score, next] : lastBranch); + } + } + }); + + return; +} + +getScoresAfterPosition(snakePos, snakeDir); + +console.log(Math.min(...scores)); \ No newline at end of file