Day 16 so far
This commit is contained in:
158
2024/16/index.ts
Normal file
158
2024/16/index.ts
Normal file
@@ -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<Array<string>> = 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<string>) => row.slice());
|
||||
console.log(mapClone.map((row: Array<string>) => 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<number> = [];
|
||||
|
||||
function getScoresAfterPosition(pos: Coord, dir: Dir, currentScore = 0, path: Array<string> = [], 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));
|
||||
Reference in New Issue
Block a user