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 = GetNodesTraversedWitTimelineCount(grid, start, [], []); return nodesWithCount[start]; } public long SolvePart2Again(string pathToPuzzleInput) { var grid = ParsePuzzleInput(pathToPuzzleInput); var nodesWithCount = GetNodesTraversedWitTimelineCount(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++; var nextLeft = (current.x, current.y - 1); var nextRight = (current.x, current.y + 1); if (visited.Add(nextLeft)) seen.Enqueue(nextLeft); if (visited.Add(nextRight)) seen.Enqueue(nextRight); } else { var next = (current.x + 1, current.y); if (visited.Add(next)) seen.Enqueue(next); } } return splittersHit; } private Dictionary GetNodesTraversedWitTimelineCount(string[] grid, Coordinate current, HashSet path, Dictionary nodeCountVisited) { if (current.x >= grid.Length || nodeCountVisited.ContainsKey(current)) { nodeCountVisited = UpdateNodeVisitedCounts(current, path, nodeCountVisited); return nodeCountVisited; } nodeCountVisited[current] = 0; path.Add(current); if (grid[current.x][current.y] == '^') { var resLeft = GetNodesTraversedWitTimelineCount(grid, (current.x, current.y - 1), [..path], nodeCountVisited); var resRight = GetNodesTraversedWitTimelineCount(grid, (current.x, current.y + 1), [..path], resLeft); return resRight; } var res = GetNodesTraversedWitTimelineCount(grid, (current.x + 1, current.y), [..path], nodeCountVisited); return res; } private static Dictionary UpdateNodeVisitedCounts(Coordinate current, HashSet path, Dictionary nodeCountVisited) { var addAmount = nodeCountVisited.GetValueOrDefault(current, 1); foreach (var node in path) { nodeCountVisited[node] += addAmount; } return nodeCountVisited; } private long[] GetNodesTraversedWitTimelineCount(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]; } }