Skip to content

Commit 71a0bd6

Browse files
committed
13/2024
1 parent 53e2bfa commit 71a0bd6

File tree

2 files changed

+128
-0
lines changed

2 files changed

+128
-0
lines changed

2024/13/index.ts

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import { getPuzzle } from "../../utils";
2+
3+
const puzzleInput = getPuzzle(__dirname).trim();
4+
5+
const configs = puzzleInput.split("\n\n").map((prizeConfig) => {
6+
const [buttonA, buttonB, prize] = prizeConfig.split("\n");
7+
8+
const [buttonAX, buttonAY] = buttonA
9+
.replace("Button A: X+", "")
10+
.replace("Y+", "")
11+
.split(", ")
12+
.map(Number);
13+
14+
const [buttonBX, buttonBY] = buttonB
15+
.replace("Button B: X+", "")
16+
.replace("Y+", "")
17+
.split(", ")
18+
.map(Number);
19+
20+
const [prizeX, prizeY] = prize
21+
.replace("Prize: X=", "")
22+
.replace("Y=", "")
23+
.split(", ")
24+
.map(Number);
25+
26+
return {
27+
buttonA: { x: buttonAX, y: buttonAY },
28+
buttonB: { x: buttonBX, y: buttonBY },
29+
prize: { x: prizeX, y: prizeY },
30+
};
31+
});
32+
33+
// Part 1
34+
(() => {
35+
console.time("part 1");
36+
let tokensSpent = 0;
37+
38+
for (const config of configs) {
39+
let lowestTokenCount: number = undefined;
40+
let currentTokenCount = 0;
41+
let x = 0;
42+
let y = 0;
43+
44+
while (true) {
45+
if (x > config.prize.x || y > config.prize.y) {
46+
break;
47+
}
48+
49+
x += config.buttonA.x;
50+
y += config.buttonA.y;
51+
currentTokenCount += 3;
52+
53+
const remainingX = config.prize.x - x;
54+
const remainingY = config.prize.y - y;
55+
56+
if (
57+
remainingX % config.buttonB.x === 0 &&
58+
remainingY % config.buttonB.y === 0 &&
59+
remainingX / config.buttonB.x === remainingY / config.buttonB.y
60+
) {
61+
const buttonBCost = remainingX / config.buttonB.x;
62+
63+
if (
64+
typeof lowestTokenCount === "undefined" ||
65+
buttonBCost + currentTokenCount < lowestTokenCount
66+
) {
67+
lowestTokenCount = buttonBCost + currentTokenCount;
68+
}
69+
}
70+
}
71+
72+
if (lowestTokenCount) {
73+
tokensSpent += lowestTokenCount;
74+
}
75+
}
76+
77+
console.log("part 1 tokens spent ::", tokensSpent);
78+
console.timeEnd("part 1");
79+
})();
80+
81+
// Part 2
82+
(() => {
83+
console.time("part 2");
84+
let tokensSpent = 0;
85+
86+
const EXTRA_DISTANCE = 10000000000000;
87+
88+
for (const config of configs) {
89+
/*
90+
* [Cramer's Rule for a 2x2 system]
91+
*
92+
* a = a button presses
93+
* ax & ay = a button distances
94+
* b = b button presses
95+
* bx & by = b button distances
96+
* cx & cy = prize position
97+
*
98+
* (a*ax) + (b*bx) = cx
99+
* (a*ay) + (b*by) = cy
100+
*
101+
* a = (by*cx - bx*cy) / (ax*by - ay*bx)
102+
* b = (ax*cy - ay*cx) / (ax*by - ay*bx)
103+
*/
104+
105+
const prizeX = config.prize.x + EXTRA_DISTANCE;
106+
const prizeY = config.prize.y + EXTRA_DISTANCE;
107+
108+
const divisor =
109+
config.buttonA.x * config.buttonB.y - config.buttonA.y * config.buttonB.x;
110+
111+
const aPresses =
112+
(config.buttonB.y * prizeX - config.buttonB.x * prizeY) / divisor;
113+
114+
const bPresses =
115+
(config.buttonA.x * prizeY - config.buttonA.y * prizeX) / divisor;
116+
117+
if (
118+
Math.floor(aPresses) === aPresses &&
119+
Math.floor(bPresses) === bPresses
120+
) {
121+
tokensSpent += aPresses * 3 + bPresses;
122+
}
123+
}
124+
125+
console.log("part 2 tokens spent ::", tokensSpent);
126+
console.timeEnd("part 2");
127+
})();

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
| Day | Part 1 | Part 2 |
88
| :----------------------------------------: | :----: | :----: |
9+
| [13](https://adventofcode.com/2024/day/13) |||
910
| [12](https://adventofcode.com/2024/day/12) |||
1011
| [11](https://adventofcode.com/2024/day/11) |||
1112
| [10](https://adventofcode.com/2024/day/10) |||

0 commit comments

Comments
 (0)