Advent of Code (AoC) 2025

Overall objective for 2025: Finish decorating the North Pole by December 12th.

Use Ctrl-Click to toggle open/closed entire hierarchy sections.

Note: Eric Wastl, the creator of Advent of Code, announced there will be only 12 (cf. 25) days of problems each year from 2025 onward.

** Day  1: Secret Entrance – Repeatedly rotate a dial while counting zeros
Part 1

%

{"L": -1, "R": 1}

Part 2

You can get more performant by using something like divmod(...), and being careful to account for edge cases, but it's really not necessary for this problem's input data. A single-stepping inner loop still finishes very quickly.

** Day  2: Gift Shop – Count invalid IDs (solely comprised of repeating sub-sequences) in number ranges
Part 1

//

Possible by doing the math, but ... str(n).

It should be obvious that ...

... only even-length numbers have even the possibility of matching, and you could use // for string slicing and comparing, etc.

But, probably what you really want to do is ...
... use re with ...

... back-referencing (and ^ and $). This approach makes Part 2 hilariously trivial.

Part 2

str(n)

Possible by doing all the iterating through in various sub-lengths and checking that they all match—in which case, I'd suggest itertools.pairwise(...) and itertools.batched(...).

But, probably what you really want to do is ...
... use re.match(...) with ...

... back-referencing (and ^ and $). This approach makes the solution for Part 2 different from the solution for Part 1 by only a single character: +.

** Day  3: Lobby – Maximize joltages from battery banks
Part 1

Find the maximum individual battery joltage within the bank of batteries.

If it's the last battery ...

... find the maximum joltage preceding it, and combine them for the total.

If not ...

... find the maximum joltage succeeding it, and combine them for the total.

Part 2

While solving Part 1, it occurred to me that this is exactly the direction Part 2 would go. You need to be a bit more clever for this one.

An initial important observation is that ...

... the first digit of the final result must be the maximum possible, while also leaving enough batteries afterward to fill out all remaining required digits.

Extending this further leads to the observation that ...

... this is true for every digit being merged into the final result.

This is, of course, in conjunction with the fact that ...

... each maximized digit must also follow all preceding already-maximized digits.

Visually ...

Battery bank joltages:

xxxxxx...xxxxx...xxxxxxxx...xx
 ^  ^ ... ^⸤___________⸥⸤______⸥
⸤__________⸥   choose    leave
n-1 initial   nth max   12-n
max joltages  joltage   batteries
are in here   in here   remaining

Whatever the nth max ends up being, move the start of the next "max selection range" to just after its index, as well as the end of it moving one additional step farther to the right (since there's one less joltage digit that must have space left for it).

** Day  4: Printing Department – Count forklift-reachable rolls of paper
Part 1

It's fairly straightforward to load the data into a grid; run through each location in it; check that it's a roll and, if so, assess what's in its immediate surroundings in order to determine if it's reachable or not; counting the reachable results the whole time, as you go. Although, that may be a little exacting in terms of getting the details right, it's not "hard" to do.

A better way ...

Instead of loading everything into a grid, if you load into a set only the (row, col) coordinates of just the rolls of paper, then you will subsequently iterate only through rolls (skipping all empty locations), and you only need to check if immediately surrounding (row, col) locations are in that set when counting how many rolls are adjacent to each.

Part 2

For the most part, this is the same as Part 1, just repeated, and with some adjustments on each iteration. Until nothing changes any more.

In the case of the "better" way in Part 1 ...

You just remove every reachable roll in each iteration to set up for the following iteration, until there's nothing more to remove, counting along the way (or just remembering the original size, then subtracting the final size from it at the end).

** Day  5: Cafeteria – Identify and count IDs of fresh (inside provided ranges) ingredients; count total possible
Part 1

Just do it. Not sure what else to say. This may be the easiest problem of this year's event so far.

One obvious optimization

When iterating through the ranges, terminate the instant one is found that fits, rather than finishing checking all of them. (But, I think it's almost harder to not terminate then than to terminate.)

any(...) is probably a good option to leverage here since its evaluation short-circuits.

sum(...)

Part 2

This one's a bit more tricky, but not too bad.

Fundamentally, the problem to solve is ...

... counting every "fresh ID" exactly once, instead of multiple times, because the provided ranges overlap with each other in various ways, and they must be processed as ranges because simply iterating through all IDs between the minimum range low value and the maximum range high value isn't feasible due to how large the range values are.

There are two obvious ways to resolve overlapping ranges ...

... shrink ranges, as needed, when they overlap, so they no longer do. But, this doesn't necessarily work very well in some situations, such as if some ranges exist entirely inside other ranges, or at least are entirely overlapped by some combination of other ranges. And, even if you do get this working properly, it still will generally yield more resulting ranges than when using the next approach.

... merge ranges, as needed, when they overlap, so they no longer do. But, then the challenge is to identify subsets of all ranges that are merge-able into respectively representative single ranges.

There are several ways to approach the merge problem, but probably the best is ...

... to first ascendingly sort all the ranges by their low values (with tie-breaks by their end values). See sorted(...), or [].sort().

Then, iterate through them, tracking ...

... an intermittently changing start value and whether or not the currently assigned end value is ≥ to the following range's low value. (Technically, you can merge on end ≥ low-1, but you don't need to.)

If it is, then set end to ...

... max(end, high), and continue.

If it's not, then add (start, end) to a set of merged ranges, and set start and end to the current range's low and high, respectively, to begin merging a new range, then continue.

Once done, simply sum the lengths of all merged ranges to get the total count of fresh IDs.

Note that it is also possible to accumulate totals on the fly (which should be more performant than storing merged ranges and later summing them), but beware of accounting for the final sorted-input range because its factoring-in with regard to merging or not, while inside versus outside the loop, is dependent upon the input data.

** Day  6: Trash Compactor – Cephalopod math homework
Part 1

"...".strip()

re.split(...)

sum(...) and math.prod(...)

{"+": sum, "*": prod}

itertools.islice(...)

zip(*lines) – I really cannot emphasize this hint enough. It will massively help in processing the input data.

Part 2

Well, throw out those "...".strip() and re.split(...) hints from Part 1 for this one.

But, still very, very much heed that zip(*lines) hint from Part 1.

"".join(...) – Ok, perhaps factor in "...".strip() in conjunction with this.

Once the input is ingested and transformed, you can either ...

... immediately go into a loop to process it, accounting for the variations in lines as you go, or ...

... first build a "point of interest" (POI) list of indices that holds all the indices of the lines where the operators appear. (Plus, append a len(data) entry so the final "equation" gets processed automatically.) Then, you can just iterate over the data using that POI index list and itertools.pairwise(...).

** Day  7: Laboratories – Counting beam splits and timelines
Part 1

Strongly suggest using sets, and set operations—both for storing column locations of splitters on rows and tracking traveling beams.

Part 2

@cache

** Day  8: Playground – Running Christmas lights between junction boxes, minimizing distances
Part 1
I don't have much to say here since this is a fairly simple problem if you use ...

... the union-find algorithm.

I suppose one thing that could make things a little more convenient at the end is ...

... collections.Counter.

Part 2

I have nothing more to add to Part 1's information, except to just keep going until they're all in the same circuit.

** Day  9: Movie Theater – Finding a largest-area rectangle; ensuring it's "in bounds"
Part 1

Very straightforward. I solved this Part faster than any other problem's part so far this year.

I'd suggest using ...

... itertools.combinations to help out a little.

And, don't fall victim to the programmer's infamous ...

... "off by one" error when computing rectangle areas.

Part 2

Not at all straightforward, even though it (at least initially) "feels like it should be", which I found rather frustrating while working through it.

I suspect that almost everybody who "solved" this ... didn't actually solve it and instead just semi-accidentally got lucky with the problem's particular input data. (I know for a fact that of the four different people's code I had run on some test data I created, all of them failed to assess it correctly, and that includes my own.)

We all misread the actual problem being asked, and we simply got lucky that the input data was designed in the shape it was, so our solutions to our misreadings of the problem were coincidentally "correct".

I'm providing some test data here for people to try out, which far better exercise solution code than the actual problem's input data did. (Triple-click inside one of the sets to select it, for easier copying.)

Test: M
Max: 21
25,0
25,2
28,2
28,4
31,4
31,6
34,6
34,8
36,8
36,10
32,10
32,8
29,8
29,6
26,6
26,4
23,4
23,2
21,2
21,5
15,5
15,2
13,2
13,4
10,4
10,6
7,6
7,8
4,8
4,10
0,10
0,8
2,8
2,6
5,6
5,4
8,4
8,2
11,2
11,0
17,0
17,3
19,3
19,0
Test: M⤸
Max: 21
10,25
8,25
8,28
6,28
6,31
4,31
4,34
2,34
2,36
0,36
0,32
2,32
2,29
4,29
4,26
6,26
6,23
8,23
8,21
5,21
5,15
8,15
8,13
6,13
6,10
4,10
4,7
2,7
2,4
0,4
0,0
2,0
2,2
4,2
4,5
6,5
6,8
8,8
8,11
10,11
10,17
7,17
7,19
10,19
Test: M_
Max: 35
25,0
25,2
28,2
28,4
31,4
31,6
35,6
35,8
37,8
37,6
43,6
43,8
45,8
45,6
51,6
51,8
53,8
53,6
59,6
59,8
63,8
63,10
57,10
57,8
55,8
55,10
49,10
49,8
47,8
47,10
41,10
41,8
39,8
39,10
33,10
33,8
29,8
29,6
26,6
26,4
23,4
23,2
21,2
21,5
15,5
15,2
13,2
13,4
10,4
10,6
7,6
7,8
4,8
4,10
0,10
0,8
2,8
2,6
5,6
5,4
8,4
8,2
11,2
11,0
17,0
17,3
19,3
19,0
Test: M_⤸
Max: 35
10,25
8,25
8,28
6,28
6,31
4,31
4,35
2,35
2,37
4,37
4,43
2,43
2,45
4,45
4,51
2,51
2,53
4,53
4,59
2,59
2,63
0,63
0,57
2,57
2,55
0,55
0,49
2,49
2,47
0,47
0,41
2,41
2,39
0,39
0,33
2,33
2,29
4,29
4,26
6,26
6,23
8,23
8,21
5,21
5,15
8,15
8,13
6,13
6,10
4,10
4,7
2,7
2,4
0,4
0,0
2,0
2,2
4,2
4,5
6,5
6,8
8,8
8,11
10,11
10,17
7,17
7,19
10,19
Test: ⇑
Max: ??
16,0
16,2
18,2
18,4
20,4
20,6
22,6
22,8
24,8
24,10
26,10
26,16
24,16
24,18
22,18
22,14
24,14
24,12
22,12
22,10
20,10
20,8
18,8
18,6
16,6
16,4
14,4
14,2
12,2
12,4
10,4
10,6
8,6
8,8
6,8
6,10
4,10
4,12
2,12
2,14
4,14
4,18
2,18
2,16
0,16
0,10
2,10
2,8
4,8
4,6
6,6
6,4
8,4
8,2
10,2
10,0
Test: ⇑⤸
Max: ??
18,16
16,16
16,18
14,18
14,20
12,20
12,22
10,22
10,24
8,24
8,26
2,26
2,24
0,24
0,22
4,22
4,24
6,24
6,22
8,22
8,20
10,20
10,18
12,18
12,16
14,16
14,14
16,14
16,12
14,12
14,10
12,10
12,8
10,8
10,6
8,6
8,4
6,4
6,2
4,2
4,4
0,4
0,2
2,2
2,0
8,0
8,2
10,2
10,4
12,4
12,6
14,6
14,8
16,8
16,10
18,10
Test: 紆
Max: 288?
25,0
25,2
23,2
23,3
28,3
28,8
25,8
25,14
22,14
22,12
23,12
23,11
21,11
21,12
19,12
19,18
5,18
5,12
0,12
0,0
8,0
8,3
7,3
7,15
11,15
11,6
13,6
13,11
12,11
12,15
16,15
16,12
18,12
18,9
16,9
16,6
26,6
26,5
15,5
15,10
17,10
17,11
15,11
15,14
13,14
13,13
14,13
14,5
10,5
10,14
8,14
8,4
9,4
9,0
Test: 紆⤸
Max: 288?
18,25
16,25
16,23
15,23
15,28
10,28
10,25
4,25
4,22
6,22
6,23
7,23
7,21
6,21
6,19
0,19
0,5
6,5
6,0
18,0
18,8
15,8
15,7
3,7
3,11
12,11
12,13
7,13
7,12
3,12
3,16
6,16
6,18
9,18
9,16
12,16
12,26
13,26
13,15
8,15
8,17
7,17
7,15
4,15
4,13
5,13
5,14
13,14
13,10
4,10
4,8
14,8
14,9
18,9
Test: ₂₅
Max: ??
342,192
340,192
340,205
339,205
339,216
337,216
337,229
332,229
332,237
333,237
333,251
333,255
325,255
325,267
318,267
318,282
315,282
315,287
310,287
310,294
301,294
301,305
292,305
292,311
285,311
285,313
275,313
275,323
266,323
266,329
253,329
253,328
239,328
239,333
230,333
230,341
223,341
208,341
208,344
194,344
194,345
183,345
183,343
173,343
173,341
166,341
166,337
154,337
154,338
143,338
143,331
134,331
134,320
141,320
151,320
151,316
157,316
157,307
170,307
170,306
185,306
185,303
186,303
186,302
193,302
193,297
200,297
200,295
211,295
211,290
222,290
222,291
234,291
234,287
244,287
244,286
254,286
254,280
255,280
255,279
261,279
261,268
265,268
265,265
275,265
275,268
286,268
286,258
296,258
296,253
304,253
304,246
310,246
310,237
313,237
313,227
314,227
314,213
315,213
315,198
312,198
312,189
305,189
305,178
296,178
286,178
286,175
279,175
279,174
278,174
278,170
268,170
268,175
256,175
256,177
250,177
250,166
251,166
251,150
258,150
271,150
271,151
280,151
280,150
293,150
293,148
306,148
306,150
310,150
310,139
310,122
305,122
305,124
296,124
296,121
284,121
284,124
269,124
269,125
262,125
262,122
250,122
250,125
238,125
238,122
230,122
224,122
224,130
225,130
225,143
221,143
221,154
219,154
219,169
220,169
220,180
219,180
219,194
222,194
222,197
229,197
229,204
238,204
238,197
249,197
249,192
263,192
263,196
273,196
273,198
281,198
281,210
284,210
284,219
282,219
282,227
276,227
276,238
268,238
268,241
257,241
257,240
247,240
247,241
246,241
246,242
235,242
235,234
225,234
225,227
219,227
219,240
211,240
211,248
212,248
212,249
220,249
220,261
230,261
230,269
242,269
254,269
254,268
253,268
242,268
231,268
231,260
221,260
221,248
213,248
213,247
212,247
212,242
213,242
213,241
220,241
220,228
224,228
224,235
234,235
234,243
248,243
248,241
256,241
256,242
269,242
269,239
277,239
277,228
283,228
283,220
285,220
285,209
282,209
282,197
274,197
274,195
264,195
264,191
248,191
248,196
237,196
237,203
230,203
230,196
223,196
223,193
220,193
220,181
221,181
221,168
220,168
220,155
222,155
222,144
226,144
226,129
225,129
225,123
230,123
237,123
237,126
251,126
251,123
261,123
261,126
270,126
270,125
285,125
285,122
295,122
295,125
306,125
306,123
309,123
309,139
309,149
307,149
307,147
292,147
292,149
279,149
279,150
272,150
272,149
258,149
250,149
250,165
249,165
249,178
257,178
257,176
269,176
269,171
277,171
277,176
285,176
285,179
296,179
304,179
304,190
311,190
311,199
314,199
314,212
313,212
313,226
312,226
312,236
309,236
309,245
303,245
303,252
295,252
295,257
285,257
285,267
276,267
276,264
264,264
264,267
260,267
260,278
253,278
253,285
243,285
243,286
233,286
233,290
223,290
223,289
210,289
210,294
199,294
199,296
192,296
192,301
184,301
184,304
183,304
183,305
169,305
169,306
156,306
156,315
150,315
150,319
141,319
133,319
133,330
122,330
122,320
112,320
112,318
103,318
103,309
95,309
95,306
86,306
86,289
79,289
79,283
70,283
70,277
64,277
64,269
62,269
62,259
56,259
56,247
51,247
51,239
48,239
48,229
42,229
42,217
44,217
44,204
46,204
46,193
43,193
43,181
42,181
42,168
47,168
47,161
49,161
49,150
50,150
50,141
53,141
53,131
58,131
58,112
67,112
67,106
76,106
76,98
83,98
83,90
86,90
86,82
95,82
95,76
108,76
108,69
113,69
113,63
121,63
121,58
135,58
135,54
146,54
146,50
156,50
156,47
167,47
167,45
178,45
178,43
188,43
188,45
199,45
199,46
211,46
211,43
221,43
221,42
232,42
232,54
241,54
241,56
249,56
249,66
245,66
245,73
238,73
238,72
224,72
224,76
211,76
211,81
198,81
198,87
190,87
190,86
178,86
178,95
170,95
170,91
156,91
156,103
148,103
148,102
135,102
135,107
129,107
129,120
135,120
135,118
142,118
142,125
154,125
154,128
163,128
163,138
168,138
168,145
172,145
172,146
173,146
173,158
177,158
177,166
179,166
179,178
178,178
178,190
172,190
172,197
163,197
163,200
162,200
162,201
153,201
153,217
147,217
147,225
142,225
142,232
131,232
131,240
134,240
134,239
144,239
144,240
145,240
157,240
157,239
168,239
168,234
179,234
179,235
180,235
180,238
188,238
188,254
188,264
183,264
173,264
173,263
162,263
162,262
148,262
136,262
136,266
127,266
127,262
116,262
105,262
95,262
95,265
88,265
88,264
80,264
80,260
80,247
86,247
86,244
95,244
95,231
103,231
103,225
113,225
113,220
121,220
121,215
128,215
128,204
134,204
134,189
139,189
139,186
146,186
146,180
148,180
148,166
148,152
144,152
144,142
128,142
128,144
116,144
116,151
107,151
107,154
98,154
98,159
92,159
92,147
84,147
84,142
84,135
95,135
95,129
104,129
104,128
114,128
114,124
126,124
126,119
125,119
125,123
113,123
113,127
103,127
103,128
94,128
94,134
83,134
83,142
83,148
91,148
91,160
99,160
99,155
108,155
108,152
117,152
117,145
129,145
129,144
130,144
130,143
143,143
143,153
147,153
147,166
147,179
145,179
145,185
138,185
138,188
133,188
133,203
127,203
127,214
120,214
120,219
112,219
112,224
102,224
102,230
94,230
94,243
85,243
85,246
79,246
79,260
79,265
87,265
87,266
96,266
96,263
105,263
116,263
126,263
126,267
137,267
137,263
148,263
161,263
161,264
172,264
172,265
183,265
189,265
189,254
189,237
181,237
181,233
167,233
167,238
156,238
156,239
146,239
146,238
133,238
133,239
132,239
132,233
143,233
143,226
148,226
148,218
154,218
154,202
164,202
164,198
173,198
173,191
179,191
179,179
180,179
180,165
178,165
178,157
174,157
174,144
169,144
169,137
164,137
164,127
155,127
155,124
143,124
143,117
134,117
134,119
130,119
130,108
136,108
136,103
147,103
147,104
157,104
157,92
169,92
169,96
179,96
179,87
188,87
188,88
189,88
199,88
199,82
212,82
212,77
225,77
225,73
237,73
237,74
246,74
246,68
247,68
247,67
250,67
250,57
262,57
262,68
273,68
273,70
281,70
281,75
288,75
288,83
297,83
297,89
304,89
304,99
312,99
312,111
321,111
321,115
324,115
324,126
330,126
330,133
334,133
334,146
334,157
339,157
339,173
343,173
343,181
343,192
Test: 25₁₀₀
Max: ??
81037,45743
81307,45743
81307,47955
81007,47955
81007,51686
79914,51686
79914,53583
79042,53583
79042,55545
78482,55545
78482,58668
77832,58668
77832,61793
77340,61793
77340,62941
76003,62941
76003,66211
73832,66211
73832,67314
72002,67314
72002,70294
70464,70294
70464,71456
69015,71456
69015,73094
66458,73094
66458,75245
64302,75245
64302,75348
62498,75348
62498,78567
60273,78567
60273,78494
57946,78494
57946,80241
54650,80241
54650,81287
51519,81287
51519,80055
49006,80055
49006,81339
46853,81339
46853,80571
44749,80571
44749,80099
42437,80099
42437,80401
39786,80401
39786,80139
36392,80139
36392,78692
34030,78692
34030,79362
31782,79362
31782,76715
32786,76715
32786,75418
35372,75418
35372,74830
37575,74830
37575,73758
40279,73758
40279,72405
40379,72405
40379,72305
43599,72305
43599,73242
45649,73242
45649,70853
48003,70853
48003,70748
51243,70748
51243,69823
53763,69823
53763,68815
55410,68815
55410,69081
58098,69081
58098,66791
60965,66791
60965,66154
61971,66154
61971,63507
63020,63507
63020,63159
65748,63159
65748,61447
68470,61447
68470,62100
70717,62100
70717,59391
72582,59391
72582,56986
73830,56986
73830,55475
74837,55475
74837,53109
75007,53109
75007,50376
74391,50376
74391,48583
73191,48583
73191,45439
71636,45439
71636,43226
70324,43226
70324,42067
68883,42067
68883,40874
66300,40874
66300,40786
63288,40786
63288,42328
60587,42328
60587,42117
59631,42117
59631,39797
59922,39797
59922,35816
61301,35816
61301,35621
63786,35621
63786,35428
66353,35428
66353,35314
69412,35314
69412,35207
72228,35207
72228,35816
74135,35816
74135,31904
74135,29251
72322,29251
72322,28324
69630,28324
69630,30044
67206,30044
67206,28478
64772,28478
64772,29995
61653,29995
61653,28932
58640,28932
58640,28955
56364,28955
56364,29730
54206,29730
54206,29251
53058,29251
53058,32779
52568,32779
52568,34149
51938,34149
51938,37197
52414,37197
52414,40872
52229,40872
52229,42428
51793,42428
51793,46246
52951,46246
52951,48250
54672,48250
54672,48470
56902,48470
56902,46411
59045,46411
59045,45987
61806,45987
61806,46987
64198,46987
64198,47587
66182,47587
66182,49330
67871,49330
67871,53134
67588,53134
67588,55429
66332,55429
66332,56648
63647,56648
63647,56367
60725,56367
60725,57996
58483,57996
58483,55693
56400,55693
56400,56258
54205,56258
54205,53871
52286,53871
52286,57456
50539,57456
50539,58795
50780,58795
50780,61207
53294,61207
53294,61692
55157,61692
55157,62137
57957,62137
57957,63389
61011,63389
61011,63507
61012,63507
61012,63388
57958,63388
57958,62136
55258,62136
55258,62036
55158,62036
55158,61691
53395,61691
53395,61591
53295,61591
53295,61206
50781,61206
50781,58794
50540,58794
50540,57457
52287,57457
52287,53872
54204,53872
54204,56259
56401,56259
56401,55694
58482,55694
58482,57997
60726,57997
60726,56368
63646,56368
63646,56649
66333,56649
66333,55430
67589,55430
67589,53135
67872,53135
67872,49329
66183,49329
66183,47586
64199,47586
64199,46986
61807,46986
61807,45986
59044,45986
59044,46410
56901,46410
56901,48369
56801,48369
56801,48469
54673,48469
54673,48249
52952,48249
52952,46245
51794,46245
51794,42429
52230,42429
52230,40873
52415,40873
52415,37196
51939,37196
51939,34150
52569,34150
52569,32780
53059,32780
53059,29252
54205,29252
54205,29731
56365,29731
56365,28956
58641,28956
58641,28933
61652,28933
61652,29996
64773,29996
64773,28479
67205,28479
67205,30045
69631,30045
69631,28325
72321,28325
72321,29252
74134,29252
74134,31904
74134,35815
72229,35815
72229,35206
69411,35206
69411,35313
66352,35313
66352,35427
63785,35427
63785,35620
61300,35620
61300,35815
59921,35815
59921,39796
59630,39796
59630,42118
60586,42118
60586,42329
63289,42329
63289,40787
66299,40787
66299,40875
68882,40875
68882,42068
70323,42068
70323,43227
71635,43227
71635,45440
73190,45440
73190,48584
74390,48584
74390,50377
75006,50377
75006,53108
74836,53108
74836,55474
73829,55474
73829,56985
72581,56985
72581,59390
70716,59390
70716,62099
68471,62099
68471,61446
65747,61446
65747,63158
63019,63158
63019,63506
61970,63506
61970,66153
60964,66153
60964,66790
58097,66790
58097,69080
55411,69080
55411,68814
53762,68814
53762,69722
53662,69722
53662,69822
51242,69822
51242,70747
48002,70747
48002,70852
45648,70852
45648,73241
43600,73241
43600,72304
40278,72304
40278,73757
37574,73757
37574,74829
35371,74829
35371,75417
32785,75417
32785,76714
31781,76714
31781,77903
28610,77903
28610,76519
26372,76519
26372,74017
24523,74017
24523,73148
22899,73148
22899,71286
20687,71286
20687,70216
18755,70216
18755,67960
17291,67960
17291,64860
15454,64860
15454,64576
14054,64576
14054,61997
13173,61997
13173,59000
12391,59000
12391,56477
11787,56477
11787,53482
11188,53482
11188,50978
10746,50978
10746,49007
10614,49007
10614,45833
10135,45833
10135,42675
10271,42675
10271,39947
11416,39947
11416,38647
12077,38647
12077,35583
12531,35583
12531,32757
13839,32757
13839,29539
14250,29539
14250,28397
15586,28397
15586,26307
17844,26307
17844,24007
19183,24007
19183,22749
20810,22749
20810,20996
22521,20996
22521,18331
24946,18331
24946,17133
27410,17133
27410,14407
29002,14407
29002,14655
31619,14655
31619,11568
34255,11568
34255,11207
37040,11207
37040,12080
39219,12080
39219,10685
41454,10685
41454,10084
44266,10084
44266,10726
46829,10726
46829,10264
49387,10264
49387,11132
51794,11132
51794,11188
54484,11188
54484,11011
56754,11011
56754,12441
59833,12441
59833,15087
58658,15087
58658,15506
56015,15506
56015,16348
53591,16348
53591,18029
51784,18029
51784,19199
49418,19199
49418,20076
46557,20076
46557,21073
46457,21073
46457,21173
43841,21173
43841,22177
41978,22177
41978,22796
40163,22796
40163,23178
37674,23178
37674,23046
34948,23046
34948,25140
32223,25140
32223,25967
31050,25967
31050,28616
32371,28616
32371,29867
34674,29867
34674,28379
36873,28379
36873,30188
39026,30188
39026,30288
39126,30288
39126,33024
40954,33024
40954,33951
41851,33951
41851,34051
41951,34051
41951,37709
42455,37709
42455,40576
42685,40576
42685,42086
42026,42086
42026,45842
40410,45842
40410,47277
38778,47277
38778,49521
37142,49521
37142,51711
34998,51711
34998,53036
32622,53036
32622,54835
30965,54835
30965,56731
31936,56731
31936,55617
34729,55617
34729,57100
37659,57100
37659,56939
40760,56939
40760,55762
43512,55762
43512,56307
44691,56307
44691,60304
44691,62871
43186,62871
43186,63293
43086,63293
43086,63393
40741,63393
40741,62028
38512,62028
38512,62136
36096,62136
36096,61972
33215,61972
33215,62036
29990,62036
29990,62488
27781,62488
27781,62144
25410,62144
25410,62872
22952,62872
22952,63042
20886,63042
20886,62942
20786,62942
20786,62871
19222,62871
19222,61335
19222,58425
20828,58425
20828,56621
20928,56621
20928,56521
22544,56521
22544,54244
24601,54244
24601,53049
24701,53049
24701,52949
26933,52949
26933,52091
28550,52091
28550,49038
30434,49038
30434,48512
31942,48512
31942,45087
33673,45087
33673,44606
34733,44606
34733,41068
34643,41068
34643,39683
34681,39683
34681,36600
33623,36600
33623,35534
31228,35534
31228,33752
29159,33752
29159,35213
26508,35213
26508,36598
23966,36598
23966,38145
21873,38145
21873,36951
19782,36951
19782,33964
20479,33964
20479,32159
22233,32159
22233,30628
23721,30628
23721,29683
26260,29683
26260,28093
29334,28093
29334,28615
29335,28615
29335,28092
26259,28092
26259,29682
23720,29682
23720,30627
22232,30627
22232,32158
20478,32158
20478,33963
19781,33963
19781,36952
21872,36952
21872,38146
23967,38146
23967,36599
26509,36599
26509,35214
29160,35214
29160,33753
31227,33753
31227,35535
33622,35535
33622,36601
34680,36601
34680,39682
34642,39682
34642,41069
34732,41069
34732,44605
33672,44605
33672,45086
31941,45086
31941,48511
30433,48511
30433,49037
28549,49037
28549,52090
26932,52090
26932,52948
24600,52948
24600,54243
22543,54243
22543,56520
20827,56520
20827,58424
19221,58424
19221,61335
19221,62872
20785,62872
20785,63043
22953,63043
22953,62873
25411,62873
25411,62145
27780,62145
27780,62489
29991,62489
29991,62037
33216,62037
33216,61973
36095,61973
36095,62137
38513,62137
38513,62029
40740,62029
40740,63394
43187,63394
43187,62872
44692,62872
44692,60304
44692,56306
43513,56306
43513,55761
40759,55761
40759,56938
37658,56938
37658,57099
34730,57099
34730,55616
31935,55616
31935,56730
30966,56730
30966,54836
32623,54836
32623,53037
34999,53037
34999,51812
35099,51812
35099,51712
37143,51712
37143,49522
38779,49522
38779,47278
40411,47278
40411,45843
42027,45843
42027,42087
42686,42087
42686,40575
42456,40575
42456,37708
41952,37708
41952,33950
40955,33950
40955,33023
39127,33023
39127,30187
36874,30187
36874,28378
34673,28378
34673,29866
32372,29866
32372,28615
31151,28615
31151,28515
31051,28515
31051,25968
32224,25968
32224,25241
32324,25241
32324,25141
34949,25141
34949,23047
37673,23047
37673,23179
40164,23179
40164,22797
41979,22797
41979,22178
43842,22178
43842,21174
46558,21174
46558,20077
49419,20077
49419,19200
51785,19200
51785,18130
51885,18130
51885,18030
53592,18030
53592,16349
56016,16349
56016,15507
58659,15507
58659,15088
59834,15088
59834,15040
62673,15040
62673,16073
64838,16073
64838,16750
66808,16750
66808,18000
68878,18000
68878,19813
70490,19813
70490,21049
71884,21049
71884,23539
73912,23539
73912,26956
76139,26956
76139,28213
78028,28213
78028,30583
78951,30583
78951,33680
78988,33680
78988,34661
79884,34661
79884,37953
80895,37953
80895,39487
80549,39487
80549,42537
80690,42537
80690,45743
Test: 25₁
Max: ??
81164,45870
81402,45870
81402,48356
81313,48356
81313,50685
80318,50685
80318,53367
79183,53367
79183,56747
79082,56747
79082,59204
78962,59204
78962,60604
77723,60604
77723,63491
76277,63491
76277,65552
74775,65552
74775,68283
72203,68283
72203,69968
70326,69968
70326,71233
69327,71233
69327,72766
67067,72766
67067,74978
65119,74978
65119,76106
63373,76106
63373,77627
60293,77627
60293,78809
57124,78809
57124,80288
54804,80288
54804,81011
52825,81011
52825,81505
50165,81505
50165,81106
46942,81106
46942,80269
44772,80269
44772,81527
42382,81527
42382,79730
39114,79730
39114,79679
36488,79679
36488,80142
34290,80142
34290,78032
32076,78032
32076,75385
33734,75385
33734,74655
36288,74655
36288,73558
38932,73558
38932,73610
41743,73610
41743,73054
44220,73054
44220,71899
45892,71899
45892,70132
48112,70132
48112,69176
50955,69176
50955,69954
53246,69954
53246,69172
56108,69172
56108,68741
58469,68741
58469,67270
60738,67270
60738,66281
62098,66281
62098,63633
63802,63633
63802,64087
66520,64087
66520,62069
68627,62069
68627,62380
70973,62380
70973,60046
72574,60046
72574,57384
73534,57384
73534,55986
74491,55986
74491,54009
74494,54009
74494,50323
74405,50323
74405,48054
73646,48054
73646,45845
72455,45845
72455,43578
70950,43578
70950,43716
68268,43716
68268,41052
66032,41052
66032,40518
63216,40518
63216,41715
60287,41715
60287,42243
59203,42243
59203,40084
59494,40084
59494,35942
61363,35942
61363,35938
64518,35938
64518,35473
66858,35473
66858,35441
69356,35441
69356,34973
72463,34973
72463,35942
74199,35942
74199,33291
74199,29377
72748,29377
72748,28691
70247,28691
70247,29194
67878,29194
67878,28599
65430,28599
65430,30424
61924,30424
61924,30264
59286,30264
59286,28509
57670,28509
57670,28371
54959,28371
54959,29377
53417,29377
53417,31211
53383,31211
53383,35099
52719,35099
52719,38245
52484,38245
52484,39759
52102,39759
52102,43200
51921,43200
51921,46373
52865,46373
52865,48210
54586,48210
54586,48597
57177,48597
57177,48198
59280,48198
59280,45964
61989,45964
61989,46759
64337,46759
64337,47673
66186,47673
66186,50614
67268,50614
67268,53016
66804,53016
66804,55300
66047,55300
66047,55554
63423,55554
63423,57530
60988,57530
60988,58069
58809,58069
58809,57102
56563,57102
56563,55283
54462,55283
54462,53997
52186,53997
52186,56580
50438,56580
50438,58921
50279,58921
50279,61046
52689,61046
52689,62534
55873,62534
55873,62784
58344,62784
58344,62984
60704,62984
60704,63633
60705,63633
60705,62983
58345,62983
58345,62783
55874,62783
55874,62533
52690,62533
52690,61045
50280,61045
50280,58922
50439,58922
50439,56582
50440,56582
50440,56581
52187,56581
52187,53998
54461,53998
54461,55284
56562,55284
56562,57103
58808,57103
58808,58070
60989,58070
60989,57531
63424,57531
63424,55555
66048,55555
66048,55301
66805,55301
66805,53017
67269,53017
67269,50613
66187,50613
66187,47672
64338,47672
64338,46758
61990,46758
61990,45963
59279,45963
59279,48197
57176,48197
57176,48596
54587,48596
54587,48209
52866,48209
52866,46372
51922,46372
51922,43201
52103,43201
52103,39760
52485,39760
52485,38246
52720,38246
52720,35100
53384,35100
53384,31212
53418,31212
53418,29378
54960,29378
54960,28372
57669,28372
57669,28510
59285,28510
59285,30265
61923,30265
61923,30425
65431,30425
65431,28600
67877,28600
67877,29195
70248,29195
70248,28692
72747,28692
72747,29378
74198,29378
74198,33291
74198,35941
72464,35941
72464,34972
69355,34972
69355,35440
66857,35440
66857,35472
64517,35472
64517,35937
61362,35937
61362,35941
59493,35941
59493,40083
59202,40083
59202,42244
60288,42244
60288,41716
63217,41716
63217,40519
66031,40519
66031,41053
68267,41053
68267,43717
70951,43717
70951,43579
72454,43579
72454,45846
73645,45846
73645,48055
74404,48055
74404,50324
74493,50324
74493,54008
74490,54008
74490,55985
73533,55985
73533,57383
72573,57383
72573,60045
70972,60045
70972,62379
68628,62379
68628,62068
66519,62068
66519,64086
63803,64086
63803,63632
62097,63632
62097,66280
60737,66280
60737,67268
60736,67268
60736,67269
58468,67269
58468,68740
56107,68740
56107,69171
53245,69171
53245,69953
50956,69953
50956,69175
48111,69175
48111,70131
45891,70131
45891,71898
44219,71898
44219,73053
41742,73053
41742,73608
41741,73608
41741,73609
38933,73609
38933,73557
36287,73557
36287,74654
33733,74654
33733,75384
32075,75384
32075,77489
30058,77489
30058,75940
27782,75940
27782,74170
25403,74170
25403,73307
23249,73307
23249,70962
20941,70962
20941,71042
18720,71042
18720,67098
16968,67098
16968,66657
16235,66657
16235,64092
15155,64092
15155,60092
13328,60092
13328,58105
12156,58105
12156,55305
11853,55305
11853,53547
11517,53547
11517,51951
10581,51951
10581,47945
10084,47945
10084,46295
10355,46295
10355,42984
11330,42984
11330,40495
12187,40495
12187,38266
12495,38266
12495,35467
13071,35467
13071,33952
13973,33952
13973,29579
15250,29579
15250,27750
16308,27750
16308,25256
17104,25256
17104,23086
19270,23086
19270,22103
21465,22103
21465,19573
23488,19573
23488,18460
25234,18460
25234,16743
27005,16743
27005,14285
29582,14285
29582,13440
32030,13440
32030,12008
34193,12008
34193,12893
36070,12893
36070,11678
38378,11678
38378,10594
41779,10594
41779,11560
44966,11560
44966,10515
47584,10515
47584,10289
50173,10289
50173,10288
52700,10288
52700,11076
55278,11076
55278,12334
57345,12334
57345,13984
59840,13984
59840,16631
58868,16631
58868,17465
55729,17465
55729,17931
52768,17931
52768,18169
50949,18169
50949,19862
48201,19862
48201,21568
45273,21568
45273,22096
42510,22096
42510,22398
40070,22398
40070,23915
37954,23915
37954,23176
35815,23176
35815,25960
33044,25960
33044,26093
31176,26093
31176,28743
32738,28743
32738,28785
34877,28785
34877,30198
36901,30198
36901,30162
39344,30162
39344,33358
41281,33358
41281,34472
42344,34472
42344,37130
42911,37130
42911,40724
42976,40724
42976,42574
42005,42574
42005,45576
40624,45576
40624,46719
39056,46719
39056,49339
37488,49339
37488,50217
37487,50217
37487,50218
35652,50218
35652,52085
33260,52085
33260,55317
31308,55317
31308,56857
31877,56857
31877,57683
34848,57683
34848,56774
38183,56774
38183,56866
40795,56866
40795,56313
43322,56313
43322,56434
44903,56434
44903,59572
44903,62997
43478,62997
43478,62408
40479,62408
40479,63128
38117,63128
38117,63866
35924,63866
35924,63929
32867,63929
32867,63048
30750,63048
30750,63494
28882,63494
28882,62914
25696,62914
25696,63070
22925,63070
22925,63280
20788,63280
20788,62997
19526,62997
19526,59915
19526,58552
20488,58552
20488,56408
20489,56408
20489,56407
22657,56407
22657,55948
24578,55948
24578,54300
26471,54300
26471,52397
28868,52397
28868,50163
30304,50163
30304,49017
31593,49017
31593,45754
34038,45754
34038,43900
35203,43900
35203,40595
35009,40595
35009,39657
35010,39657
35010,39656
35022,39656
35022,35462
33924,35462
33924,36128
31354,36128
31354,35449
28186,35449
28186,35250
26314,35250
26314,36245
24735,36245
24735,38271
22441,38271
22441,35782
20350,35782
20350,34088
19985,34088
19985,32471
21940,32471
21940,30448
24765,30448
24765,28386
27804,28386
27804,28846
30164,28846
30164,28742
30163,28742
30163,28845
27805,28845
27805,28385
24764,28385
24764,30447
21939,30447
21939,32470
19984,32470
19984,34089
20349,34089
20349,35783
22440,35783
22440,38272
24736,38272
24736,36246
26315,36246
26315,35251
28185,35251
28185,35450
31353,35450
31353,36129
33925,36129
33925,35463
35021,35463
35021,39655
35008,39655
35008,40596
35202,40596
35202,43899
34037,43899
34037,45753
31592,45753
31592,49016
30303,49016
30303,50162
28867,50162
28867,52395
28866,52395
28866,52396
26470,52396
26470,54299
24577,54299
24577,55947
22656,55947
22656,56406
20487,56406
20487,58551
19525,58551
19525,59915
19525,62998
20787,62998
20787,63281
22926,63281
22926,63071
25697,63071
25697,62915
28881,62915
28881,63495
30751,63495
30751,63049
32865,63049
32865,63050
32866,63050
32866,63930
35925,63930
35925,63867
38118,63867
38118,63130
38119,63130
38119,63129
40480,63129
40480,62409
43477,62409
43477,62998
44904,62998
44904,59572
44904,56433
43323,56433
43323,56312
40794,56312
40794,56864
40793,56864
40793,56865
38184,56865
38184,56773
34847,56773
34847,57682
31879,57682
31879,57681
31878,57681
31878,56856
31309,56856
31309,55318
33261,55318
33261,52086
35653,52086
35653,50219
37489,50219
37489,49340
39057,49340
39057,46720
40625,46720
40625,45577
42006,45577
42006,42575
42977,42575
42977,40723
42912,40723
42912,37129
42345,37129
42345,34471
41282,34471
41282,33357
39345,33357
39345,30161
36900,30161
36900,30197
34878,30197
34878,28784
32739,28784
32739,28742
31177,28742
31177,26094
33045,26094
33045,25961
35816,25961
35816,23177
37953,23177
37953,23916
40071,23916
40071,22399
42511,22399
42511,22097
45274,22097
45274,21569
48202,21569
48202,19863
50950,19863
50950,18170
52769,18170
52769,17932
55730,17932
55730,17466
58869,17466
58869,16632
59841,16632
59841,14241
62085,14241
62085,15457
64103,15457
64103,17414
66237,17414
66237,18372
69084,18372
69084,20040
71575,20040
71575,21133
72818,21133
72818,24913
74391,24913
74391,24866
75648,24866
75648,28304
76911,28304
76911,29493
78642,29493
78642,32317
79687,32317
79687,36169
80374,36169
80374,37109
80646,37109
80646,40621
80271,40621
80271,43885
80654,43885
80654,45870

I will add more to this write-up later...

** Day 10: Factory – Pressing buttons to turn on lights in a pattern, and set joltage levels
Part 1

Not so bad.

Probably, the most important insight for this one ...

... is noting that every button is pressed either exactly once or not at all.

You could use ...

... itertools.combinations to help out a little here.

Just put it in a loop, and ...

... increase the combo count from 0 through n (the number of lights). With this approach, the very first solution found is necessarily the minimum button-press count.

all(...) and zip(...) could be useful as well (for checking against the goal pattern).

Part 2

This was substantially harder than Part 1, and it reminded me a bit of Part 2 of Claw Contraption from 2024. (That's a bit of a hint.)

The single most important thing to recognize is ...

... that this is fundamentally a linear programming/algebra problem.

The first step is to ...

... transform it into a system of linear equations that represent buttons as columns in matrix A, and joltages as the target vector b, with x being the solution vector to solve for: Ax = b.

Using the problem's example data—[.##.] (3) (1,3) (2) (2,3) (0,2) (0,1) {3,5,4,7}—this looks like ...
                                 A                              x          b

row 0 [ 0         0         0         0         1         0 ] [ x₀ ]     [ 3 ]
row 1 [ 0         1         0         0         0         0 ] [ x₁ ]     [ 5 ]
row 2 [ 0         0         1         1         1         1 ] [ x₂ ]  =  [ 4 ]
row 3 [ 1         1         0         1         0         1 ] [ x₃ ]     [ 7 ]
        ^         ^         ^         ^         ^         ^   [ x₄ ]       ^
        |         |         |         |         |         |   [ x₅ ]       |
       (3)      (1,3)      (2)      (2,3)     (0,2)     (0,1)   ^         goal
    button 0  button 1  button 2  button 3  button 4  button 5  |       joltages
                                                             solution
                                                  (times each button is pressed)
Then, you need to ...

... manipulate the matrices into a form where things are more directly determined, i.e., get things into row-reduced echelon form (RREF) using Gauss-Jordan elimination on the (augmented) matrix.

Beware of possible ...

... non-integer resulting entries, which may throw a monkey wrench into the process. I solved this by using the fractions module, along with lcm(...) and gcd(...) to, as needed, transform all entries back into smallest-possible exact integers before continuing.

For some of the data set's problems, solving this is enough to get the answer since they're fully determined. For others, it's not. So, what do you do then?

Specifically, what do you do when you have free (independent) variables remaining?

In that case, just remember that the whole reason for using all this linear algebra stuff is because the solution space was simply too large to brute-force explore, but ...

... now it's not. Its size has been radically reduced by the math, and, fortunately, you have hard limits on each of the free variables remaining since you can easily identify bounds on the number of button presses for each: compare the goal joltages to those affected by each free-variable-button press, and select the minimum as the upper limit, per variable. (Obviously, 0 is the lower limit for all of them.) Since none of the systems in the data exceed three free variables—at least, I don't think they did in my data—you can just exhaustively try them all quite quickly, and track the minimum.

** Day 11: Reactor – Troubleshooting a server rack's connections by tracing cables
Part 1
This problem seems pretty much custom-tailored for ...

... a dynamic programming solution. It requires only very short code to solve, and I was surprised to see it as the second-to-last day's problem.

Part 2

Repeat the same tip as for Part 1. This required just a couple very minor tweaks to adapt Part 1's solution code to solve it.

** Day 12: Christmas Tree Farm – Trying to fit collections of oddly-shaped gifts under limited-boundary trees
Part 1

Carefully analyze the input data. (Seriously. Just do it. That's the first hint.)

As far as I know, this problem is ...

... in the general case, NP-hard. So, when I glanced at the scale of the provided input data, I was initially entirely at a loss as to how to approach it because the values appear far too large to just brute-force through.

However, I figured that, at the very least, I could examine the data in more detail to see if maybe some of the inputs could fairly easily be ruled out via a simple check or two.

The first test was to ...

... see if any of the entries were able to be rejected even if they were perfectly densely packed (no holes at all).

For each data input independently examined, let:

  • W : width of boundary region
  • L : length of boundary region
  • AR = WL : area of boundary region
  • ni : required number of shape i
  • ai : area covered by shape i, computed as its '#'-count (same across all "WxL: ni for i in 0..5" data inputs)
  • AD = Σ ni ai : "dense area", which is the theoretical minimum coverage area of all of an input's shapes (ignoring region shape)
  • N = Σ ni : total shape count
It should be obvious that if AD>AR, then that input can immediately be rejected as impossible.

Imagine my surprise when literally hundreds of the inputs were rejected by this simple check!

At any rate, this was all fine and good to discover, but it still didn't necessarily get me much closer to a final answer since it didn't tell me whether or not those remaining (not rejected) would work, and trying to crank through even just one of them would be computationally infeasible.

But, it did encourage me to then look more closely at those remaining inputs. I next examined ...

... just how much larger AR was than AD. It turned out to be by quite a substantial amount, even for the smallest one! Now, this seemed potentially promising...

I decided to examine them in terms of ratio, too—(1 - AD/AR)—and this also showed great promise because even the smallest "excess" was still >26%! That felt like quite a lot of "wiggle room".

Given all this, I decided to just see what would happen if ...

... I checked to see if all the respectively required shapes for each of the remaining regions could just be dropped in by providing it with its own little independent 3x3 tile space (since all the shapes are "3x3"), without even trying to interlock them at all. See figure.

┏━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃             ←"excesses"↓┃
┠┄┄┄┄┄┬┄┄┄┄┄┐     ┌┄┄┄┄┄┐ ┃
┃     ┆     ┆     ┆     ┆ ┃
┃  ?  ┆  ?  ┆ ... ┆  ?  ┆ ┃ ⌊L/3⌋
┃     ┆     ┆     ┆     ┆ ┃
┠┄┄┄┄┄┴┄┄┄┄┄┘     └┄┄┄┄┄┘ ┃
┃  .     .      .    .    ┃  .
┃  .     .     .     .    ┃  .
┃  .     .    .      .    ┃  .
┠┄┄┄┄┄┬┄┄┄┄┄┐     ┌┄┄┄┄┄┐ ┃
┃ ### ┆ ### ┆     ┆     ┆ ┃
┃  ## ┆ #   ┆ ... ┆  ?  ┆ ┃  2
┃   # ┆ ### ┆     ┆     ┆ ┃
┠┄┄┄┄┄┼┄┄┄┄┄┤     ├┄┄┄┄┄┤ ┃
┃   # ┆ ##  ┆     ┆     ┆ ┃
┃ ### ┆  ## ┆ ... ┆  ?  ┆ ┃  1
┃ ### ┆   # ┆     ┆     ┆ ┃
┗━━━━━┷━━━━━┷━━━━━┷━━━━━┷━┛
   1     2    ...  ⌊W/3⌋

That is, I tested to see how many inputs passed the check that ⌊W/3⌋ × ⌊L/3⌋ ≥ N.

Every single one of the remaining inputs passed this test, giving me my answer!

On a closing note, I will just say that I think this problem is super sketchy in how it unfolded. For example, the approach outlined above fails on the test data, and the entire problem presentation essentially misleads you away from it! (Don't get me wrong; I'm glad it ended up the way it did, because I don't see how it's feasible otherwise; but, still...)

Part 2

This Part gives you a star for free, providing that final required piece to finish . . . in conjunction with completing all 23 of the preceding Parts of this year's problems.