Skip to content

Commit 245e630

Browse files
committed
feat: 2024 Day 20 Part 1
1 parent 3de357d commit 245e630

File tree

2 files changed

+106
-0
lines changed

2 files changed

+106
-0
lines changed

2024/day/20/part/1/solve.test.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import solve, { findSavedTimeCountsByCheating, parseTrack } from "./solve.ts";
2+
3+
import { assertEquals } from "@std/assert";
4+
5+
Deno.test("example", () => {
6+
const input = `\
7+
###############
8+
#...#...#.....#
9+
#.#.#.#.#.###.#
10+
#S#...#.#.#...#
11+
#######.#.#.###
12+
#######.#.#...#
13+
#######.#.###.#
14+
###..E#...#...#
15+
###.#######.###
16+
#...###...#...#
17+
#.#####.#.###.#
18+
#.#...#.#.#...#
19+
#.#.#.#.#.#.###
20+
#...#...#...###
21+
###############`;
22+
23+
const track = parseTrack(input);
24+
25+
assertEquals(
26+
findSavedTimeCountsByCheating(track),
27+
new Map([
28+
[2, 14],
29+
[4, 14],
30+
[6, 2],
31+
[8, 4],
32+
[10, 2],
33+
[12, 3],
34+
[20, 1],
35+
[36, 1],
36+
[38, 1],
37+
[40, 1],
38+
[64, 1],
39+
]),
40+
);
41+
});

2024/day/20/part/1/solve.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
const directions = [[0, -1], [0, 1], [-1, 0], [1, 0]];
2+
3+
const factorials = [1, 1, 2];
4+
5+
export function parseTrack(text: string) {
6+
return text.split("\n").map((line) => [...line]);
7+
}
8+
9+
function buildTimeTrack(track: string[][]) {
10+
const result = track.map((row) => row.map(() => Infinity));
11+
const yf = track.findIndex((line) => line.includes("E")),
12+
xf = track[yf].indexOf("E");
13+
const stack = [[xf, yf, 0]];
14+
const seen = new Set<`${number},${number}`>();
15+
while (stack.length) {
16+
// console.log(stack.at(-1));
17+
const [x, y, t] = stack.pop()!;
18+
const hash = `${x},${y}` as const;
19+
if (seen.has(hash)) continue;
20+
seen.add(hash);
21+
if (track[y][x] === "#") continue;
22+
result[y][x] = t;
23+
for (const [dx, dy] of directions) stack.push([x + dx, y + dy, t + 1]);
24+
}
25+
return result;
26+
}
27+
28+
function* manhattanDirections(d: number) {
29+
for (let offset = 0; offset < d; offset++) {
30+
const complement = d - offset;
31+
yield [offset, complement];
32+
yield [complement, -offset];
33+
yield [-offset, -complement];
34+
yield [-complement, offset];
35+
}
36+
}
37+
38+
export function findSavedTimeCountsByCheating(track: string[][]) {
39+
const result = new Map<number, number>();
40+
const timeTrack = buildTimeTrack(track);
41+
for (let y = 0; y < timeTrack.length; y++) {
42+
for (let x = 0; x < timeTrack[y].length; x++) {
43+
const t = timeTrack[y][x];
44+
if (t === Infinity) continue;
45+
for (const [dx, dy] of manhattanDirections(2)) {
46+
const rt = timeTrack[y + dy]?.[x + dx];
47+
if (!isFinite(rt)) continue;
48+
const saved = t - rt - 2;
49+
if (saved <= 0) continue;
50+
const ax = Math.abs(dx), ay = Math.abs(dy);
51+
const count = factorials[2] / (factorials[ax] * factorials[ay]);
52+
result.set(saved, (result.get(saved) ?? 0) + count);
53+
}
54+
}
55+
}
56+
return result;
57+
}
58+
59+
export default function solve(input: string) {
60+
const track = parseTrack(input);
61+
let sum = 0;
62+
const savedTimeCounts = findSavedTimeCountsByCheating(track);
63+
for (const [saved, count] of savedTimeCounts) if (saved >= 100) sum += count;
64+
return sum;
65+
}

0 commit comments

Comments
 (0)