Advent of Code 2025 solutions
Day 1
+/~100!i:50+\.'@[;0;"--"5!]'0:"i/1" /p1
+/50(-/-100!@/1>:\-/1>/\,)':i /p2
Parsing
i:50+\.'@[;0;"--"5!]'0:"i/1"
0:"i/1"reads lines from the input file@[;0;"--"5!]'for each line, edit the first (0th) character by:5!taking modulo 5; the ASCII values of L and R are 76 and 82, so 1 and 2 mod 5- index
"--"with the mod 5 value; this gives"-"or" "because of a ngn/k quirk (the null value, returned when indexing outside an array, is a space for characters)
.'evaluate each line (it’s a convenient way to parse numbers)50+\scan addition, i.e. rolling sum, seeded with 50
Part 1
+/~100!i
100!modulo 100 of the rolling sum~not, which is equivalent to “equals 0”+/sum
Part 2
+/50(-/-100!@/1>:\-/1>/\,)':i
50(…)':for each value and its prior value (with 50 as the “prior” value for the first element),make a pair out of the two valuesN.B. The
':“eachprior” adverb calls functions with the prior value (before in the array) as the second argumentFor an input with a single
R50line,iis50 100, but the pair created here is100 50-/1>/\bubbler train #1: subtract 1 from both values if the first (current value) is larger – i.e. right turnsThe end result of the solution is the same regardless of whether
>or<is used, there just needs to be a choice made1(>/)\apply>/(greater-than fold), once. this results in a pair like((100 50);1)-/subtract fold. resulting in100 50-1or99 49
@/1>:\bubbler train #2: sort in descending order (put the greater element first)1(>:)\grade, descending. this results in a pair of the values and permutation vector, like(99 49;0 1)@/apply. results in99 49@0 1(it’s a no-op when the first value is greater already)
-100!integer division (of both values independently) by 100-/subtract
+/sum
Day 3
+/'(.*|)'',\:[,'0:"i/3";""]{(1_v_*x;x[1],(*x)v:*>y_*x)}/\:/:-|'!'2 12
,\:[,'0:"i/3";""]reads and creates a pair(line; "")(which hold unprocessed input and output) for each line of the input-|'!'2 12creates a sequence-1 0and-11 -10 ... -1 0(for part1/part2){(1_v_*x;x[1],(*x)v:*>y_*x)}/\:/:iterates through that sequence (yvalues) for each line of the input (xvalues are thein;outpairs)each iteration of this returns the
xvalue pair for the next iteration:v:*>y_*xsetsvto the index of the max value in the line, ignoring the lasty.(*x)vgets the line at that position.x[1],concatenates the value to the output1_v_*xdrops thev+1first characters of the line, leaving only what’s unprocessed
(.*|)''for both part 1 and 2, for each line,*|last element (get the output),.eval (to parse as a number)+/'for each part, sum
original ungolfed solution
i:.''0:"i/3"
f:{v:*>(-y)_*x;(1_v_*x;x[1],x[0;v])}
+/{10/*|(x;!0)f/1 0}'i /p1
+/{10/*|(x;!0)f/|!12}'i /p2
Day 4
i:"@"=0:"i/4"
f:&/1(5>2(+3+/':,[;0]0,)/)\
+//f i /p1
+//i-{x-f x}/i /p2
Parsing: 0:"i/4" read the file, "@"= equals to @ – resulting in a bit matrix (. -> 0, @ -> 1)
f is one huge bubbler train, let’s go in execution order:
2(...)/n-do, apply the function inside twice (one for each 2D axis):,[;0]0,prepend and append 0 (this is equal to{0,x,0})3+/':sum (+/) of sliding windows of 3 (3 f':)+transpose (swap axes)
1(5>...)\make it a pair (input; cells with <=4 neighbors)&/and – turn off 0 cells
Part 1 is just “how many 1 cells have <=4 neighbors", so +// sum-converge is all
Part 2 is “if you remove cells with <=4 neighbors and repeat, how many do you remove", so... you {x-f x} remove with a / converge. i- remove from the input to invert (we want what we’ve removed, not what’s left after removing), and just +// sum-converge again to get the final answer.
Day 5
not golfed
(r;s):"\n"\'"\n\n"\1:"i/5"; s:.'s
r:@[+@/1<:\.''"-"\'r;1;1+]
r:r@\:&~<':*|r
r:r@'&'~1(,[;0]1_)\~>/@[r;1;0 :':]
+/~2!(,/+r)'s /p1
+/-/|r /p2
(r;s):"\n"\'"\n\n"\1:"i/5"read the input file as a single string (1:as opposed to the usual pre-split0:), split ourselvess:.'seval each line in the second block+@/1<:\.''"-"\'rsplit ranges on"-",.''eval each each,@/1<:\sort,+transpose.transposition transforms the list of ranges from
((start;end);(start;end);(start;end);...)to a pair of two lists(starts; ends)r:@[...;1;1+]add 1 to range endsr:r@\:&~<':*|r: remove ranges whose ends are below the end of the range before (i.e. which are fully contained in another range)*|rlast element ofr(range ends)<':lessthan-eachpriorr@\:&~r where not
r:r@'&'~1(,[;0]1_)\~>/@[r;1;0 :':]merge ranges which overlap:@[r;1;0 :':]shift range ends to the right, inserting0at the start and dropping the last element~>/not greaterthan (less than or equals) comparison of starts and shifted ends1(,[;0]1_)\shift the comparison results list to the left, dropping the first element and inserting a 0 at the endr@'&'~r where not
for examples, ranges
1-4, 3-6, 10-12(r: (1 3 10;4 6 12)) get processed as:(1 3 10;0 4 6)shift ends0 1 0compared (1 <= 0, 3 <= 4, 10 <= 6)(0 1 0;1 0 0)shift: we’re dropping the start of the second range and the end of the first range(0 2;1 2)indices where not,(1 10;6 12)from r
Part 1
(,/+r)transpose r back and unravel, resulting in one single array like1 6 10 12(,/+r)'sbinary search every value inswithin the list, get the index of the closest value in the ranges~2!mod 2, invert – range starts are on even indices (0,2,…) and range ends are on odd indices (1,3,…)+/sum
Part 2
|rreverser(from a pair(starts;ends)to(ends;starts))-/subtract+/sum
Day 6
goal instead of ngn/k today. very boring day, basically all parsing
o:(+/;*/)@"*"=rx/ +/\*|i:=-read"i/6"
\+/o@'+"v"$-1_i
\+/o@'"v"$1_'rx/^ *$/_"","c"$+"c"$-1_i
Day 7
(+//<':;+/*|:)@\:(2!*i){(x*~y)+(1_b,0)+0 :':b:x*y}\94=i:0:"i/7"
This solution uses the “many-worlds interpretation” (given part 2) to solve both parts: “times the beam is split” are positions where, on one line, there are worlds where there is a beam, and on the next line, there are no longer any worlds where there could be a beam.
i:0:"i/7"read file, save intoi94=(94 is"^") turn the input into a bit matrix of splitters2!*iuse mod 2 to get a vector of zeros with a 1 for the inital beam ("S"is 83,"."is 46){(x*~y)+(1_b,0)+0 :':b:x*y}\scan through the input line matrix, adding up:0 :':b:x*ythe current beam count (x) where there are splitters (ythe input line), shifted right (0 :':is just a nerd version of0,-1_)1_b,0and shifted leftx*~yand where there aren’t splitters, the current beam count
(...)@\:apply eachleft:+//<':part 1:<':less than eachprior to obtain places where a beam splits,+//sum-converge to count+/*|:part 2:+/sum of*|:the last line (the possible number of worlds only matters after all splits are done)
Home About Contact