using AdvenOfCode.Contracts; using AdventOfCode.HelperClasses; namespace AoC_2025; public class Day07 : IPuzzleSolver { private string[] ParsePuzzleInput(string path) { var puzzleInput = File.ReadAllLines(path) .Where(line => !string.IsNullOrWhiteSpace(line)) .ToArray(); return puzzleInput; } public long SolvePart1(string pathToPuzzleInput) { var grid = ParsePuzzleInput(pathToPuzzleInput); var start = GetStart(grid); var count = TraverseGridAndCountSplitters(grid, start); return count; } public long SolvePart2(string pathToPuzzleInput) { var grid = ParsePuzzleInput(pathToPuzzleInput); var start = GetStart(grid); var timelinesCount = GetTimelinesCountRecursive(grid, start, []); return timelinesCount; } public long SolvePart2Again(string pathToPuzzleInput) { var grid = ParsePuzzleInput(pathToPuzzleInput); var timelinesCount = GetTimelinesCount(grid); return timelinesCount; } private Coordinate GetStart(string[] grid) { return new Coordinate(0, grid[0].IndexOf('S')); } private long TraverseGridAndCountSplitters(string[] grid, Coordinate start) { HashSet visited = [start]; var seen = new Queue(); seen.Enqueue(start); var splittersHit = 0L; while (seen.TryDequeue(out var current)) { if (current.X >= grid.Length) continue; if (current.Y >= grid[0].Length || current.Y < 0) continue; if (grid[(int)current.X][(int)current.Y] == '^') { splittersHit++; CheckAndEnqueueIfNotVisited(current with {Y = current.Y - 1}); CheckAndEnqueueIfNotVisited(current with {Y = current.Y + 1}); } else { CheckAndEnqueueIfNotVisited(current with {X = current.X + 1}); } } return splittersHit; void CheckAndEnqueueIfNotVisited(Coordinate coordinate) { if (visited.Add(coordinate)) seen.Enqueue(coordinate); } } // Dictionary only for memoization private long GetTimelinesCountRecursive(string[] grid, Coordinate current, Dictionary memory) { if (current.X >= grid.Length) { return 1; } if(memory.TryGetValue(current, out var count)) return count; if (grid[(int)current.X][(int)current.Y] == '^') { var resLeft = GetTimelinesCountRecursive(grid, current with {Y = current.Y - 1}, memory); var resRight = GetTimelinesCountRecursive(grid, current with {Y = current.Y + 1}, memory); memory[current] = resLeft + resRight; return resLeft + resRight; } var res = GetTimelinesCountRecursive(grid, current with {X = current.X + 1}, memory); memory[current] = res; return res; } private long GetTimelinesCount(string[] grid) { var numbersGrid = grid .Select(line => line.Select(c => 0L).ToArray()) .ToArray(); for (var x = 1; x < numbersGrid.Length; x++) { for (var y = 0; y < numbersGrid[x].Length; y++) { var gridValue = grid[x - 1][y]; switch (gridValue) { case 'S': numbersGrid[x][y] = 1; break; case '.': numbersGrid[x][y] += numbersGrid[x - 1][y]; break; case '^': numbersGrid[x][y - 1] += numbersGrid[x - 1][y]; numbersGrid[x][y + 1] += numbersGrid[x - 1][y]; break; } } } return numbersGrid[^1].Sum(); } }