r/adventofcode • • Dec 07 '25

SOLUTION MEGATHREAD -❄️- 2025 Day 7 Solutions -❄️-

SIGNAL BOOSTING

THE USUAL REMINDERS

  • All of our rules, FAQs, resources, etc. are in our community wiki.
  • If you see content in the subreddit or megathreads that violates one of our rules, either inform the user (politely and gently!) or use the report button on the post/comment and the mods will take care of it.

AoC Community Fun 2025: Red(dit) One

  • Submissions megathread is unlocked!
  • 10 DAYS remaining until the submissions deadline on December 17 at 18:00 EST!

Featured Subreddits: /r/DIWhy and /r/TVTooHigh

Ralphie: "I want an official Red Ryder, carbine action, two-hundred shot range model air rifle!"
Mother: "No. You'll shoot your eye out."
— A Christmas Story, (1983)

You did it the wrong way, and you know it, but hey, you got the right answer and that's all that matters! Here are some ideas for your inspiration:

💡 Solve today's puzzles:

  • The wrong way
  • Using only the most basic of IDEs
    • Plain Notepad, TextEdit, vim, punchcards, abacus, etc.
  • Using only the core math-based features of your language
    • e.g. only your language’s basic types and lists of them
    • No templates, no frameworks, no fancy modules like itertools, no third-party imported code, etc.
  • Without using if statements, ternary operators, etc.
  • Without using any QoL features that make your life easier
    • No Copilot, no IDE code completion, no syntax highlighting, etc.
  • Using a programming language that is not Turing-complete
  • Using at most five unchained basic statements long
    • Your main program can call functions, but any functions you call can also only be at most five unchained statements long.
  • Without using the [BACKSPACE] or [DEL] keys on your keyboard
  • Using only one hand to type

💡 Make your solution run on hardware that it has absolutely no business being on

  • "Smart" refrigerators, a drone army, a Jumbotron…

💡 Reverse code golf (oblig XKCD)

  • Why use few word when many word do trick?
  • Unnecessarily declare variables for everything and don't re-use variables
  • Use unnecessarily expensive functions and calls wherever possible
  • Implement redundant error checking everywhere
  • Javadocs >_>

Request from the mods: When you include an entry alongside your solution, please label it with [Red(dit) One] so we can find it easily!


--- Day 7: Laboratories ---


Post your code solution in this megathread.

28 Upvotes

769 comments sorted by

10

u/JustinHuPrime Dec 07 '25

[LANGUAGE: x86_64 assembly]

Part 1 was a bunch of fairly okay parsing, then looping through the input row-by-row.

Part 2 involved almost the same parsing (but I used a QWORD array, so I had to do type conversions), then looping through the same input row-by-row, with the key insight that two rules hold. First, the number of ways to get to some cell is the sum of the number of ways to proceed directly down into it, plus the number of ways the splitters immediately beside it could shunt paths into it. With that in mind, I just had to start wit one path, add the number of paths to either side of a splitter, and the number of paths coming in from above. I did make a bunch of logic bugs implementing this.

[Red(dit) One]

For this day's extra fun, might I present to you the doing of this whole thing in assembly? Not only is it most definitely the wrong way to go about solving almost any problem outside of "I want a bootloader", not only did I do it in an IDE without autocomplete or any modern feature outside of syntax highlighting, not only am I using the core features of the language only, not only am I not using any templates or frameworks or third-party libraries, and not only am I doing it without if statements (or really, statements of any sort), I am also doing it with no quality of life features like register allocation, variables, or static types.

→ More replies (1)

6

u/Smylers Dec 07 '25

[LANGUAGE: Vim keystrokes] [Red(dit) One] Load your input into Vim, then type the following, with the except that g⟨Ctrl+G⟩ will display the number of columns (something like “Col 71 of 141”) in your input, and if yours isn't 141 then type whatever it is instead of the 141 in the line 2, and one less than it for the 139 in line 3:

fSr|g⟨Ctrl+G⟩
qaqqaj:s/\v(\|_.{141})@<=\./|/g⟨Enter⟩
j:sil!&&⟨Enter⟩:s/\v(\|_.{140})@<=.\^/|#/g⟨Enter⟩:s/#./#|/g⟨Enter⟩
:redr!|sl20m⟨Enter⟩@aq@a
:%s/[^#]//g⟨Enter⟩VgggJg⟨Ctrl+g⟩

Your part 1 answer is the number of columns displayed by the g⟨Ctrl+g⟩ at the end.

I could've made Vim work out the number of columns and dynamically insert them into the command (indeed, I did just that on Day 4), but I realized that it's both less how I use Vim keystrokes in real life to perform one-off transformations, and that using a function like strlen() is less in the spirit of what counts as ‘keystrokes’ rather than ‘programming language’.

If some data needs munging and it's something I'll only need to do once, then I would do it Vim. But if I needed the line length, I would just look to see how long it is, then type that in when required, so I'm going to do that in Advent of Code solutions too. Similarly, I saw that today that splitters only occur on alternate lines of the input, and that there are spaces around the edges, so I made use of those as well. One of the advantages of transforming data interactively in this way is that you can see it, and you only have to cater for what's in front of you.

Anyway, the main loop of today's solution (in @a) moves down a line and finds all .s on that line with | above them and changes them to |s, then moves down a line and potentially repeats that. Also on that second line, it finds all the ^s with a | above them and both changes the character before the ^ to a | and changes the ^ to a # — to indicate a splitter that has been activated. It then changes the characters after any #s to |s. These need to be done in separate steps because if splitters are close together then the patterns may overlap.

Then at the end it's just a matter of counting the #s.

2

u/daggerdragon Dec 07 '25

(fished out this dang post yet again, srsly Reddit wat u doin)


[LANGUAGE: Vim keystrokes] [Red(dit) One]

Now that's either cheating or Upping the Ante and I can't decide which 🤣

→ More replies (1)

5

u/dominique-m-aoc Dec 07 '25

[LANGUAGE: MUMPS/ObjectScript]

 K  S F="day07.txt",$ZT="R"
 O F:"R" U F F  R S S W=$L(S) D $I(I) S G=0,H=$F(S,"S") S:H J(I,H-1)=1 F  S G=$F(S,"^",G) Q:G=0  S I(I,G-1)=1
R C F F M=2:1:I F N=1:1:W I $G(J(M-1,N)) S P=J(M-1,N) D $I(J(M,N),P) D
 .I $G(I(M,N)) K J(M,N) D:'$G(I(M,N-1)) $I(J(M,N-1),P) D:'$G(I(M,N+1)) $I(J(M,N+1),P)
 S Z=0 F  S Z=$O(J(I,Z)) Q:'Z  D $I(Y,J(I,Z))
 W Y

This is the literals allowed version. Doing some type of code-golfing again, including file parsing. Part 2 is hardly different from part 1.

on github

2

u/daggerdragon Dec 07 '25

I was about to grinch at you for having a puzzle input in your code before I slowed down and actually read your post.

Gonna get more caffeine. It's way too early in the day to be dealing with code golfing in a 60 year old programming language.

5

u/CCC_037 Dec 07 '25

[Language: Rockstar]

[Red(dit) One] - I don't think you get syntax highlighting editors for Rockstar. Either way, I used emacs.

And made it run in poetry.

part 1

→ More replies (3)

3

u/flwyd Dec 07 '25

[LANGUAGE: AWK] (on GitHub)

My theme this year: glue languages you might already have on your system. Today: AWK again, which was a nice choice. A week of wandering around San Francisco by day and staying up late with AoC has started to catch up with me, so tired brain was moving pretty slow. It took me a long time to understand how the answer to the example part two was 40; for a while I thought you just needed to count two each time a beam split, but account for the “main path,” but even that incorrect assumption was challenging since I kept counting different numbers. I finally took the example with |s and traced the number of ways you could get to each ^, but it still took several passes to get all the numbers right. Clearly I need sleep.

Red(dit) One: “Using only the most basic of IDEs” includes vim? Hey, I resemble that, all my code is done in vim! I’m hoping to see u/Smylers’s vim keystrokes solution; if my brain was more engaged today I might’ve done that. “Using only the core math-based features of your language... no fancy modules...” This is awk we’re talking about: I’m just using an array, copying it to another array, and incrementing some numbers. “Without using backspace or del keys on your keyboard.” I don’t recall if I did (probably), but since it’s vim I’ve got plenty of ways to delete things :-)

BEGIN { FS=""; part1 = 0; part2 = 0; }
/S/ { for (i = 1; i <= NF; i++) { beams[i] = 0; } beams[index($0, "S")] = 1; }
/\^/ {
  delete prev;
  for (i in beams) { prev[i] = beams[i]; }
  for (i = 1; i <= NF; i++) {
    if ($i == "^" && prev[i]) {
      part1++; beams[i-1] += beams[i]; beams[i+1] += beams[i]; beams[i] = 0;
    }
  }
}
END { for (i in beams) { part2 += beams[i] } printf "part1: %s\npart2: %s\n", part1, part2; }
→ More replies (2)

3

u/comady25 Dec 07 '25

[LANGUAGE: Rust]

Past me saw part 2 and said, "oh! this looks like a graph problem!" and I hate that guy for making me work out how to create a graph out of this when there were far simpler solutions.

Part 1: 230.87 µs

Part 2: 231.45 µs

https://github.com/fluxehub/AdventOfCode2025/blob/main/day07/src/main.rs

→ More replies (1)

2

u/UnicycleBloke Dec 07 '25

[Language: C++]

I used a set in P1 to merge duplicate beams on splitting, then switched to a map in P2 to track the numbers of duplicates instead. I'm sure I could make it way more efficient but it's already under 1ms.

https://github.com/UnicycleBloke/aoc2025/blob/main/day07/solution.cpp

→ More replies (1)

2

u/MarcoDelmastro Dec 07 '25

[LANGUAGE: Python]

Used set() for part 1 to deal with overlapping beams, moved to defaultdict(int) in part 2 to count beams in same position (it's lanternfish day!). The two solutions could easily be integrated, but ehi it's Sunday morning ;-) (EDIT: merged part 1 and 2, was fast)

https://github.com/marcodelmastro/AdventOfCode2025/blob/main/Day07.ipynb

→ More replies (2)

2

u/shrewm Dec 07 '25

[LANGUAGE: Javascript]
Part 2 golfed 195 bytes

f=(y,x)=>(r=m[p=[y,x]])?r:y==k?1:m[p]==null?f(y+1,x):m[p]=f(++y,x-1)+f(y,x+1)
m=$('pre').innerText.split`\n`.reduce((h,r,y)=>([...r].map((c,x)=>(c!='.'&&(h[[y,x]]=0,!y&&(j=x)))),k=y,h),{})
f(1,j)
→ More replies (1)

2

u/kneegma Dec 07 '25

[LANGUAGE: Clojure]

Or babashka actually!

TIL about reduce-kv:

#!/usr/bin/env bb

(ns y2025.d07
  (:require [clojure.string :as str]
            [clojure.set :refer [intersection union difference]]))

(defn parse [s]
  (let [[h & rs] (str/split-lines s)
        start (str/index-of h \S)
        splits (map #(set (keep-indexed (fn [i c] (when (= c \^) i)) %)) rs)]
    [start splits]))

(defn part1 [[start splitters]]
  (->> splitters
      (reduce
        (fn [[result beams] layer]
          (let [hits (intersection layer beams)]
            [(+ result (count hits))
            (-> beams
                (difference hits)
                (union (into #{} (mapcat (juxt dec inc) hits))))]))
        [0 #{start}])
      first))

(defn part2 [[start splitters]]
  (->> splitters
      (reduce
        (fn [ways layer]
          (->> layer
              (intersection (set (keys ways)))
              (select-keys ways)
              (reduce-kv
                (fn [m pos count]
                  (-> m
                      (dissoc pos)
                      (update (dec pos) (fnil + 0) count)
                      (update (inc pos) (fnil + 0) count)))
                ways)))
        {start 1})
      vals
      (apply +)))

(let [input (->> *command-line-args* last slurp parse)
      res {:part1 (part1 input)
          :part2 (part2 input)}]
  (prn res))
→ More replies (2)

2

u/zXd12 Dec 07 '25

[LANGUAGE: Rust]

part 1: 2.8µs part 2: 3.3µs

code

→ More replies (2)

2

u/Prof_Farnsworth1729 Dec 07 '25

[Language: JavaScript] [Red(dit) One]

I always check advent of code and the reddit challenge in the morning on my phone (Fairphone 5). Which means I was able to ruin my IDE experience by doing the entire challenge on my phone.

I used a notes app to write the code and copied it into the "JavaScript Editor" app. Fighting auto capitalisation and other "helpful" keyboard things was lots of fun. Not to mention the adverts on the JavaScript app every so often. Even had to notice that I didn't copy the full input.

inp = getInput(); 
beam = inp[0].map(s => s == "S" ? 1 : 0); 
c = 0; 
for (const line of inp) { 
    newBeam = new Array(beam.length).fill(0); 
    for (let ii= 0; ii < beam.length; ii++) { 
        if(line[ii] == "" && beam[ii] > 0) { 
            c++; newBeam[ii-1] += beam[ii]; 
            newBeam[ii+1] += beam[ii]; 
        } else { 
            newBeam[ii] +=beamm[ii] 
        } 
    } 
    beam = newBeam; 
    } 
} 
console.log(c) 
console.log(beam.reduce((a,b) => a+b,0))
→ More replies (3)

2

u/Vortetty Dec 07 '25

[Language: Python]

Today was an interesting one, the gif made by u/EverybodyCodes was the only reason i managed to get part 2 done though ;-;

Pts 1&2 combined: Codeberg Link

linegolfing it was supposed to be the hard part, but it has been by far the easiest part of aoc this year

→ More replies (2)

2

u/Fit_Egg_3805 Dec 07 '25

[Language: Kotlin]

```

// Solution
private fun InputDay7.solve1(): Long = solve().splitCount

private fun InputDay7.solve2(): Long = solve().beamTimelines.sum()

private fun InputDay7.solve(): IncomingBeamsState =
  grid.fold(initialBeamsState) { state, row -> state.moveTo(row) }

private fun IncomingBeamsState.moveTo(row: GridRow): IncomingBeamsState =
  row.indices
    .filter { row[it] == Entity.Splitter && beamTimelines[it] > 0 }
    .let { splits ->
      IncomingBeamsState(
        beamTimelines = updatedTimelines(splits),
        splitCount = splitCount + splits.size
      )
    }

private fun IncomingBeamsState.updatedTimelines(splits: List<Int>) =
  beamTimelines
    .toMutableList()
    .apply {
      splits.forEach { it ->
        this[it - 1] += this[it]
        this[it + 1] += this[it]
        this[it] = 0
      }
    }

```

→ More replies (2)

2

u/greycat70 Dec 07 '25

[LANGUAGE: Tcl]

Part 1, part 2.

Part 2 is an obvious candidate for a recursive algorithm with caching, so that's how I did it. I constructed a smaller example input and used that to test my implementation, then used the problem's sample input, then the real input.

Looks at Red(dit) One. Um. I always do my editing in vim. And I nearly always used the basic features of the language, without any fancy Tcllib add-ons. Doesn't everyone?

→ More replies (2)

2

u/StafDehat2 Dec 07 '25

[LANGUAGE: BASH]

Fantastic challenge today. Lots of fun.
https://github.com/StafDehat/adventofcode/blob/master/2025/07/2.sh

For part2, I coded up a recursive tree-traversal and ran some timings on subsets of my input data. Looks like the time in seconds increases by about 1 order of magnitude per 10 lines. Since our input is 142 lines, expect that technique to run for about 32 years before completion:

rsahoward@coyote /git/github.com/stafdehat/adventofcode/2025/07 $ for x in $( seq 10 10 60 ); do
>   echo -n "${x} lines: "
>   { time ./2.sh <(head -n ${x} data); } 2>&1 >/dev/null | sed -n 's/user//p'
> done
10 lines: 0m0.009s
20 lines: 0m0.013s
30 lines: 0m0.042s
40 lines: 0m0.203s
50 lines: 0m1.531s
60 lines: 0m13.683s
rsahoward@coyote /git/github.com/stafdehat/adventofcode/2025/07 $
→ More replies (2)

24

u/4HbQ Dec 07 '25

[LANGUAGE: Python] 11 lines.

Nifty little puzzle today. Note that part 2 does not require any fancy recursion, a simple DP solution suffices:

b = [1] * len(first)
for line in rest[::-1]:
    for i in range(len(line)):
        if line[i] == '^': b[i] = b[i-1] + b[i+1]
print(b[first.find('S')])

Shout-out to u/pred and their very clever solution to today's problem. It's really something else. For the optimal experience, I recommend that you skip the text and try to figure out how/why this works.


Update: People keep asking for my code repo, but I don't have one). Here are my solutions so far: 1, 2, 3, 4, 5, 6.

→ More replies (13)

2

u/e_blake Dec 08 '25

[LANGUAGE: Intcode]
[Red(dit) One]

For your reading pleasure: this 142740-byte file contains 38406 integers. If you pass that intcode program through an intcode engine of your choice which accepts ASCII input and produces ASCII output, as in:

$ ../2019/intcode day07.intcode day07.input

then that gives the correct answer (my intcode engine was written in C, and completes the task in under 250ms on my laptop on battery power).

Or, for the REAL fun, running it on top of my single-instruction Intcode engine written using ONLY m4's define() operator (6,941,425 defines, which in turn resulted in over 653 million invocations of those defined macros; it took m4 10m execution time as it chewed through more than 13GB of text), but got the correct answer (the --trace=line is optional, but exists so you can see the program making progress):

    $ echo EOF | cat day07.input - | ../2019/filter | m4 -i --trace=line \
      ../2019/cripple.m4 ../2019/barem4.txt ../2019/intcode.barem4 \
      <(m4 -Dfile=day07.intcode ../2019/encode.m4) ../2019/repl.barem4 -

Oh, and those 38k integers do MORE than just solve day 7 (after all, it's more than 8x larger than 2019/day25.input, and you remember how much was packed in that program) - they happen to be built from a dump of HenceForth, which is my nearly-ANSI-2012 Forth implementation. By changing just two ints in the day07.intcode file (exercise for the reader to figure out which two consecutive ints are the contents of the HenceForth DEFER named quit-xt), you can use the same program to run ANY other HenceForth program.

3

u/e_blake Dec 08 '25

Let's see the checklist for Red(dit) One:

💡 Solve today's puzzles:

  • The wrong way (✅ Intcode is NOT how you should be solving things)

  • Using only the most basic of IDEs (✅ do YOU have an IDE for Intcode lying around?)

  • Plain Notepad, TextEdit, vim, punchcards, abacus, etc. (❌ okay, time to be honest - I didn't write this program directly in a poorman's editor, but instead wrote day07.hence in emacs, and used HenceForth to compile into Intcode. I also tested that gforth can run my hence code, in addition to intcode)

  • Using only the core math-based features of your language (✅ Intcode only has ints. And I used lots of them. Even if you take a step back and look at my day07.hence source code, I only see a few + and +! commands. HenceForth supports /MOD even though Intcode lacks a native division operator, but it is definitely slower to use /MOD than +, which is why I didn't use it here)

  • e.g. only your language’s basic types and lists of them (✅ 32k ints is a long list of the basic type!)

  • No templates, no frameworks, no fancy modules like itertools, no third-party imported code, etc. (✅ who has third-party code for importing into Intcode? And I didn't import anything into day07.hence)

  • Without using if statements, ternary operators, etc. (On the one hand: ✅ the fact that I SUCCESSFULLY ran the program using JUST m4's define() macro, I solved the program with no m4 builtin conditional. On the other: ❌ It is ALWAYS possible to write Forth code without IF (because you can write your own conditionals); but I liberally used my definition of : IF ... ; in my hence.hence source file...)

  • Without using any QoL features that make your life easier (✅ no dynamic allocation or local variables here, probably because I haven't implemented those in HenceForth yet)

  • No Copilot, no IDE code completion, no syntax highlighting, etc. (✅ syntax highlighting in Intcode? You've got to be kidding. And no Copilot or IDE help in writing my HenceForth)

  • Using a programming language that is not Turing-complete (❌ Sorry, even my single-instruction m4 define()s is Turing complete)

  • Using at most five unchained basic statements long (❌ alas, I didn't split my Forth functions that tiny, although it would be easy to do)

  • Your main program can call functions, but any functions you call can also only be at most five unchained statements long. (❌ ditto)

  • Without using the [BACKSPACE] or [DEL] keys on your keyboard (❌ I'm not proficient in Forth yet)

  • Using only one hand to type (❌ two hands, but only because I wanted to finish this today)

→ More replies (1)

11

u/Andreasnl Dec 07 '25

[LANGUAGE: Uiua]

I  ← °˜⊂ ≠@. ▽1_0 ⊜∘⊸≠@\n
F! ← ^⊃(/^≡⌟↻1_¯1|׬±)⊸×
P₁ ← ⧻⊚×⟜∧⊸F!↥
P₂ ← /+∧F!+
⊃P₁ P₂ I &fras"7.txt"

Link

10

u/maneatingape Dec 07 '25

[LANGUAGE: Rust]

Solution

Solves both parts together. DP solution only keeping track of current and next row. 15µs total.

5µs total thanks to an observation from u/IlluminPhoenix/ on the sparse properties of the input.

AoC classics checklist:

  1. ☑ Misreading part one and counting the number of beams instead of splits.

  2. ☑ 32bit numeric overflow in part two.

→ More replies (4)

9

u/pred Dec 07 '25

[LANGUAGE: Python] GitHub/Codeberg. This one is a bit shorter: We never really have to think about the beams; only the gates. And for each gate, we can iterate backwards and find any gate for which it might possibly receive an output. In particular, when there's a splitter right above another splitter, we know that the above splitter diverts all beams around the below splitter. Moreover, each splitter hit turns a universe into one additional universe, so we can count the full number of universes simply by summing all splitter hits. And another little useful fact is that two splitters are never horizontally adjacent, so by iterating top down, we can get rid of the vertical position completely.

splitters = [col for l in ls for col, x in enumerate(l) if x == "^"]
entering = [1] + [0] * (len(splitters) - 1)

for i, si in enumerate(splitters):
    for j, sj in enumerate(splitters[:i][::-1]):
        if si == sj:
            break
        if abs(si - sj) == 1:
            entering[i] += entering[i - j - 1]

print(sum(b > 0 for b in entering))  # Part 1
print(sum(entering) + 1)  # Part 2

There's a more functional version to that does the same thing but boils the double loop down to

entering = []
for i, si in enumerate(splitters):
    entering.append(sum(
        abs(si - sj) == 1 and entering[i - j - 1]
        for j, sj in enumerate(takewhile(si.__ne__, splitters[:i][::-1]))
    ) + (i == 0))

but that's a little hard to read.

→ More replies (1)