Advent of Code 2025 in Charly

Day 3

This article is part of my series on implementing each Advent of Code 2025 challenge in my own programming language Charly.

Today’s task was determining which batteries to turn on to reach the highest possible joltage. Batteries were grouped together into a bank.

For example: 987654321111111 is a battery bank that consists of 15 batteries, each with a lower joltage rating than the one before it. The total output joltage of a bank is equal to the number formed by the joltage ratings of each battery that is turned on.

For example, if you have a bank like 12345 and you turn on battery 2 and 4, you get a total of 24 jolts.

Part 1 of the puzzle required finding the largest possible joltage achievable by turning on exactly two batteries. Part 2 modified the task by instead requiring 12 batteries to be turned on.

I solved the task by determining which battery, when turned on, would result in the largest possible joltage for the entire bank, and then repeating this as many times as required.

Interestingly, parallelizing the computation via the List::parallelMap method I added yesterday actually resulted in a noticeable speedup of around 4x. 😁

#!/usr/local/bin/charly

if ARGV.length < 2 {
  print("Missing filepath")
  exit(1)
}

const input_path = ARGV[1]
const input = readfile(input_path)

const amountOfBatteriesToTurnOn = 12

func applyActivationRecord(bank, record) {
    assert bank.length == record.length

    const activatedBatteries = bank.filter(->(e, i) record[i])
    const finalNumber = activatedBatteries.join("").to_number()

    return finalNumber
}

const banks = input
    .split("\n")
    .map(->(bank) {
        bank.split("").map(->(battery) battery.to_number())
    })
    .parallelMap(->(bank) {
        const activationRecord = List.create(bank.length, false)

        amountOfBatteriesToTurnOn.times(->{
            const potentialFlips = activationRecord.mapNotNull(->(s, i) {
                if s return null

                const newRecord = activationRecord.copy()
                newRecord[i] = true

                const newNumber = applyActivationRecord(bank, newRecord)
                return (newNumber, i)
            })

            const (newNumber, flipIndex) = potentialFlips.findMaxBy(->(e) e[0])
            activationRecord[flipIndex] = true
        })

        applyActivationRecord(bank, activationRecord)
    })

const finalJoltage = banks.sum()
print(finalJoltage)

Changes to the stdlib / VM

No changes to the VM itself had to be made, but I did add a good amount of new functionality to the standard library.


Copyright © 2024 - 2025 Leonard Schütz | Attributions This post was written by a human and reviewed and proof-read by LLMs