Skip to content

Commit 6f52fec

Browse files
committed
preparing for optimize
1 parent 5efe6f1 commit 6f52fec

File tree

1 file changed

+40
-38
lines changed

1 file changed

+40
-38
lines changed

src/2024/day16.js

Lines changed: 40 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,64 @@
11
const opposite = { up: "down", down: "up", left: "right", right: "left" };
22

3-
function solve(input, part2 = false) {
3+
function parse(input) {
44
let map = input.split("\n").map(line => line.split(""));
55
let sy = map.findIndex(line => line.includes("S"));
66
let sx = map[sy].indexOf("S");
77
let ey = map.findIndex(line => line.includes("E"));
88
let ex = map[ey].indexOf("E");
9-
let current = { x: sx, y: sy, score: 0, dir: "right", path: ["0,0"] };
9+
return { map, start: { x: sx, y: sy }, end: { x: ex, y: ey } };
10+
}
11+
12+
function getNeighbors(current, map) {
13+
let neighbors = [
14+
{ x: current.x - 1, y: current.y, direction: "left" },
15+
{ x: current.x + 1, y: current.y, direction: "right" },
16+
{ x: current.x, y: current.y - 1, direction: "up" },
17+
{ x: current.x, y: current.y + 1, direction: "down" },
18+
]
19+
.filter(n => n.direction !== opposite[current.direction])
20+
.filter(n => map[n.y]?.[n.x] !== "#")
21+
.map(n => ({
22+
...n,
23+
path: current.path.concat(`${n.x},${n.y}`),
24+
score: current.score + (n.direction !== current.direction ? 1001 : 1),
25+
}));
26+
return neighbors;
27+
}
28+
29+
function solve(input, part2 = false) {
30+
let { map, start, end } = parse(input);
31+
let current = { ...start, score: 0, direction: "right", path: ["0,0"] };
1032
let queue = [current];
1133
let visited = new Map();
12-
let min = Infinity;
13-
let paths = [];
34+
let results = [{ score: Infinity }];
1435
visited.set(`${current.x},${current.y}`, 0);
1536
while (queue.length > 0) {
1637
current = queue.shift();
17-
if (current.x === ex && current.y === ey) {
18-
if (current.score < min) paths = [current.path];
19-
if (current.score === min) paths.push(current.path);
20-
min = Math.min(min, current.score);
38+
if (current.x === end.x && current.y === end.y) {
39+
if (current.score < results[0].score) results = [current];
40+
if (current.score === results[0].score) results.push(current);
2141
continue;
2242
}
23-
let neighbors = [
24-
{ x: current.x - 1, y: current.y, dir: "left" },
25-
{ x: current.x + 1, y: current.y, dir: "right" },
26-
{ x: current.x, y: current.y - 1, dir: "up" },
27-
{ x: current.x, y: current.y + 1, dir: "down" },
28-
]
29-
.filter(neighbor => neighbor.dir !== opposite[current.dir])
30-
.filter(neighbor => map[neighbor.y]?.[neighbor.x] !== "#")
31-
.map(neighbor => ({
32-
...neighbor,
33-
path: current.path.concat(`${neighbor.x},${neighbor.y}`),
34-
score: current.score + (neighbor.dir !== current.dir ? 1001 : 1),
35-
}));
36-
neighbors.forEach(neighbor => {
37-
if (
38-
!visited.has(`${neighbor.x},${neighbor.y},${neighbor.dir}`) ||
39-
visited.get(`${neighbor.x},${neighbor.y},${neighbor.dir}`) >
40-
neighbor.score
41-
) {
42-
queue.push(neighbor);
43-
visited.set(
44-
`${neighbor.x},${neighbor.y},${neighbor.dir}`,
45-
neighbor.score + (part2 ? 1 : 0),
46-
);
43+
getNeighbors(current, map).forEach(n => {
44+
const prev = visited.get(`${n.x},${n.y},${n.direction}`) || Infinity;
45+
// for part two we follow also paths with same score passing the same cell
46+
// this can easily be optimized by saving the path and going in only once
47+
// alternatively we could use dfs with memoization to optimize the search
48+
if (prev > n.score || (part2 && prev === n.score)) {
49+
queue.push(n);
50+
visited.set(`${n.x},${n.y},${n.direction}`, n.score);
4751
}
4852
});
4953
}
50-
return { min, paths };
54+
return results;
5155
}
5256

5357
export function part1(input) {
54-
return solve(input).min;
58+
return solve(input)[0].score;
5559
}
5660

5761
export function part2(input) {
58-
return solve(input, true).paths.reduce(
59-
(acc, path) => acc.union(new Set(path)),
60-
new Set(),
61-
).size;
62+
const results = solve(input, true).map(result => new Set(result.path));
63+
return results.reduce((acc, next) => acc.union(next)).size;
6264
}

0 commit comments

Comments
 (0)