diff --git a/2024/15/index.ts b/2024/15/index.ts new file mode 100644 index 0000000..b15c946 --- /dev/null +++ b/2024/15/index.ts @@ -0,0 +1,89 @@ +const fs = require('fs'); + +const input = fs.readFileSync(__dirname + '/input.txt', 'utf8'); + +interface Coord { + x: number, + y: number, +}; + +const [mapStr, movementsStr] = input.split("\n\n"); + +const map: Array> = mapStr.split("\n").map((row: string) => row.split('')); +const movements = movementsStr.split("\n").join(''); + +const width = map[0].length; +const height = map.length; + +const robotIndex = mapStr.indexOf('@'); +let robotPos = { x: robotIndex % (width + 1), y: Math.floor(robotIndex / height) }; +map[robotPos.y][robotPos.x] = '.'; + +function nextCoord(pos: Coord, dir: '^'|'>'|'<'|'v'): Coord|null { + const newCoord = { + "^": { x: pos.x, y: pos.y - 1 }, + ">": { x: pos.x + 1, y: pos.y }, + "v": { x: pos.x, y: pos.y + 1 }, + "<": { x: pos.x - 1, y: pos.y }, + }[dir]; + + if (newCoord.x < 0 || newCoord.x >= width || newCoord.y < 0 || newCoord.y > height) { + return null; + } + return newCoord; +} + +function printMap() { + const mapClone = map.slice().map((row: Array) => row.slice()); + mapClone[robotPos.y][robotPos.x] = '@'; + console.log(mapClone.map((row: Array) => row.join('')).join("\n")); +} + +printMap(); + +for (let i = 0; i < movements.length; i++) { + const direction = movements[i]; + + const nextRobotPosition = nextCoord(robotPos, direction); + if (!nextRobotPosition) { + continue; + } + let value = map[nextRobotPosition.y][nextRobotPosition.x]; + if (value === '#') { + continue; + } + let boxes = []; + let boxPos = {...nextRobotPosition}; + while (value === 'O') { + boxes.push(boxPos); + const nextBoxCoord = nextCoord(boxPos, direction); + if (!nextBoxCoord) { + break; + } + boxPos = nextBoxCoord; + value = map[boxPos.y][boxPos.x]; + } + if (boxes.length && value !== '#') { + boxes.reverse().forEach((pos) => { + map[pos.y][pos.x] = '.'; + const newPos = nextCoord(pos, direction)!; + map[newPos.y][newPos.x] = 'O'; + }) + } else if (boxes.length) { + continue; + } + robotPos = nextRobotPosition; + printMap(); +} + +let sum = 0; + +map.forEach((row, y) => { + row.forEach((val, x) => { + if (val === 'O') { + sum += ((y * 100) + x); + } + }); +}); + +console.log(sum); \ No newline at end of file diff --git a/2024/15/index2.ts b/2024/15/index2.ts new file mode 100644 index 0000000..c3259cd --- /dev/null +++ b/2024/15/index2.ts @@ -0,0 +1,184 @@ +const fs = require('fs'); + +const input = fs.readFileSync(__dirname + '/input.txt', 'utf8'); + +interface Coord { + x: number, + y: number, +}; + +let [mapStr, movementsStr] = input.split("\n\n"); +mapStr = mapStr.replace(/([#.])/g, '$1$1').replaceAll('O', '[]').replaceAll('@', '@.'); + +const map: Array> = mapStr.split("\n").map((row: string) => row.split('')) +const movements = movementsStr.split("\n").join(''); + +const width = map[0].length; +const height = map.length; + +const robotIndex = mapStr.indexOf('@'); +let robotPos = { x: robotIndex % (width + 1), y: Math.floor(robotIndex / width) }; +map[robotPos.y][robotPos.x] = '.'; + +function nextCoord(pos: Coord, dir: '^'|'>'|'<'|'v'): Coord { + return { + "^": { x: pos.x, y: pos.y - 1 }, + ">": { x: pos.x + 1, y: pos.y }, + "v": { x: pos.x, y: pos.y + 1 }, + "<": { x: pos.x - 1, y: pos.y }, + }[dir]; +} + +function printMap() { + const mapClone = map.slice().map((row: Array) => row.slice()); + mapClone[robotPos.y][robotPos.x] = '@'; + console.log(mapClone.map((row: Array) => row.join('')).join("\n")); +} + +printMap(); + +function get(coord: Coord) { + return map[coord.y][coord.x]; +} + +function set(coord: Coord, val: string) { + return map[coord.y][coord.x] = val; +} + +function canPushBox(leftPart: Coord, dir: '^'|'>'|'<'|'v'): boolean { + if (dir === '<') { + const next = nextCoord(leftPart, dir); + const val = get(next); + if (val === '#') { + return false; + } + if (val === ']') { + const movedNext = canPushBox(nextCoord(next, dir)!, dir); + if (!movedNext) { + return false; + } + } + return true; + } + const rightPart = nextCoord(leftPart, '>'); + if (dir === '>') { + const next = nextCoord(rightPart, dir); + const val = get(next); + if (val === '#') { + return false; + } + if (val === '[') { + const movedNext = canPushBox(next, dir); + if (!movedNext) { + return false; + } + } + return true; + } + const nextLeft = nextCoord(leftPart, dir); + const nextRight = nextCoord(rightPart, dir); + const nextLeftVal = get(nextLeft); + const nextRightVal = get(nextRight); + if (nextLeftVal === '#' || nextRightVal === '#') { + return false; + } + if (nextLeftVal === '[' || nextLeftVal === ']') { + const movedNext = canPushBox(nextLeftVal === '[' ? nextLeft : nextCoord(nextLeft, '<'), dir); + if (!movedNext) { + return false; + } + } + if (nextRightVal === '[') { + const movedNext = canPushBox(nextRight, dir); + if (!movedNext) { + return false; + } + } + return true; +} + +function pushBox(leftPart: Coord, dir: '^'|'>'|'<'|'v') { + if (dir === '<') { + const next = nextCoord(leftPart, dir); + const val = get(next); + if (val === ']') { + pushBox(nextCoord(next, dir)!, dir); + } + set(next, '['); + set(leftPart, ']'); + set(nextCoord(leftPart, '>')!, '.'); + return; + } + const rightPart = nextCoord(leftPart, '>'); + if (dir === '>') { + const next = nextCoord(rightPart, dir); + const val = get(next); + if (val === '[') { + pushBox(next, dir); + } + set(rightPart, '['); + set(next, ']'); + set(leftPart, '.'); + return; + } + const nextLeft = nextCoord(leftPart, dir); + const nextRight = nextCoord(rightPart, dir); + const nextLeftVal = get(nextLeft); + const nextRightVal = get(nextRight); + if (nextLeftVal === '[' || nextLeftVal === ']') { + pushBox(nextLeftVal === '[' ? nextLeft : nextCoord(nextLeft, '<'), dir); + } + if (nextRightVal === '[') { + pushBox(nextRight, dir); + } + set(nextLeft, '['); + set(nextRight, ']'); + set(leftPart, '.'); + set(rightPart, '.'); +} + +function sleep() { + const promise: Promise = new Promise((resolve) => { + setTimeout(() => resolve(), 50); + }); + return promise; +} + +async function go() { + for (let i = 0; i < movements.length; i++) { + const direction = movements[i]; + + const nextRobotPosition = nextCoord(robotPos, direction); + let value = get(nextRobotPosition); + if (value === '#') { + printMap(); + continue; + } + if (value === '[' || value === ']') { + const leftBoxCoord = value === '[' ? nextRobotPosition : nextCoord(nextRobotPosition, '<'); + if (canPushBox(leftBoxCoord, direction)) { + pushBox(leftBoxCoord, direction); + } else { + printMap(); + continue; + } + } + robotPos = nextRobotPosition; + printMap(); + await sleep(); + } + + let sum = 0; + + map.forEach((row, y) => { + row.forEach((val, x) => { + if (val === '[') { + sum += ((y * 100) + x); + } + }); + }); + + console.log(sum); +} + +go(); \ No newline at end of file