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 obs: Array = []; let guard: { pos: Coord, dir: Dir } = { pos: { x: 0, y: 0}, dir: Dir.Up }; const keyMap: { [key: string]: (pos: Coord) => any } = { "#": (pos: Coord) => obs.push(pos), "^": (pos: Coord) => guard = { pos, dir: Dir.Up }, ">": (pos: Coord) => guard = { pos, dir: Dir.Up }, "v": (pos: Coord) => guard = { pos, dir: Dir.Up }, "<": (pos: Coord) => guard = { pos, dir: Dir.Up }, } let x = 0; let y = 0; for (let i = 0; i <= input.length; i++) { const char = input[i]; if (char === "\n") { y++; x = 0; continue; } if (keyMap[char]) { keyMap[char]({ x, y }); } x++; } const width = x; const height = y + 1; const guardStart = guard.pos; const positions: Array = [guard.pos]; function coordsMatch(a: Coord, b: Coord) { return a.x === b.x && a.y === b.y; } function getNextPosition() { if (guard.dir === Dir.Up) { return { x: guard.pos.x, y: guard.pos.y - 1 }; } if (guard.dir === Dir.Right) { return { x: guard.pos.x + 1, y: guard.pos.y }; } if (guard.dir === Dir.Down) { return { x: guard.pos.x, y: guard.pos.y + 1 }; } return { x: guard.pos.x - 1, y: guard.pos.y }; } function rotateGuard() { if (guard.dir === Dir.Up) { guard.dir = Dir.Right; } else if (guard.dir === Dir.Right) { guard.dir = Dir.Down; } else if (guard.dir === Dir.Down) { guard.dir = Dir.Left; } else { guard.dir = Dir.Up; } } function isObs(coord: Coord, otherObs: Array|null = null) { return (otherObs || obs).some((obsCoord) => coordsMatch(obsCoord, coord)); } function offMap(coord: Coord) { return coord.x >= width || coord.x < 0 || coord.y >= height || coord.y < 0; } function alreadyVisited(coord: Coord) { return positions.some((pos) => coordsMatch(pos, coord)); } while (true) { const nextPos = getNextPosition(); if (isObs(nextPos)) { rotateGuard(); continue; } if (offMap(nextPos)) { break; } guard.pos = nextPos; if (!alreadyVisited(nextPos)) { positions.push(nextPos); } } // Part 2 let loops = 0; positions.slice(1).forEach((pos, i) => { console.log(Math.floor(`${i / positions.length * 100}%`)); guard.pos = guardStart; guard.dir = Dir.Up; const newObs = [...obs, pos]; const guardPositions: Array = []; while (true) { const nextPos = getNextPosition(); if (isObs(nextPos, newObs)) { rotateGuard(); continue; } if (offMap(nextPos)) { break; } const guardPos = `${guard.pos.x},${guard.pos.y},${guard.dir}`; if (guardPositions.includes(guardPos)) { loops++; break; } guardPositions.push(guardPos); guard.pos = nextPos; } x++; }); // End Part 2 console.log(positions.length); console.log(loops);