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 path: 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 { if (map[pos.y] && map[pos.y][pos.x]) { return map[pos.y][pos.x]; } return '#'; } 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 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()); path.forEach(({ x, y }) => { mapClone[y][x] = 'O'; }); console.log(mapClone.map((row: Array) => row.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(); 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; } }); 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; } 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)