using AdventOfCode.Core.Shared.IO; namespace AdventOfCode.Solutions._2023 { public partial class Day12 : IChallange { public int Year => 2023; public int Day => 12; private readonly IInputReader _inputReader; public Day12(IInputReader inputReader) { _inputReader = inputReader; _inputReader.SetInput(this); } public async Task GetSolutionPart1() { long total = 0; await foreach(string line in _inputReader.ReadAsStringLine()) { string[] splitted = line.Split(' '); int[] groups = splitted[1].Split(',').Select(int.Parse).ToArray(); long possiblies = Possibilities([], splitted[0], groups, 0, 0, 0); total += possiblies; } return total.ToString(); } public async Task GetSolutionPart2() { long total = 0; await foreach (string line in _inputReader.ReadAsStringLine()) { string[] splitted = line.Split(' '); var joinedLine = string.Join("?", [splitted[0], splitted[0], splitted[0], splitted[0], splitted[0]]); int[] groups = splitted[1].Split(',').Select(int.Parse).ToArray(); int[] groupsTotal = groups.Concat(groups).Concat(groups).Concat(groups).Concat(groups).ToArray(); long possiblies = Possibilities([], joinedLine, groupsTotal, 0, 0, 0); total += possiblies; } return total.ToString(); } private static long Possibilities(Dictionary<(int, int, int), long> capturedCache, string stringToValidate, int[] captureGroups, int stringIndex, int groupIndex, int currentCaptureLength) { if (capturedCache.TryGetValue((stringIndex, groupIndex, currentCaptureLength), out var possibilities)) return possibilities; if (stringIndex == stringToValidate.Length) // End of string return groupIndex == captureGroups.Length || (groupIndex == captureGroups.Length - 1 && captureGroups[groupIndex] == currentCaptureLength) ? 1 : 0; possibilities = 0L; if (stringToValidate[stringIndex] is '.' or '?') // Assuming '?' is '.' { if (currentCaptureLength == 0) // Start a capture { possibilities += Possibilities(capturedCache, stringToValidate, captureGroups, stringIndex + 1, groupIndex, 0); // Not in capture. Skip to next char } else if (currentCaptureLength == captureGroups[groupIndex]) // After a capture { possibilities += Possibilities(capturedCache, stringToValidate, captureGroups, stringIndex + 1, groupIndex + 1, 0); // Captured group. Go to next group } } if (stringToValidate[stringIndex] is '#' or '?' && groupIndex < captureGroups.Length && currentCaptureLength < captureGroups[groupIndex]) // Assuming '?' is '#' { possibilities += Possibilities(capturedCache, stringToValidate, captureGroups, stringIndex + 1, groupIndex, currentCaptureLength + 1); // In capture } // Add the capture to the capture cache capturedCache[(stringIndex, groupIndex, currentCaptureLength)] = possibilities; return possibilities; } } }