AdventOfCode/AdventOfCode.Solutions/2023/Day 10/Day10.cs
2024-12-01 10:17:24 +01:00

162 lines
5.4 KiB
C#

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<string> GetSolutionPart1()
{
Grid<Pipe> grid = await _inputReader.ReadToGrid<Pipe>();
return GetLoop(grid).Max(p => p.Steps).ToString();
}
public async Task<string> GetSolutionPart2()
{
Grid<Pipe> grid = await _inputReader.ReadToGrid<Pipe>();
_ = 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<Pipe> GetLoop(Grid<Pipe> 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<Pipe> mainLoop = [startPipe];
int steps = 1;
while (true)
{
List<Pipe> 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<Pipe> 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 };
}
}
}