111 lines
3.4 KiB
C#
111 lines
3.4 KiB
C#
namespace ReindeerMaze;
|
|
|
|
static class PuzzleSolver
|
|
{
|
|
public static int Solve(string[] input, bool isPart2 = false)
|
|
{
|
|
List<Direction> directions = [
|
|
Direction.Right,
|
|
Direction.Down,
|
|
Direction.Left,
|
|
Direction.Up,
|
|
];
|
|
|
|
var rows = input.Length;
|
|
var columns = input[0].Length;
|
|
|
|
var startPosition = new Position(-1, -1);
|
|
var endPosition = new Position(-1, -1);
|
|
|
|
for (var row = 0; row < rows; row++)
|
|
{
|
|
for (var column = 0; column < columns; column++)
|
|
{
|
|
var currentValue = input[row][column];
|
|
|
|
switch (currentValue)
|
|
{
|
|
case 'S':
|
|
startPosition = new(column, row);
|
|
break;
|
|
case 'E':
|
|
endPosition = new(column, row);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
var queue = new PriorityQueue<MazePath, int>();
|
|
var visitedTiles = new HashSet<Tile>();
|
|
var initialScore = 0;
|
|
var initialDirection = 0;
|
|
var startTile = new Tile(startPosition, initialDirection);
|
|
var bestScore = int.MaxValue;
|
|
var bestPath = new MazePath([startTile], initialScore);
|
|
HashSet<Position> bestSeats = [startPosition];
|
|
|
|
queue.Enqueue(bestPath, initialScore);
|
|
|
|
while (queue.Count is not 0)
|
|
{
|
|
var path = queue.Dequeue();
|
|
var currentTile = path.CurrentTile;
|
|
var currentScore = path.Score;
|
|
|
|
if (currentScore > bestScore)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (currentTile.Position == endPosition)
|
|
{
|
|
bestScore = currentScore;
|
|
bestSeats.UnionWith(path.Tiles.Select(t => t.Position));
|
|
continue;
|
|
}
|
|
|
|
visitedTiles.Add(currentTile);
|
|
|
|
var currentDirection = directions[currentTile.DirectionIndex];
|
|
var nextPosition = currentTile.Position.GetNextPosition(currentDirection);
|
|
|
|
if (
|
|
nextPosition.X >= 0 &&
|
|
nextPosition.X < columns &&
|
|
nextPosition.Y >= 0 &&
|
|
nextPosition.Y < rows &&
|
|
input[nextPosition.Y][nextPosition.X] != '#'
|
|
)
|
|
{
|
|
var newScoreAfterMovingForward = currentScore + 1;
|
|
var nextTileAfterMovingForward = currentTile with { Position = nextPosition };
|
|
var nextPath = new MazePath([..path.Tiles, nextTileAfterMovingForward], newScoreAfterMovingForward);
|
|
|
|
if (visitedTiles.Contains(nextTileAfterMovingForward) is false)
|
|
{
|
|
queue.Enqueue(nextPath, newScoreAfterMovingForward);
|
|
}
|
|
}
|
|
|
|
var newScoreAfterTurning = currentScore + 1000;
|
|
|
|
var directionAfterClockWiseTurn = (currentTile.DirectionIndex + 1) % directions.Count;
|
|
var nextTileAfterClockWiseTurn = currentTile with { DirectionIndex = directionAfterClockWiseTurn };
|
|
|
|
if (visitedTiles.Contains(nextTileAfterClockWiseTurn) is false)
|
|
{
|
|
queue.Enqueue(new([..path.Tiles, nextTileAfterClockWiseTurn], newScoreAfterTurning), newScoreAfterTurning);
|
|
}
|
|
|
|
var directionAfterCounterClockWiseTurn = (currentTile.DirectionIndex + 3) % directions.Count;
|
|
var nextTileAfterCounterClockWiseTurn = currentTile with { DirectionIndex = directionAfterCounterClockWiseTurn };
|
|
|
|
if (visitedTiles.Contains(nextTileAfterCounterClockWiseTurn) is false)
|
|
{
|
|
queue.Enqueue(new([..path.Tiles, nextTileAfterCounterClockWiseTurn], newScoreAfterTurning), newScoreAfterTurning);
|
|
}
|
|
}
|
|
|
|
return isPart2 ? bestSeats.Count : bestScore;
|
|
}
|
|
} |