Advent of Code 2025 in Charly
Day 7
This article is part of my series on implementing each Advent of Code 2025 challenge in my own programming language Charly.
Part 1
Today’s task asked to fix the teleporter matrix in the elves
teleporter room. To do so, we need to inspect the teleporter’s
tachyon manifold. The tachyon manifold looks something like
this:
.......S.......
...............
.......^.......
...............
......^.^......
...............
.....^.^.^.....
...............
....^.^...^....
...............
...^.^...^.^...
...............
..^...^.....^..
...............
.^.^.^.^.^...^.
...............In the diagram above, the S denotes where the tachyon
beam enters the manifold. Tachyon beams (|) extend
downwards and can freely pass through empty space (.). If a
tachyon beam hits a splitter (^), the beam is stopped and
two new tachyon beams are emitted from the immediate left and right of
the splitter.
After letting the beam pass through the entire manifold, the resulting beam paths look like this:
.......S.......
.......|.......
......|^|......
......|.|......
.....|^|^|.....
.....|.|.|.....
....|^|^|^|....
....|.|.|.|....
...|^|^|||^|...
...|.|.|||.|...
..|^|^|||^|^|..
..|.|.|||.|.|..
.|^|||^||.||^|.
.|.|||.||.||.|.
|^|^|^|^|^|||^|
|.|.|.|.|.|||.|To solve the puzzle, I had to determine how many times the beam was split.
I did this by storing the positions where a beam is currently traveling and splitting those positions into two whenever a splitter was encountered.
You can find my solution for part 1 below:
const input_path = ARGV[1]
const lines = readfile(input_path).lines().filter(->(r, i) i % 2 == 0)
const grid = lines.map(->(row) { row.chars() })
const splitters = grid.dropFirst(1)
let totalSplits = 0
let beamPath = grid.first().map(->(point) {
switch point {
case "." return false
case "S" return true
}
})
splitters.each(->(row) {
const newBeamPath = beamPath.copy()
row.each(->(point, i) {
if beamPath[i] && point == "^" {
newBeamPath[i - 1] = true
newBeamPath[i + 1] = true
newBeamPath[i] = false
totalSplits += 1
}
})
beamPath = newBeamPath
})
print("totalSplits = {totalSplits}")Part 2
The second part of the puzzle revealed that this was no
regular tachyon manifold, it’s a
quantum tachyon manifold. In a quantum tachyon manifold, a
beam can only ever take a single path. So when it encounters a splitter,
it will only go one way, left or right.
To solve the second part, I had to determine how many possible paths through the manifold the tachyon beam could take.
I upgraded my solution from part 1 to instead keep track of how many paths could have led to the current position. Whenever two beams merged, their path counts were added together.
You can find my solution for part 2 below:
const input_path = ARGV[1]
const lines = readfile(input_path).lines().filter(->(r, i) i % 2 == 0)
const grid = lines.map(->(row) { row.chars() })
const splitters = grid.dropFirst(1)
let totalSplits = 0
let beamPathsCount = grid.first().map(->(point) {
switch point {
case "." return 0
case "S" return 1
}
})
splitters.each(->(row) {
const newBeamCount = beamPathsCount.copy()
row.each(->(point, i) {
if beamPathsCount[i] > 0 && point == "^" {
newBeamCount[i - 1] += newBeamCount[i]
newBeamCount[i + 1] += newBeamCount[i]
newBeamCount[i] = 0
totalSplits += 1
}
})
beamPathsCount = newBeamCount
})
const totalAvailablePaths = beamPathsCount.sum()
print("totalSplits = {totalSplits}")
print("totalAvailablePaths = {totalAvailablePaths}")Changes to the stdlib / VM
No changes had to be made to either the VM or the standard library.
Links
Copyright © 2024 - 2025 Leonard Schütz | Attributions This post was written by a human and reviewed and proof-read by LLMs