using System.Collections.Generic; using System.Data.Common; using System.IO; using System.Linq; using AdvenOfCode.Contracts; using Coordinate = (int x, int y); 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 nodesWithCount = GetTimelinesCountRecursive(grid, start, []); return nodesWithCount; } public long SolvePart2Again(string pathToPuzzleInput) { var grid = ParsePuzzleInput(pathToPuzzleInput); var nodesWithCount = GetTimelinesCount(grid); return nodesWithCount.Sum(); } private Coordinate GetStart(string[] grid) { return (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[current.x][current.y] == '^') { splittersHit++; CheckAndEnqueueIfNotVisited((current.x, current.y - 1)); CheckAndEnqueueIfNotVisited((current.x, current.y + 1)); } else { CheckAndEnqueueIfNotVisited((current.x + 1, current.y)); } } 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[current.x][current.y] == '^') { var resLeft = GetTimelinesCountRecursive(grid, (current.x, current.y - 1), memory); var resRight = GetTimelinesCountRecursive(grid, (current.x, current.y + 1), memory); memory[current] = resLeft + resRight; return resLeft + resRight; } var res = GetTimelinesCountRecursive(grid, (current.x + 1, current.y), 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]; } }