tangled
alpha
login
or
join now
hauleth.dev
/
advent-of-code
3
fork
atom
this repo has no description
3
fork
atom
overview
issues
pulls
pipelines
2024 day 13
hauleth.dev
1 year ago
78fd5a1d
e85c74bf
verified
This commit was signed with the committer's
known signature
.
hauleth.dev
SSH Key Fingerprint:
SHA256:1hEP8QO8nM2KQfQ8jK4Q19y/CmqVZQI/cNSht3c1QlI=
+272
1 changed file
expand all
collapse all
unified
split
2024
day13.livemd
+272
2024/day13.livemd
···
1
1
+
<!-- livebook:{"persist_outputs":true} -->
2
2
+
3
3
+
# Day 13
4
4
+
5
5
+
```elixir
6
6
+
Mix.install([:kino_aoc])
7
7
+
```
8
8
+
9
9
+
## Section
10
10
+
11
11
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiIxMyIsInNlc3Npb25fc2VjcmV0IjoiQURWRU5UX09GX0NPREVfU0VTU0lPTiIsInllYXIiOiIyMDI0In0","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
12
12
+
13
13
+
```elixir
14
14
+
{:ok, puzzle_input} =
15
15
+
KinoAOC.download_puzzle("2024", "13", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
16
16
+
```
17
17
+
18
18
+
<!-- livebook:{"output":true} -->
19
19
+
20
20
+
```
21
21
+
{:ok,
22
22
+
"Button A: X+22, Y+88\nButton B: X+90, Y+28\nPrize: X=6496, Y=3076\n\nButton A: X+54, Y+14\nButton B: X+14, Y+44\nPrize: X=8084, Y=1284\n\nButton A: X+96, Y+15\nButton B: X+55, Y+63\nPrize: X=5535, Y=3966\n\nButton A: X+17, Y+42\nButton B: X+40, Y+25\nPrize: X=12176, Y=3136\n\nButton A: X+87, Y+31\nButton B: X+15, Y+36\nPrize: X=6672, Y=2500\n\nButton A: X+59, Y+27\nButton B: X+21, Y+56\nPrize: X=1475, Y=15098\n\nButton A: X+39, Y+51\nButton B: X+98, Y+14\nPrize: X=7890, Y=3126\n\nButton A: X+23, Y+37\nButton B: X+35, Y+14\nPrize: X=16537, Y=6184\n\nButton A: X+21, Y+89\nButton B: X+74, Y+23\nPrize: X=2407, Y=8748\n\nButton A: X+47, Y+17\nButton B: X+35, Y+59\nPrize: X=17994, Y=16242\n\nButton A: X+14, Y+45\nButton B: X+52, Y+16\nPrize: X=18768, Y=3912\n\nButton A: X+29, Y+45\nButton B: X+85, Y+11\nPrize: X=3149, Y=4161\n\nButton A: X+81, Y+95\nButton B: X+67, Y+12\nPrize: X=5489, Y=2110\n\nButton A: X+48, Y+58\nButton B: X+86, Y+22\nPrize: X=4802, Y=2280\n\nButton A: X+27, Y+59\nButton B: X+47, Y+15\nPrize: X=2602, Y=2090\n\nButton A: X+39, Y+87\nButton B: X+94, Y+38\nPrize: X=8830, Y=6134\n\nButton A: X+23, Y+61\nButton B: X+82, Y+16\nPrize: X=8405, Y=3957\n\nButton A: X+54, Y+14\nButton B: X+24, Y+63\nPrize: X=894, Y=1708\n\nButton A: X+26, Y+14\nButton B: X+18, Y+35\nPrize: X=5510, Y=12541\n\nButton A: X+65, Y+55\nButton B: X+21, Y+69\nPrize: X=430, Y=620\n\nButton A: X+11, Y+62\nButton B: X+50, Y+11\nPrize: X=11414, Y=3683\n\nButton A: X+21, Y+54\nButton B: X+93, Y+22\nPrize: X=7683, Y=5642\n\nButton A: X+20, Y+95\nButton B: X+52, Y+29\nPrize: X=5580, Y=10155\n\nButton A: X+37, Y+13\nButton B: X+11, Y+66\nPrize: X=18250, Y=14983\n\nButton A: X+54, Y+28\nButton B: X+37, Y+58\nPrize: X=17939, Y=14902\n\nButton A: X+87, Y+65\nButton B: X+11, Y+79\nPrize: X=3765, Y=4087\n\nButton A: X+74, Y+30\nButton B: X+16, Y+59\nPrize: X=9858, Y=8342\n\nButton A: X+74, Y+31\nButton B: X+17, Y+59\nPrize: X=14764, Y=6598\n\nButton A: X+12, Y+95\nButton B: X+27, Y+33\nPrize: X=945, Y=3324\n\nButton A: X+21, Y+36\nButton B: X+34, Y+14\nPrize: X=7247, Y=5012\n\nButton A: X+48, Y+62\nButton B: X+90, Y+29\nPrize: X=9150, Y=5973\n\nButton A: X+93, Y+43\nButton B: X+49, Y+91\nPrize: X=7090, Y=6422\n\nButton A: X+28, Y+70\nButton B: X+68, Y+21\nPrize: X=17176, Y=3693\n\nButton A: X+33, Y+16\nButton B: X+27, Y+51\nPrize: X=1884, Y=2771\n\nButton A: X+11, Y+43\nButton B: X+51, Y+19\nPrize: X=4114, Y=10066\n\nButton A: X+26, Y+70\nButton B: X+87, Y+46\nPrize: X=3532, Y=6874\n\nButton A: X+22, Y+35\nButton B: X+38, Y+13\nPrize: X=7508, Y=16592\n\nButton A: X+33, Y+16\nButton B: X+48, Y+72\nPrize: X=12065, Y=15896\n\nButton A: X+67, Y+25\nButton B: X+14, Y+55\nPrize: X=4093, Y=10275\n\nButton A: X+36, Y+17\nButton B: X+43, Y+77\nPrize: X=3253, Y=1933\n\nButton A: X+84, Y+24\nButton B: X+42, Y+69\nPrize: X=8862, Y=4869\n\nButton A: X+70, Y+16\nButton B: X+17, Y+68\nPrize: X=5690, Y=3224\n\nButton A: X+58, Y+27\nButton B: X+44, Y+92\nPrize: X=1890, Y=1595\n\nButton A: X+64, Y+30\nButton B: X+29, Y+57\nPrize: X=15004, Y=15224\n\nButton A: X+13, Y+90\nButton B: X+64, Y+33\nPrize: X=6560, Y=6048\n\nButton A: X+37, Y+91\nButton B: X+64, Y+49\nPrize: X=5214, Y=8379\n\nButton A: X+12, Y+80\nButton B: X+75, Y+25\nPrize: X=6684, Y=8460\n\nButton A: X+27, Y+53\nButton B: X+53, Y+30\nPrize: X=4897, Y=14148\n\nButton A: X+41, Y+11\nButton B: X+39, Y+72\nPrize: X=2818, Y=493\n\nButton A: X+74, Y+45\nButton B: X+14, Y+35\nPrize: X=8996, Y=13510\n\nButton A: X+11, Y+36\nButton B: X+86, Y+58\nPrize: X=18273, Y=14722\n\nButton A: X+99, Y+72\nButton B: X+11, Y+39\nPrize: X=2530, Y=3390\n\nButton A: X+55, Y+17\nButton B: X+22, Y+80\nPrize: X=3652, Y=6326\n\nButton A: X+11, Y+17\nButton B: X+76, Y+16\nPrize: X=5480, Y=1976\n\nButton A: X+18, Y+73\nButton B: X+28, Y+22\nPrize: X=3222, Y=4827\n\nButton A: X+14, Y+46\nButton B: X+33, Y+29\nPrize: X=2212, Y=3932\n\nButton A: X+11, Y+14\nButton B: X+80, Y+28\nPrize: X=4187, Y=2450\n\nButton A: X+28, Y+70\nButton B: X+78, Y+25\nPrize: X=2220, Y=1810\n\nButton A: X+53, Y+19\nButton B: X+73, Y+91\nPrize: X=4514, Y=2850\n\nButton A: X+21, Y+54\nButton B: X+54, Y+25\nPrize: X=5609, Y=7594\n\nButton A: X+79, Y+15\nButton B: X+16, Y+80\nPrize: X=14993, Y=17105\n\nButton A: X+20, Y+59\nButton B: X+35, Y+17\nPrize: X=10820, Y=1709\n\nButton A: X+96, Y+22\nButton B: X+24, Y+43\n" <> ...}
23
23
+
```
24
24
+
25
25
+
```elixir
26
26
+
#puzzle_input =
27
27
+
"""
28
28
+
Button A: X+94, Y+34
29
29
+
Button B: X+22, Y+67
30
30
+
Prize: X=8400, Y=5400
31
31
+
32
32
+
Button A: X+26, Y+66
33
33
+
Button B: X+67, Y+21
34
34
+
Prize: X=12748, Y=12176
35
35
+
36
36
+
Button A: X+17, Y+86
37
37
+
Button B: X+84, Y+37
38
38
+
Prize: X=7870, Y=6450
39
39
+
40
40
+
Button A: X+69, Y+23
41
41
+
Button B: X+27, Y+71
42
42
+
Prize: X=18641, Y=10279
43
43
+
"""
44
44
+
```
45
45
+
46
46
+
<!-- livebook:{"output":true} -->
47
47
+
48
48
+
```
49
49
+
warning: outdented heredoc line. The contents inside the heredoc should be indented at the same level as the closing """. The following is forbidden:
50
50
+
51
51
+
def text do
52
52
+
"""
53
53
+
contents
54
54
+
"""
55
55
+
end
56
56
+
57
57
+
Instead make sure the contents are indented as much as the heredoc closing:
58
58
+
59
59
+
def text do
60
60
+
"""
61
61
+
contents
62
62
+
"""
63
63
+
end
64
64
+
65
65
+
The current heredoc line is indented too little
66
66
+
└─ Workspace/hauleth/advent-of-code/2024/day13.livemd#cell:b6uoz4dag7jywljr:3:3
67
67
+
68
68
+
```
69
69
+
70
70
+
<!-- livebook:{"output":true} -->
71
71
+
72
72
+
```
73
73
+
"Button A: X+94, Y+34\nButton B: X+22, Y+67\nPrize: X=8400, Y=5400\n\nButton A: X+26, Y+66\nButton B: X+67, Y+21\nPrize: X=12748, Y=12176\n\nButton A: X+17, Y+86\nButton B: X+84, Y+37\nPrize: X=7870, Y=6450\n\nButton A: X+69, Y+23\nButton B: X+27, Y+71\nPrize: X=18641, Y=10279\n"
74
74
+
```
75
75
+
76
76
+
```elixir
77
77
+
games =
78
78
+
puzzle_input
79
79
+
|> String.split("\n\n", trim: true)
80
80
+
|> Enum.map(fn game ->
81
81
+
[
82
82
+
"Button A: X+" <> <<ax::2-binary>> <> ", Y+" <> <<ay::2-binary>>,
83
83
+
"Button B: X+" <> <<bx::2-binary>> <> ", Y+" <> <<by::2-binary>>,
84
84
+
"Prize: " <> prize_pos
85
85
+
] = String.split(game, "\n", trim: true)
86
86
+
87
87
+
["X=" <> px, "Y=" <> py] = String.split(prize_pos, ", ")
88
88
+
89
89
+
%{
90
90
+
btn_a: {String.to_integer(ax), String.to_integer(ay)},
91
91
+
btn_b: {String.to_integer(bx), String.to_integer(by)},
92
92
+
prize: {String.to_integer(px), String.to_integer(py)}
93
93
+
}
94
94
+
end)
95
95
+
```
96
96
+
97
97
+
<!-- livebook:{"output":true} -->
98
98
+
99
99
+
```
100
100
+
[
101
101
+
%{btn_a: {22, 88}, btn_b: {90, 28}, prize: {6496, 3076}},
102
102
+
%{btn_a: {54, 14}, btn_b: {14, 44}, prize: {8084, 1284}},
103
103
+
%{btn_a: {96, 15}, btn_b: {55, 63}, prize: {5535, 3966}},
104
104
+
%{btn_a: {17, 42}, btn_b: {40, 25}, prize: {12176, 3136}},
105
105
+
%{btn_a: {87, 31}, btn_b: {15, 36}, prize: {6672, 2500}},
106
106
+
%{btn_a: {59, 27}, btn_b: {21, 56}, prize: {1475, 15098}},
107
107
+
%{btn_a: {39, 51}, btn_b: {98, 14}, prize: {7890, 3126}},
108
108
+
%{btn_a: {23, 37}, btn_b: {35, 14}, prize: {16537, 6184}},
109
109
+
%{btn_a: {21, 89}, btn_b: {74, 23}, prize: {2407, 8748}},
110
110
+
%{btn_a: {47, 17}, btn_b: {35, 59}, prize: {17994, 16242}},
111
111
+
%{btn_a: {14, 45}, btn_b: {52, 16}, prize: {18768, 3912}},
112
112
+
%{btn_a: {29, 45}, btn_b: {85, 11}, prize: {3149, 4161}},
113
113
+
%{btn_a: {81, 95}, btn_b: {67, 12}, prize: {5489, 2110}},
114
114
+
%{btn_a: {48, 58}, btn_b: {86, 22}, prize: {4802, 2280}},
115
115
+
%{btn_a: {27, 59}, btn_b: {47, 15}, prize: {2602, 2090}},
116
116
+
%{btn_a: {39, 87}, btn_b: {94, 38}, prize: {8830, 6134}},
117
117
+
%{btn_a: {23, 61}, btn_b: {82, 16}, prize: {8405, 3957}},
118
118
+
%{btn_a: {54, 14}, btn_b: {24, 63}, prize: {894, 1708}},
119
119
+
%{btn_a: {26, 14}, btn_b: {18, 35}, prize: {5510, 12541}},
120
120
+
%{btn_a: {65, 55}, btn_b: {21, 69}, prize: {430, 620}},
121
121
+
%{btn_a: {11, 62}, btn_b: {50, 11}, prize: {11414, 3683}},
122
122
+
%{btn_a: {21, 54}, btn_b: {93, 22}, prize: {7683, 5642}},
123
123
+
%{btn_a: {20, 95}, btn_b: {52, 29}, prize: {5580, 10155}},
124
124
+
%{btn_a: {37, 13}, btn_b: {11, 66}, prize: {18250, 14983}},
125
125
+
%{btn_a: {54, 28}, btn_b: {37, 58}, prize: {17939, 14902}},
126
126
+
%{btn_a: {87, 65}, btn_b: {11, 79}, prize: {3765, 4087}},
127
127
+
%{btn_a: {74, 30}, btn_b: {16, 59}, prize: {9858, 8342}},
128
128
+
%{btn_a: {74, 31}, btn_b: {17, 59}, prize: {14764, 6598}},
129
129
+
%{btn_a: {12, 95}, btn_b: {27, 33}, prize: {945, 3324}},
130
130
+
%{btn_a: {21, 36}, btn_b: {34, 14}, prize: {7247, 5012}},
131
131
+
%{btn_a: {48, 62}, btn_b: {90, 29}, prize: {9150, 5973}},
132
132
+
%{btn_a: {93, 43}, btn_b: {49, 91}, prize: {7090, 6422}},
133
133
+
%{btn_a: {28, 70}, btn_b: {68, 21}, prize: {17176, 3693}},
134
134
+
%{btn_a: {33, 16}, btn_b: {27, 51}, prize: {1884, 2771}},
135
135
+
%{btn_a: {11, 43}, btn_b: {51, 19}, prize: {4114, 10066}},
136
136
+
%{btn_a: {26, 70}, btn_b: {87, 46}, prize: {3532, 6874}},
137
137
+
%{btn_a: {22, 35}, btn_b: {38, 13}, prize: {7508, 16592}},
138
138
+
%{btn_a: {33, 16}, btn_b: {48, 72}, prize: {12065, 15896}},
139
139
+
%{btn_a: {67, 25}, btn_b: {14, 55}, prize: {4093, 10275}},
140
140
+
%{btn_a: {36, 17}, btn_b: {43, 77}, prize: {3253, 1933}},
141
141
+
%{btn_a: {84, 24}, btn_b: {42, 69}, prize: {8862, 4869}},
142
142
+
%{btn_a: {70, 16}, btn_b: {17, 68}, prize: {5690, 3224}},
143
143
+
%{btn_a: {58, 27}, btn_b: {44, 92}, prize: {1890, 1595}},
144
144
+
%{btn_a: {64, 30}, btn_b: {29, 57}, prize: {15004, 15224}},
145
145
+
%{btn_a: {13, 90}, btn_b: {64, 33}, prize: {6560, 6048}},
146
146
+
%{btn_a: {37, 91}, btn_b: {64, 49}, prize: {5214, ...}},
147
147
+
%{btn_a: {12, 80}, btn_b: {75, ...}, prize: {...}},
148
148
+
%{btn_a: {27, ...}, btn_b: {...}, ...},
149
149
+
%{btn_a: {...}, ...},
150
150
+
%{...},
151
151
+
...
152
152
+
]
153
153
+
```
154
154
+
155
155
+
Yay, matrices again. We need to solve linear equations in form of:
156
156
+
157
157
+
$$
158
158
+
\begin{cases}
159
159
+
a_x x & + & b_x y & = & p_x \\
160
160
+
a_y x & + & b_x y & = & p_y
161
161
+
\end{cases}
162
162
+
$$
163
163
+
164
164
+
So we need to solve:
165
165
+
166
166
+
$$
167
167
+
\begin{bmatrix}
168
168
+
a_x & b_x \\
169
169
+
a_y & b_y
170
170
+
\end{bmatrix}
171
171
+
\begin{bmatrix}
172
172
+
x \\
173
173
+
y
174
174
+
\end{bmatrix}
175
175
+
= \begin{bmatrix}
176
176
+
p_x \\
177
177
+
p_y
178
178
+
\end{bmatrix}
179
179
+
$$
180
180
+
181
181
+
For each game. So we can use [Cramer's Rule](https://en.wikipedia.org/wiki/Cramer%27s_rule).
182
182
+
183
183
+
$$
184
184
+
\begin{gather*}
185
185
+
x = \frac{\text{det}(A_x)}{\text{det}(A)} \\
186
186
+
y = \frac{\text{det}(A_y)}{\text{det}(A)}
187
187
+
\end{gather*}
188
188
+
$$
189
189
+
190
190
+
Assuming that $\text{det}(A) \ne 0$ (otherwise there will be no solution). In case of $2\times2$ matrices determinant is simple to compute:
191
191
+
192
192
+
$$
193
193
+
\text{det}
194
194
+
\begin{vmatrix}
195
195
+
a & b \\
196
196
+
c & d
197
197
+
\end{vmatrix}
198
198
+
= ad - bc
199
199
+
$$
200
200
+
201
201
+
So in the end we need to compute:
202
202
+
203
203
+
$$
204
204
+
\begin{gather*}
205
205
+
x = \frac{p_x b_y - b_x p_y}{a_x b_y - b_x a_y} \\
206
206
+
y = \frac{a_x p_y - p_x a_y}{a_x b_y - b_x a_y}
207
207
+
\end{gather*}
208
208
+
$$
209
209
+
210
210
+
And reject cases where $x$ or $y$ is non-integer value.
211
211
+
212
212
+
```elixir
213
213
+
defmodule Game do
214
214
+
def solve(%{btn_a: {ax, ay}, btn_b: {bx, by}, prize: {px, py}}) do
215
215
+
det_a = ax * by - bx * ay
216
216
+
det_x = px * by - bx * py
217
217
+
det_y = ax * py - px * ay
218
218
+
219
219
+
if rem(det_x, det_a) == 0 do
220
220
+
{div(det_x, det_a), div(det_y, det_a)}
221
221
+
end
222
222
+
end
223
223
+
end
224
224
+
```
225
225
+
226
226
+
<!-- livebook:{"output":true} -->
227
227
+
228
228
+
```
229
229
+
{:module, Game, <<70, 79, 82, 49, 0, 0, 8, ...>>, {:solve, 1}}
230
230
+
```
231
231
+
232
232
+
## Part 1
233
233
+
234
234
+
```elixir
235
235
+
games
236
236
+
|> Enum.map(&Game.solve/1)
237
237
+
|> Enum.map(fn
238
238
+
nil -> 0
239
239
+
{a, b} -> a * 3 + b * 1
240
240
+
end)
241
241
+
|> Enum.sum()
242
242
+
```
243
243
+
244
244
+
<!-- livebook:{"output":true} -->
245
245
+
246
246
+
```
247
247
+
31897
248
248
+
```
249
249
+
250
250
+
## Part 2
251
251
+
252
252
+
```elixir
253
253
+
games
254
254
+
|> Enum.map(fn %{prize: {px, py}} = game ->
255
255
+
add = 10_000_000_000_000
256
256
+
%{game | prize: {px + add, py + add}}
257
257
+
end)
258
258
+
|> Enum.map(&Game.solve/1)
259
259
+
|> Enum.map(fn
260
260
+
nil -> 0
261
261
+
{a, b} -> a * 3 + b * 1
262
262
+
end)
263
263
+
|> Enum.sum()
264
264
+
```
265
265
+
266
266
+
<!-- livebook:{"output":true} -->
267
267
+
268
268
+
```
269
269
+
87596249540359
270
270
+
```
271
271
+
272
272
+
<!-- livebook:{"offset":11449,"stamp":{"token":"XCP.AhVykQ8wyKxhTI29dXZZ0BnWEqWCuVGz8E2TRFpScgbUfqJJtY47yrvU9g9OzcejZVc8LbU3ak4YrgSGy5A5XeARPC3qt5fGPV4K9PYS3YabI7-q8rCKi8R6ZpGBpmZeDNQ","version":2}} -->