using AdventOfCode.Core.Shared.IO; namespace AdventOfCode.Solutions._2023 { public class Day10 : IChallange { public int Year => 2023; public int Day => 10; private readonly IInputReader _inputReader; public Day10(IInputReader inputReader) { _inputReader = inputReader; _inputReader.SetInput(this); } public async Task GetSolutionPart1() { Grid grid = await _inputReader.ReadToGrid(); return GetLoop(grid).Max(p => p.Steps).ToString(); } public async Task GetSolutionPart2() { Grid grid = await _inputReader.ReadToGrid(); _ = GetLoop(grid); // marks all the pipes from the main loop int inside = 0; for (int rowIndex = 0; rowIndex < grid.Rows; rowIndex++) { char prevSegment = '.'; int pipesCrossed = 0; for (int columnIndex = 0; columnIndex < grid.Columns; columnIndex++) { // filter the special cases that need checking Pipe value = grid.GetNode(columnIndex, rowIndex); if (value.Steps >= 0) // this is in the main loop { if (value.Value == '-') // never crosses, also to not update prev continue; if ((prevSegment == 'L' && value.Value == '7') // this is L7 meaning that there is no crossing || prevSegment == 'F' && value.Value == 'J') // this is FJ meaning that there is no crossing { prevSegment = value.Value; continue; } prevSegment = value.Value; pipesCrossed++; continue; } if (pipesCrossed % 2 == 1) // inside the main loop inside++; } } return inside.ToString(); } private List GetLoop(Grid grid) { Pipe startPipe = grid.FindWithValue('S').First(); startPipe.Steps = 0; Pipe[] lineToWalk = grid.GetNeighbors(startPipe, false) .Where(n => n.Value != '.') .Where(n => n.GetNeighbors().Any(np => np.X == startPipe.X && np.Y == startPipe.Y)) .ToArray(); for (int i = 0; i < lineToWalk.Length; i++) lineToWalk[i].From = startPipe; List mainLoop = [startPipe]; int steps = 1; while (true) { List nextLoop = []; foreach (Pipe line in lineToWalk) { line.Steps = steps; // update the pipe in the grid with the steps grid.UpdateNode(line); mainLoop.Add(line); // get the pipe location Pipe next = line.GetNextPipe(); // get the actual pipe from the grid next = grid.GetNode(next.X, next.Y); if (next.Steps != -1) { return mainLoop; } next.From = line; nextLoop.Add(next); } lineToWalk = [.. nextLoop]; steps++; } } public class Pipe : Point { public Pipe? From { get; set; } = null; public int Steps { get; set; } = -1; public Pipe GetNextPipe() { if (From == null) throw new ArgumentException("From not set"); var neighbors = GetNeighbors(); return neighbors.First(n => n.X != From.X || n.Y != From.Y); } public IEnumerable GetNeighbors() { switch (Value) { case '|': yield return GetNorth(); yield return GetSouth(); yield break; case '-': yield return GetWest(); yield return GetEast(); yield break; case 'L': yield return GetNorth(); yield return GetEast(); yield break; case 'J': yield return GetNorth(); yield return GetWest(); yield break; case '7': yield return GetSouth(); yield return GetWest(); yield break; case 'F': yield return GetSouth(); yield return GetEast(); yield break; } } private Pipe GetNorth() => new() { X = this.X, Y = this.Y - 1 }; private Pipe GetSouth() => new() { X = this.X, Y = this.Y + 1 }; private Pipe GetWest() => new() { X = this.X - 1, Y = this.Y }; private Pipe GetEast() => new() { X = this.X + 1, Y = this.Y }; } } }