Files
2024-12-19 15:20:16 +01:00

168 lines
4.2 KiB
TypeScript

// @ts-ignore
import { astar, Graph } from 'javascript-astar';
import { replaceChar } from '../../utils/array.ts';
import {
type Coordinate,
inBounds,
isCoordinateEqual
} from '../../utils/coordinates.ts';
import { MultiMap } from '../../utils/multi-map.ts';
import { PriorityQueue } from '../../utils/queue.ts';
function getGraph(
allBytes: [number, number][],
byteCount: number,
height: number,
width: number
): Graph {
const bytes = allBytes.slice(0, byteCount);
const map = new Array(height)
.fill(null)
.map((_, y) =>
new Array(width)
.fill(0)
.map((_, x) =>
bytes.findIndex((c) => isCoordinateEqual(c, [x, y])) >= 0 ? 0 : 1
)
);
return new Graph(map);
}
export function solveFirst(
input: string,
width = 71,
height = 71,
byteCount = 1024
): number {
const match = input.matchAll(/^(\d*),(\d*)/gm);
const allBytes = Array.from(
match,
(m) => m.slice(1, 3).map(Number) as Coordinate
);
const graph = getGraph(allBytes, byteCount, height, width);
const start = graph.grid[0][0];
const end = graph.grid[height - 1][width - 1];
const result = astar.search(graph, start, end);
return result.length;
}
export function solveSecond(
input: string,
width = 71,
height = 71,
byteCount = 1024
): string {
const match = input.matchAll(/^(\d*),(\d*)/gm);
const allBytes = Array.from(
match,
(m) => m.slice(1, 3).map(Number) as Coordinate
);
// let lastPath: Coordinates = [];
for (let i = byteCount; i < allBytes.length; i++) {
const nextByte = allBytes[i];
// if (
// lastPath.length > 0 &&
// !lastPath.some((p) => isCoordinateEqual(p, nextByte))
// ) {
// console.log(lastPath);
// continue;
// }
const graph = getGraph(allBytes, i + 1, height, width);
const start = graph.grid[0][0];
const end = graph.grid[height - 1][width - 1];
const result = astar.search(graph, start, end);
if (result.length <= 0) {
return nextByte.join(',');
}
// lastPath = result.map((n: GridNode) => [n.x, n.y] as Coordinate);
}
return '';
}
export function solveFirstOld(
input: string,
width = 71,
height = 71,
byteCount = 1024
): number {
const match = input.matchAll(/^(\d*),(\d*)/gm);
const bytes = Array.from(
match,
(m) => m.slice(1, 3).map(Number) as Coordinate
).slice(0, byteCount);
const map = new Array(height)
.fill(null)
.map(() => new Array(width).fill('.').join('') as string);
bytes.forEach(([x, y]) => replaceChar(map, x, y, '#'));
replaceChar(map, width - 1, height - 1, 'E');
console.log(map.join('\n'));
const start = { x: 0, y: 0, score: 0 };
const possibleOptions = new PriorityQueue<typeof start>();
possibleOptions.enqueue(start, 0);
const visited = new Set<`${number}:${number}`>();
const scores = new MultiMap<number, Coordinate>();
visited.add(`${start.x}:${start.y}`);
let i = 0;
while (possibleOptions.size() > 0) {
const el = possibleOptions.dequeue()!!;
scores.multiSet(el.node.score, el.node.y, el.node.x);
visited.add(`${el.node.x}:${el.node.y}`);
if (map[el.node.y]?.[el.node.x] === 'E') {
// console.log(visited);
return el.node.score;
}
if (possibleOptions.size() % 10_000 === 0) {
console.log(visited.size, possibleOptions.size());
}
for (let [x, y] of [
[0, 1],
[0, -1],
[1, 0],
[-1, 0]
]) {
const nx = el.node.x + x;
const ny = el.node.y + y;
const score = el.node.score + 1;
if (!inBounds(width, height)([nx, ny]) || map[ny]?.[nx] === '#') {
continue;
}
if (visited.has(`${nx}:${ny}`)) {
continue;
}
const existingScore = scores.multiGet(ny, nx) || Number.MAX_SAFE_INTEGER;
if (score < existingScore) {
possibleOptions.enqueue({ x: nx, y: ny, score }, score);
}
}
// console.log('a', el.node, visited.size, possibleOptions.size());
// return 0;
i++;
if (i >= 10_000_000) {
visited.forEach((v) => {
const [x, y] = v.split(':').map(Number);
replaceChar(map, x, y, 'O');
});
console.log(map.join('\n'));
return 0;
}
}
return 0;
}