01020304050607080910111213141516171819202122232425

Advent of Code

2024/7

Bridge Repair

in C#

by encse

The Historians take you to a familiar rope bridge over a river in the middle of a jungle. The Chief isn't on this side of the bridge, though; maybe he's on the other side?

When you go to cross the bridge, you notice a group of engineers trying to repair it. (Apparently, it breaks pretty frequently.) You won't be able to cross until it's fixed.

Visit the website for the full story and puzzle description.

It's time to pull out the recursion guns. I introduced a checker logic that goes through the numbers in one line of input and tries all possible operators on the accumulated result to reach the target.

The common logic that parses the input and executes the checker was extracted into a single Solve function, but I found it more readable to have distinct checkers for the two parts of the problem.

Everything runs in about a second, but since it's just a single line, I couldn't stand and added an optimization in Check2 to exit early when the accumulated result exceeds the target.

namespace AdventOfCode.Y2024.Day07;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

[ProblemName("Bridge Repair")]
class Solution : Solver {

    public object PartOne(string input) => Filter(input, Check1).Sum();
    public object PartTwo(string input) => Filter(input, Check2).Sum();

    // returns those calibrations that are valid according to the checker
    private IEnumerable<long> Filter(string input, Func<long,long,List<long>, bool> check) => 
        from line in input.Split("\n")
            let parts = Regex.Matches(line, @"\d+").Select(m=>long.Parse(m.Value))
            let target = parts.First()
            let nums = parts.Skip(1).ToList()
        where check(target, nums[0], nums[1..])
        select target;

    // separate checkers provided for the two parts, these recursive functions go
    // over the numbers and use all allowed operators to update the accumulated result.
    // at the end of the recursion we simply check if we reached the target
    private bool Check1(long target, long acc, List<long> nums) =>
        nums switch {
            [] => target == acc,
            _  => Check1(target, acc * nums[0], nums[1..]) ||
                  Check1(target, acc + nums[0], nums[1..])
        };

    private bool Check2(long target, long acc, List<long> nums) =>
        nums switch {
            _ when acc > target => false, // optimization: early exit from deadend
            [] => target == acc,
            _  => Check2(target, long.Parse($"{acc}{nums[0]}"), nums[1..]) ||
                  Check2(target, acc * nums[0], nums[1..]) ||
                  Check2(target, acc + nums[0], nums[1..])
        };
}

Please ☆ my repo if you like it!

© 2025 Advent of Code is a registered trademark in the US Images provided by Bing image creator