From 1873ce8e666253b5eeba05af3e599551c2844b7d Mon Sep 17 00:00:00 2001 From: Sebastian Lindemeier Date: Fri, 12 Dec 2025 15:03:01 +0100 Subject: [PATCH] Refactor Day10 to optimize pattern cost calculation by introducing bitmasking and grouping logic (speedup from 7 sec to 0.2 sec) --- AoC_2025/Day10.cs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/AoC_2025/Day10.cs b/AoC_2025/Day10.cs index 735f8b4..f1326c6 100644 --- a/AoC_2025/Day10.cs +++ b/AoC_2025/Day10.cs @@ -155,7 +155,7 @@ public class Day10 : IPuzzleSolver yield break; } - foreach (var (pattern, cost) in GetPatternCosts(lampState.Length, buttons)) + foreach (var (_,(pattern, cost)) in GetPatternCosts(lampState.Length, buttons)) { if (pattern.Zip(lampState, (pat, lam) => (pat % 2 == 1) == lam).All(x => x)) { @@ -166,30 +166,26 @@ public class Day10 : IPuzzleSolver private long GetMinCountButtonPressesForJoltageLevels(int[] joltages, int[][] buttons) { - var patternCosts = GetPatternCosts(joltages.Length, buttons).ToArray(); + var patternCosts = GetPatternCosts(joltages.Length, buttons) + .GroupBy(x => x.Item1) + .ToDictionary(x => x.Key, x => x.Select(y => y.Item2).ToArray()); var res = GetMinCountInternal(joltages, patternCosts, new Dictionary(new IntArrayEqualityComparer())); return res; - static long GetMinCountInternal(int[] targetJoltages, (int[] joltages, int cots)[] patternCosts, Dictionary memory) + static long GetMinCountInternal(int[] targetJoltages, Dictionary patternCosts, Dictionary memory) { + if (targetJoltages.Min() < 0) return 1_000_000_000L; if (targetJoltages.All(j => j == 0)) return 0; if (memory.TryGetValue(targetJoltages, out var knownResult)) return knownResult; var minCount = 1_000_000_000L; - var patternsToCheck = patternCosts - .Where(pc => - pc.joltages - .Zip(targetJoltages, (pJolt, tJolt) => (pJolt % 2) == (tJolt % 2)) - .All(isEqual => isEqual)) - .ToArray(); + var joltageMask = GetMask(targetJoltages, level => level % 2 == 1); + var patternsToCheck = patternCosts.GetValueOrDefault(joltageMask, []); foreach (var (joltageLevels, cost) in patternsToCheck) { var nextPattern = targetJoltages.Zip(joltageLevels, (jolts, level) => (jolts - level) / 2).ToArray(); var resultNext = 2 * GetMinCountInternal(nextPattern, patternCosts, memory) + cost; - if (resultNext < minCount) - { - minCount = resultNext; - } + minCount = Math.Min(minCount, resultNext); } memory[targetJoltages] = minCount; @@ -197,15 +193,16 @@ public class Day10 : IPuzzleSolver } } - private IEnumerable<(int[], int)> GetPatternCosts(int patternLength, int[][] buttons) + private IEnumerable<(uint, (int[], int))> GetPatternCosts(int patternLength, int[][] buttons) { - yield return ([..Enumerable.Repeat(0, patternLength)], 0); + yield return (0,([..Enumerable.Repeat(0, patternLength)], 0)); for (var i = 1; i <= buttons.Length; i++) { foreach (var buttonPattern in buttons.Combinations(i)) { var joltageLevels = GetJoltageLevelsForButtonPattern(patternLength, buttonPattern); - yield return (joltageLevels, buttonPattern.Length); + var mask = GetMask(joltageLevels, level => level % 2 == 1); + yield return (mask,(joltageLevels, buttonPattern.Length)); } } @@ -225,6 +222,9 @@ public class Day10 : IPuzzleSolver return joltagesProduced; } } + + private static uint GetMask(int[] toBeMasked, Func maskPredicate) => + toBeMasked.Aggregate((uint)0L, (acc, val) => (acc << 1) | (uint)(maskPredicate(val) ? 1 : 0)); private long GetMinCountButtonPressesForJoltagesZ3(int[] joltages, int[][] buttons) {