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 GetSolutionPart1() { Grid grid = await _inputReader.ReadToGrid(); Point? point = grid.TryGetNode(0, 0); ISet set = Move(grid, new HashSet(), new HashSet(), point, Direction.Right); return set.Count.ToString(); } public async Task GetSolutionPart2() { Grid grid = await _inputReader.ReadToGrid(); int columnMax = grid.GetColumn(0).Select(p => Move(grid, new HashSet(), new HashSet(), p, Direction.Down).Count).Max(); int rowMax = grid.GetRow(0).Select(p => Move(grid, new HashSet(), new HashSet(), p, Direction.Right).Count).Max(); return Math.Max(columnMax, rowMax).ToString(); } private static ISet Move(Grid grid, ISet energized, ISet 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), }; } } }