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

143 lines
6.5 KiB
C#

using AdventOfCode.Core.Shared.IO;
namespace AdventOfCode.Solutions._2023
{
public class Day16 : IChallange
{
public int Year => 2023;
public int Day => 16;
private readonly IInputReader _inputReader;
public Day16(IInputReader inputReader)
{
_inputReader = inputReader;
_inputReader.SetInput(this);
}
public async Task<string> GetSolutionPart1()
{
Grid<Point> grid = await _inputReader.ReadToGrid<Point>();
Point? point = grid.TryGetNode(0, 0);
ISet<Point> set = Move(grid, new HashSet<Point>(), new HashSet<Point>(), point, Direction.Right);
return set.Count.ToString();
}
public async Task<string> GetSolutionPart2()
{
Grid<Point> grid = await _inputReader.ReadToGrid<Point>();
int columnMax = grid.GetColumn(0).Select(p => Move(grid, new HashSet<Point>(), new HashSet<Point>(), p, Direction.Down).Count).Max();
int rowMax = grid.GetRow(0).Select(p => Move(grid, new HashSet<Point>(), new HashSet<Point>(), p, Direction.Right).Count).Max();
return Math.Max(columnMax, rowMax).ToString();
}
private static ISet<Point> Move(Grid<Point> grid, ISet<Point> energized, ISet<Point> splittersHit, Point? currentLocation, Direction direction)
{
if (currentLocation == null)
return energized;
if ((currentLocation.Value == '-' || currentLocation.Value == '|') && !splittersHit.Add(currentLocation))
return energized;
energized.Add(currentLocation);
(long X, long Y, Direction NewDirection) newPosition = (currentLocation.X, currentLocation.Y, direction);
switch (currentLocation.Value)
{
case '.':
newPosition = MoveStraight(currentLocation, direction);
Point? newPoint = grid.TryGetNode(newPosition.X, newPosition.Y);
while(newPoint != null && newPoint.Value == '.')
{
energized.Add(newPoint);
newPosition = MoveStraight(newPoint, direction);
newPoint = grid.TryGetNode(newPosition.X, newPosition.Y);
}
return Move(grid, energized, splittersHit, grid.TryGetNode(newPosition.X, newPosition.Y), newPosition.NewDirection);
case '\\':
if (direction == Direction.Down || direction == Direction.Up)
newPosition = MoveLeft(currentLocation, direction);
else if (direction == Direction.Right ||direction == Direction.Left)
newPosition = MoveRight(currentLocation, direction);
return Move(grid, energized, splittersHit, grid.TryGetNode(newPosition.X, newPosition.Y), newPosition.NewDirection);
case '/':
if (direction == Direction.Down || direction == Direction.Up)
newPosition = MoveRight(currentLocation, direction);
else if (direction == Direction.Right || direction == Direction.Left)
newPosition = MoveLeft(currentLocation, direction);
return Move(grid, energized, splittersHit, grid.TryGetNode(newPosition.X, newPosition.Y), newPosition.NewDirection);
case '|':
if (direction == Direction.Up || direction == Direction.Down)
newPosition = MoveStraight(currentLocation, direction);
else
{
newPosition = MoveLeft(currentLocation, direction);
energized = Move(grid, energized, splittersHit, grid.TryGetNode(newPosition.X, newPosition.Y), newPosition.NewDirection);
newPosition = MoveRight(currentLocation, direction);
}
return Move(grid, energized, splittersHit, grid.TryGetNode(newPosition.X, newPosition.Y), newPosition.NewDirection);
case '-':
if (direction == Direction.Right || direction == Direction.Left)
newPosition = MoveStraight(currentLocation, direction);
else
{
newPosition = MoveLeft(currentLocation, direction);
energized = Move(grid, energized, splittersHit, grid.TryGetNode(newPosition.X, newPosition.Y), newPosition.NewDirection);
newPosition = MoveRight(currentLocation, direction);
}
return Move(grid, energized, splittersHit, grid.TryGetNode(newPosition.X, newPosition.Y), newPosition.NewDirection);
}
return energized;
}
private enum Direction
{
Up,
Down,
Left,
Right
}
private static (long X, long Y, Direction NewDirection) MoveStraight(Point from, Direction direction)
{
return direction switch
{
Direction.Up => (from.X, from.Y - 1, direction),
Direction.Down => (from.X, from.Y + 1, direction),
Direction.Left => (from.X - 1, from.Y, direction),
Direction.Right => (from.X + 1, from.Y, direction),
_ => (from.X, from.Y, direction),
};
}
private static (long X, long Y, Direction NewDirection) MoveLeft(Point from, Direction direction)
{
return direction switch
{
Direction.Up => (from.X - 1, from.Y, Direction.Left),
Direction.Down => (from.X + 1, from.Y, Direction.Right),
Direction.Left => (from.X, from.Y + 1, Direction.Down),
Direction.Right => (from.X, from.Y - 1, Direction.Up),
_ => (from.X, from.Y, direction),
};
}
private static (long X, long Y, Direction NewDirection) MoveRight(Point from, Direction direction)
{
return direction switch
{
Direction.Up => (from.X + 1, from.Y, Direction.Right),
Direction.Down => (from.X - 1, from.Y, Direction.Left),
Direction.Left => (from.X, from.Y - 1, Direction.Up),
Direction.Right => (from.X, from.Y + 1, Direction.Down),
_ => (from.X, from.Y, direction),
};
}
}
}