Skip to content

Commit 85e06a5

Browse files
committed
feat: 2024 Day 21
1 parent deae5c6 commit 85e06a5

File tree

4 files changed

+140
-0
lines changed

4 files changed

+140
-0
lines changed

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import solve from "./solve.ts";
2+
3+
import { assertEquals } from "@std/assert";
4+
5+
Deno.test("example", () => {
6+
const input = `\
7+
029A
8+
980A
9+
179A
10+
456A
11+
379A`;
12+
13+
assertEquals(solve(input), 126384);
14+
});

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

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
type Paths = Record<string, Record<string, string>>;
2+
3+
const numericKeypadPaths: Paths = Object.fromEntries(
4+
[
5+
["", "^<", "^", "^>", "^^<", "^^", "^^>", "^^^<", "^^^", "^^^>", ">"],
6+
[">v", "", ">", ">>", "^", "^>", "^>>", "^^", "^^>", "^^>>", ">>v"],
7+
["v", "<", "", ">", "<^", "^", "^>", "<^^", "^^", "^^>", "v>"],
8+
["<v", "<<", "<", "", "<<^", "<^", "^", "<<^^", "<^^", "^^", "v"],
9+
[">vv", "v", "v>", "v>>", "", ">", ">>", "^", "^>", "^>>", ">>vv"],
10+
["vv", "<v", "v", "v>", "<", "", ">", "<^", "^", "^>", "vv>"],
11+
["<vv", "<<v", "<v", "v", "<<", "<", "", "<<^", "<^", "^", "vv"],
12+
[">vvv", "vv", "vv>", "vv>>", "v", "v>", "v>>", "", ">", ">>", ">>vvv"],
13+
["vvv", "<vv", "vv", "vv>", "<v", "v", "v>", "<", "", ">", "vvv>"],
14+
["<vvv", "<<vv", "<vv", "vv", "<<v", "<v", "v", "<<", "<", "", "vvv"],
15+
["<", "^<<", "<^", "^", "^^<<", "<^^", "^^", "^^^<<", "<^^^", "^^^", ""],
16+
].map((row, u) => [
17+
u.toString(11).toUpperCase(),
18+
Object.fromEntries(row.map((p, v) => [v.toString(11).toUpperCase(), p])),
19+
]),
20+
);
21+
22+
const directionalKeypadPaths: Paths = {
23+
"^": { "^": "", "v": "v", "<": "v<", ">": "v>", "A": ">" },
24+
"v": { "^": "^", "v": "", "<": "<", ">": ">", "A": "^>" },
25+
"<": { "^": ">^", "v": ">", "<": "", ">": ">>", "A": ">>^" },
26+
">": { "^": "<^", "v": "<", "<": "<<", ">": "", "A": "^" },
27+
"A": { "^": "<", "v": "<v", "<": "v<<", ">": "v", "A": "" },
28+
};
29+
30+
export default function solve(input: string) {
31+
const codes = input.split("\n");
32+
let sum = 0;
33+
for (const code of codes) {
34+
let path = code;
35+
for (let i = 0; i <= 2; i++) {
36+
let nextPath = "";
37+
let pointer = "A";
38+
const paths = i === 0 ? numericKeypadPaths : directionalKeypadPaths;
39+
for (const char of path) {
40+
nextPath += paths[pointer][char];
41+
nextPath += "A";
42+
pointer = char;
43+
}
44+
path = nextPath;
45+
}
46+
sum += path.length * parseInt(code);
47+
}
48+
return sum;
49+
}

2024/day/21/part/2/solve.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import solve from "./solve.ts";
2+
3+
import { assertEquals } from "@std/assert";
4+
5+
Deno.test("example", () => {
6+
const input = `\
7+
029A
8+
980A
9+
179A
10+
456A
11+
379A`;
12+
13+
assertEquals(solve(input, { depth: 2 }), 126384);
14+
});

2024/day/21/part/2/solve.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
type Paths = Record<string, Record<string, string>>;
2+
3+
const numericKeypadPaths: Paths = Object.fromEntries(
4+
[
5+
["", "^<", "^", "^>", "^^<", "^^", "^^>", "^^^<", "^^^", "^^^>", ">"],
6+
[">v", "", ">", ">>", "^", "^>", "^>>", "^^", "^^>", "^^>>", ">>v"],
7+
["v", "<", "", ">", "<^", "^", "^>", "<^^", "^^", "^^>", "v>"],
8+
["<v", "<<", "<", "", "<<^", "<^", "^", "<<^^", "<^^", "^^", "v"],
9+
[">vv", "v", "v>", "v>>", "", ">", ">>", "^", "^>", "^>>", ">>vv"],
10+
["vv", "<v", "v", "v>", "<", "", ">", "<^", "^", "^>", "vv>"],
11+
["<vv", "<<v", "<v", "v", "<<", "<", "", "<<^", "<^", "^", "vv"],
12+
[">vvv", "vv", "vv>", "vv>>", "v", "v>", "v>>", "", ">", ">>", ">>vvv"],
13+
["vvv", "<vv", "vv", "vv>", "<v", "v", "v>", "<", "", ">", "vvv>"],
14+
["<vvv", "<<vv", "<vv", "vv", "<<v", "<v", "v", "<<", "<", "", "vvv"],
15+
["<", "^<<", "<^", "^", "^^<<", "<^^", "^^", "^^^<<", "<^^^", "^^^", ""],
16+
].map((row, u) => [
17+
u.toString(11).toUpperCase(),
18+
Object.fromEntries(row.map((p, v) => [v.toString(11).toUpperCase(), p])),
19+
]),
20+
);
21+
22+
const directionalKeypadPaths: Paths = {
23+
"^": { "^": "", "v": "v", "<": "v<", ">": "v>", "A": ">" },
24+
"v": { "^": "^", "v": "", "<": "<", ">": ">", "A": "^>" },
25+
"<": { "^": ">^", "v": ">", "<": "", ">": ">>", "A": ">>^" },
26+
">": { "^": "<^", "v": "<", "<": "<<", ">": "", "A": "^" },
27+
"A": { "^": "<", "v": "<v", "<": "v<<", ">": "v", "A": "" },
28+
};
29+
30+
function findShortestSequenceLength(
31+
code: string,
32+
depth: number,
33+
{
34+
paths = numericKeypadPaths,
35+
seen = new Map<`${number},${string}`, number>(),
36+
} = {},
37+
): number {
38+
if (depth < 0) return code.length;
39+
const hash = `${depth},${code}` as const;
40+
if (seen.has(hash)) return seen.get(hash)!;
41+
let result = 0;
42+
let pointer = "A";
43+
const options = { paths: directionalKeypadPaths, seen };
44+
for (const char of code) {
45+
result += findShortestSequenceLength(
46+
`${paths[pointer][char]}A`,
47+
depth - 1,
48+
options,
49+
);
50+
pointer = char;
51+
}
52+
seen.set(hash, result);
53+
return result;
54+
}
55+
56+
export default function solve(input: string, { depth = 25 } = {}) {
57+
const codes = input.split("\n");
58+
let sum = 0;
59+
for (const code of codes) {
60+
sum += findShortestSequenceLength(code, depth) * parseInt(code);
61+
}
62+
return sum;
63+
}

0 commit comments

Comments
 (0)