Skip to content

Commit f5c785e

Browse files
committed
2024D21: part 2 refactor
1 parent 796725c commit f5c785e

File tree

2 files changed

+83
-49
lines changed

2 files changed

+83
-49
lines changed

2024/src/2024/day21/day21.test.ts

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import {encodeFirstLevel, encodeSecondLevel, part1 } from "./day21";
2-
import { part2 } from "./extra";
1+
import {encodeFirstLevel, encodeSecondLevel, part1, part2 } from "./day21";
32
import {readInputLineByLine} from "@utils/io";
43

54
describe('2024 Day 21', () => {
@@ -13,13 +12,8 @@ describe('2024 Day 21', () => {
1312
});
1413

1514
test('Part 2', async () => {
16-
// expect(await part2('testInput1')).toEqual(31);
17-
expect(part2(["671A",
18-
"083A",
19-
"582A",
20-
"638A",
21-
"341A"])).toEqual(204040805018350);
22-
15+
expect(await part2('testInput1')).toEqual(154115708116294);
16+
expect(await part2("input")).toEqual(204040805018350);
2317
});
2418

2519
test('encode first level', () => {

2024/src/2024/day21/day21.ts

Lines changed: 80 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -48,54 +48,94 @@ function calcComplexities(lines: string[]) {
4848
}
4949

5050
function calcComplexities2(lines: string[]) {
51-
let complexityCount = 0;
52-
53-
for (const line of lines) {
54-
let minLength = Infinity;
55-
const num = Number.parseInt(line.replace('A', ''));
56-
57-
const level3List: string[] = [];
58-
const level1 = encodeFirstLevel(line);
59-
for (const l1 of level1) {
60-
const level2 = encodeSecondLevel(l1);
51+
const memo: { [key: string]: number } = {};
6152

62-
for (const l2 of level2) {
63-
const level3 = encodeSecondLevel(l2);
53+
return lines.reduce((sum, code) => {
54+
const numerical = parseInt((code.split('').filter(character => character.match(/\d/)).join('')));
55+
return sum + numerical * getKeyPresses(KEYPAD, code, 25, memo);
56+
}, 0);
57+
}
6458

65-
for (const l3 of level3) {
66-
for (const l4 of encodeSecondLevel(l3)) {
67-
for (const l5 of encodeSecondLevel(l4)) {
68-
for (const l6 of encodeSecondLevel(l5)) {
69-
for (const l7 of encodeSecondLevel(l6)) {
70-
for (const l8 of encodeSecondLevel(l7)) {
71-
for (const l9 of encodeSecondLevel(l8)) {
72-
for (const l10 of encodeSecondLevel(l9)) {
73-
if (l10.length < minLength) {
74-
level3List.push(l10);
75-
minLength = l10.length;
76-
}
77-
}
78-
}
79-
}
80-
}
81-
}
82-
}
83-
}
59+
const BFS_DIRECTIONS = {
60+
'^': new Coord(0, -1),
61+
'>': new Coord(1, 0),
62+
'v': new Coord(0, 1),
63+
'<': new Coord(-1, 0)
64+
};
65+
66+
const KEYPAD: { [key: string]: Coord } = {
67+
7: new Coord(0, 0),
68+
8: new Coord(1, 0),
69+
9: new Coord(2, 0),
70+
4: new Coord(0, 1),
71+
5: new Coord(1, 1),
72+
6: new Coord(2, 1),
73+
1: new Coord(0, 2),
74+
2: new Coord(1, 2),
75+
3: new Coord(2, 2),
76+
X: new Coord(0, 3),
77+
0: new Coord(1, 3),
78+
A: new Coord(2, 3)
79+
};
80+
81+
const DIRECTIONS: { [key: string]: Coord } = {
82+
X: new Coord(0, 0),
83+
'^': new Coord(1, 0),
84+
A: new Coord(2, 0),
85+
'<': new Coord(0, 1),
86+
'v': new Coord(1, 1),
87+
'>': new Coord(2, 1)
88+
};
89+
90+
const getCommand = (input: { [key: string]: Coord }, start: string, end: string) => {
91+
const queue = [{ ...input[start], path: '' }];
92+
const distances: { [key: string]: number } = {};
93+
94+
if (start === end) return ['A'];
95+
96+
let allPaths: string[] = [];
97+
while (queue.length) {
98+
const current = queue.shift();
99+
if (current === undefined) break;
100+
101+
if (current.x === input[end].x && current.y === input[end].y) allPaths.push(current.path + 'A');
102+
if (distances[`${current.x},${current.y}`] !== undefined && distances[`${current.x},${current.y}`] < current.path.length) continue;
103+
104+
Object.entries(BFS_DIRECTIONS).forEach(([direction, vector]) => {
105+
const position = { x: current.x + vector.x, y: current.y + vector.y };
106+
107+
if (input.X.x === position.x && input.X.y === position.y) return;
108+
109+
const button = Object.values(input).find(button => button.x === position.x && button.y === position.y);
110+
if (button !== undefined) {
111+
const newPath = current.path + direction;
112+
if (distances[`${position.x},${position.y}`] === undefined || distances[`${position.x},${position.y}`] >= newPath.length) {
113+
queue.push({ ...position, path: newPath });
114+
distances[`${position.x},${position.y}`] = newPath.length;
84115
}
85116
}
86-
}
87-
88-
level3List.sort((a, b) => a.length - b.length);
89-
complexityCount += num * level3List[0].length;
117+
});
90118
}
91-
return complexityCount;
92-
}
93119

94-
function uniqueLengths(arr: string[]): number[] {
95-
const lengths = arr.map(str => str.length); // Get lengths of all strings
96-
return [...new Set(lengths)]; // Use Set to get unique lengths and convert back to array
120+
return allPaths.sort((a, b) => a.length - b.length);
97121
}
98122

123+
const getKeyPresses = (input: { [key: string]: Coord }, code: string, robot: number, memo: { [key: string]: number }): number => {
124+
const key = `${code},${robot}`;
125+
if (memo[key] !== undefined) return memo[key];
126+
127+
let current = 'A';
128+
let length = 0;
129+
for (let i = 0; i < code.length; i++) {
130+
const moves = getCommand(input, current, code[i]);
131+
if (robot === 0) length += moves[0].length;
132+
else length += Math.min(...moves.map(move => getKeyPresses(DIRECTIONS, move, robot - 1, memo)));
133+
current = code[i];
134+
}
135+
136+
memo[key] = length;
137+
return length;
138+
}
99139

100140
// +---+---+---+
101141
// | 7 | 8 | 9 | 0,0 1,0 2,0

0 commit comments

Comments
 (0)