diff --git a/2024/Day07/README.md b/2024/Day07/README.md index 17748365..8f9c87af 100644 --- a/2024/Day07/README.md +++ b/2024/Day07/README.md @@ -6,3 +6,7 @@ When you go to cross the bridge, you notice a group of engineers trying to repai You ask how long it'll take; the engineers tell you that it only needs final calibrations, but some young elephants were playing nearby and stole all the operators from their calibration equations! They could finish the calibrations if only someone could determine which test values could possibly be produced by placing any combination of operators into their calibration equations (your puzzle input). Read the [full puzzle](https://adventofcode.com/2024/day/7). + +It's time to pull out the recursion guns. I introduced a checker logic that go 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 added an optimization in `Check2` to exit early when the accumulated result exceeds the target. diff --git a/2024/Day07/Solution.cs b/2024/Day07/Solution.cs index e1ac5026..ee341d35 100644 --- a/2024/Day07/Solution.cs +++ b/2024/Day07/Solution.cs @@ -11,6 +11,7 @@ class Solution : Solver { public object PartOne(string input) => Filter(input, Check1).Sum(); public object PartTwo(string input) => Filter(input, Check2).Sum(); + // returns those calibrations returns that are valid according to the checker private IEnumerable Filter(string input, Func, bool> check) => from line in input.Split("\n") let parts = Regex.Matches(line, @"\d+").Select(m=>long.Parse(m.Value)) @@ -19,6 +20,9 @@ from line in input.Split("\n") where check(target, 0, nums) select target; + // separate checkers provided for the two parts, these recursive functions go + // over the numbers and use all alloved 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 nums) => nums switch { [] => target == acc, @@ -28,9 +32,10 @@ private bool Check1(long target, long acc, List nums) => private bool Check2(long target, long acc, List nums) => nums switch { + _ when acc > target => false, // optimization: early exit from deadend [] => target == acc, - _ => Check2(target, acc * nums[0], nums[1..]) || - Check2(target, acc + nums[0], nums[1..]) || - Check2(target, long.Parse($"{acc}{nums[0]}"), nums[1..]) + _ => Check2(target, long.Parse($"{acc}{nums[0]}"), nums[1..]) || + Check2(target, acc * nums[0], nums[1..]) || + Check2(target, acc + nums[0], nums[1..]) }; } \ No newline at end of file