diff --git a/2024/18/index.ts b/2024/18/index.ts index 73a098c..25a78f6 100644 --- a/2024/18/index.ts +++ b/2024/18/index.ts @@ -14,9 +14,7 @@ enum Dir { Left, }; -const map: Array> = []; - -const path: Array = []; +const map: Array> = []; const width = 71; const height = 71; @@ -35,14 +33,14 @@ for (let i = 0; i < 1024; i++) { map[y][x] = '#' } -function get(pos: Coord): string { +function get(pos: Coord): string|number { if (map[pos.y] && map[pos.y][pos.x]) { return map[pos.y][pos.x]; } return '#'; } -function set(pos: Coord, val: string): void { +function set(pos: Coord, val: string|number): void { map[pos.y][pos.x] = val; } @@ -60,26 +58,12 @@ function prevDir(dir: Dir): Dir { return directions[i]; } -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 printMap(path: Array = []) { - const mapClone = map.slice().map((row: Array) => row.slice()); + const mapClone = map.slice().map((row: Array) => row.slice()); path.forEach(({ x, y }) => { mapClone[y][x] = 'O'; }); - console.log(mapClone.map((row: Array) => row.join('')).join("\n")); + console.log(mapClone.map((row: Array) => row.map((c) => typeof c === 'number' ? '.' : c).join('')).join("\n")); console.log("\n"); } @@ -114,105 +98,53 @@ function fillDeadEnd(pos: Coord): void { } printMap(); -// for (let y = 0; y < height; y++) { -// for (let x = 0; x < width; x++) { -// const pos = { x, y }; -// const char = get(pos); -// if (char !== '.') { -// continue; -// } -// if (isDeadEnd(pos)) { -// fillDeadEnd(pos); -// } -// } -// } - -// printMap(); - -interface Nd { - parent: Nd|null, - pos: Coord, - g: number, - h: number, - f: number, -}; - -const openList: Array = []; -const closedList: Array = []; - -const startNode: Nd = { - parent: null, - pos: { x: 0, y: 0 }, - g: 0, - h: 0, - f: 0, -}; - -const endNode = { - parent: null, - pos: { x: width - 1, y: height - 1 }, - g: 0, - h: 0, - f: 0, -}; - -openList.push(startNode); - -while (openList.length > 0) { - let currentNode = openList[0]; - let currentIndex = 0; - openList.forEach((item, index) => { - if (item.f < currentNode.f) { - currentNode = item; - currentIndex = index; +for (let y = 0; y < height; y++) { + for (let x = 0; x < width; x++) { + const pos = { x, y }; + const char = get(pos); + if (char !== '.') { + continue; } - }); - - openList.splice(currentIndex, 1); - closedList.push(currentNode); - - if (currentNode.pos.x === endNode.pos.x && currentNode.pos.y === endNode.pos.y) { - let current: Nd|null = currentNode; - while (current) { - path.push(current.pos); - current = current.parent; + if (isDeadEnd(pos)) { + fillDeadEnd(pos); } - - break; } - - const children: Array = []; - - [Dir.Up, Dir.Right, Dir.Down, Dir.Left].forEach((dir) => { - const nodePos = nextCoord(currentNode.pos, dir); - - if (get(nodePos) === '#') { - return; - } - - const newNode: Nd = { - parent: currentNode, - pos: nodePos, - g: 0, - h: 0, - f: 0, - }; - - if (closedList.find((closedChild) => closedChild.pos.x === newNode.pos.x && closedChild.pos.y === newNode.pos.y)) { - return; - } - - newNode.g = currentNode.g + 1; - newNode.h = ((newNode.pos.x - endNode.pos.x) ** 2) + ((newNode.pos.y - endNode.pos.y) ** 2); - newNode.f = newNode.g + newNode.h; - - if (openList.find((openNode) => newNode.pos.x === openNode.pos.x && newNode.pos.y === openNode.pos.y && newNode.g > openNode.g)) { - return; - } - - openList.push(newNode); - }); } printMap(); -console.log(path, path.length) + +let fastest: number|null = null; + +const scores: Array> = []; + +function getScoresAfterPosition(pos: Coord, dir: Dir, path: Array = [], lastBranch: [number, Coord]|null = null): void { + if (fastest !== null && path.length >= fastest) { + return; + } + [dir, nextDir(dir), prevDir(dir)].forEach((newDir, i) => { + const next = nextCoord(pos, newDir); + const nextCell = get(next); + if (nextCell !== '#' && (typeof nextCell !== 'number' || nextCell > path.length) && !path.find(({ x, y }) => next.x === x && next.y === y)) { + if (next.x === width - 1 && next.y === height - 1) { + if (fastest === null || path.length < fastest) { + fastest = path.length; + } + scores.push(path); + return; + } else if (next.x >= 0 && next.x < width && next.y >= 0 && next.y < height) { + set(next, path.length); + getScoresAfterPosition(next, newDir, [...path, next], lastBranch); + } + } + }); + + return; +} + +getScoresAfterPosition({ x: 0, y: 0 }, Dir.Up, [{ x: 0, y: 0 }]); + +console.log(scores); +const fastestScore = Math.min(...scores.map((p) => p.length)); +const fastestPath = scores.find((p) => p.length === fastestScore); +printMap(fastestPath); +console.log(fastestScore); diff --git a/2024/18/index2.ts b/2024/18/index2.ts new file mode 100644 index 0000000..75c350d --- /dev/null +++ b/2024/18/index2.ts @@ -0,0 +1,163 @@ +const fs = require('fs'); + +const input = fs.readFileSync(__dirname + '/input.txt', 'utf8').split("\n"); + +interface Coord { + x: number, + y: number, +}; + +enum Dir { + Up, + Right, + Down, + Left, +}; + +const map: Array> = []; + +const width = 71; +const height = 71; + +for (let y = 0; y < height; y++) { + if (!map[y]) { + map[y] = []; + } + for (let x = 0; x < width; x++) { + map[y][x] = '.'; + } +} + +for (let i = 0; i < 1024; i++) { + const [x, y] = input[i].split(',').map((st: string) => parseInt(st)); + map[y][x] = '#' +} + +function get(pos: Coord): string|number { + if (map[pos.y] && map[pos.y][pos.x]) { + return map[pos.y][pos.x]; + } + return '#'; +} + +function set(pos: Coord, val: string|number): 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(path: Array = []) { + const mapClone = map.slice().map((row: Array) => row.slice()); + path.forEach(({ x, y }) => { + mapClone[y][x] = 'O'; + }); + console.log(mapClone.map((row: Array) => row.map((c) => typeof c === 'number' ? '.' : c).join('')).join("\n")); + console.log("\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 { + if ((pos.x === 0 && pos.y === 0) || (pos.x === width - 1 && pos.y === width - 1)) { + return false; + } + const adjs = [Dir.Up, Dir.Right, Dir.Down, Dir.Left].map((dir) => get(nextCoord(pos, dir))).join(''); + return adjs === '###.' + || adjs === '##.#' + || adjs === '#.##' + || adjs === '.###'; +} + +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 = 0; y < height; y++) { + for (let x = 0; x < width; x++) { + const pos = { x, y }; + const char = get(pos); + if (char !== '.') { + continue; + } + if (isDeadEnd(pos)) { + fillDeadEnd(pos); + } + } +} + +printMap(); + +for (let i = 1025; i < input.length; i++) { + const byte = input[i].split(',').map((c: string) => parseInt(c)); + set({ x: byte[0], y: byte[1] }, '#'); + + for (let y = 0; y < height; y++) { + for (let x = 0; x < width; x++) { + const pos = { x, y }; + let char = get(pos); + if (typeof char === 'number') { + set(pos, '.'); + } + } + } + + let finished = false; + + function getScoresAfterPosition(pos: Coord, dir: Dir, path: Array = []): void { + if (finished) { + return; + } + [dir, nextDir(dir), prevDir(dir)].forEach((newDir, i) => { + if (finished) { + return; + } + const next = nextCoord(pos, newDir); + if (next.x === width - 1 && next.y === height - 1) { + finished = true; + return; + } + const nextCell = get(next); + if (nextCell !== '#' && (typeof nextCell !== 'number' || nextCell > path.length) && !path.find(({ x, y }) => next.x === x && next.y === y)) { + set(next, path.length); + getScoresAfterPosition(next, newDir, [...path, next]); + } + }); + + return; + } + + getScoresAfterPosition({ x: 0, y: 0 }, Dir.Right, [{ x: 0, y: 0 }]); + + console.log(i, byte); + printMap(); + if (!finished) { + console.log('blocked'); + break; + } +}