Files
advent-of-code-2024/06/GuardGallivant/Map.cs
T

209 lines
5.0 KiB
C#
Raw Normal View History

2024-12-07 01:28:15 -06:00
namespace GuardGallivant;
class Map
{
private static readonly Dictionary<Direction, Move> MovementDictionary = new()
{
{ Direction.Up, Move.Up },
{ Direction.Down, Move.Down },
{ Direction.Left, Move.Left },
{ Direction.Right, Move.Right },
};
private static readonly Direction[] Directions = MovementDictionary.Keys.ToArray();
private readonly string[] _input;
public Map(string[] input)
{
_input = input;
}
public int IdentifyNumberOfPlacementsForNewObstruction()
{
var count = 0;
var guardPathPositions = GetDistinctGuardPositions();
foreach (var (columnIndex, rowIndex) in guardPathPositions)
2024-12-07 01:28:15 -06:00
{
var currentCharacter = _input[rowIndex][columnIndex];
if (IsGuard(currentCharacter) || IsBlocked(currentCharacter))
{
continue;
2024-12-07 01:28:15 -06:00
}
var mapWithNewObstruction = _input.ToArray();
var row = mapWithNewObstruction[rowIndex].ToCharArray();
row[columnIndex] = '#';
mapWithNewObstruction[rowIndex] = new string(row);
var hasLoop = new Map(mapWithNewObstruction).DetectLoop();
if (hasLoop)
{
count++;
}
}
2024-12-07 01:28:15 -06:00
return count;
}
private bool DetectLoop()
{
var originalGuardPosition = GetGuardPosition();
var currentGuardPosition = originalGuardPosition;
var blockedPositions = new List<GuardPosition>();
while (true)
{
var nextMove = MovementDictionary[currentGuardPosition.Direction];
var nextGuardPosition = currentGuardPosition with
{
RowIndex = currentGuardPosition.RowIndex + nextMove.YOffset,
ColumnIndex = currentGuardPosition.ColumnIndex + nextMove.XOffset,
};
if (IsOffGrid(nextGuardPosition))
{
return false;
}
if (IsBlocked(nextGuardPosition))
{
if (blockedPositions.Contains(nextGuardPosition))
{
return true;
}
blockedPositions.Add(nextGuardPosition);
var newDirection = TurnRight(currentGuardPosition);
currentGuardPosition = currentGuardPosition with { Direction = newDirection };
continue;
}
currentGuardPosition = nextGuardPosition;
}
}
public int PredictDistinctPositionsCount() => GetDistinctGuardPositions().Count;
private HashSet<(int x, int y)> GetDistinctGuardPositions()
2024-12-07 01:28:15 -06:00
{
var currentGuardPosition = GetGuardPosition();
2024-12-07 01:28:15 -06:00
var uniquePositions = new HashSet<(int x, int y)>()
{
(currentGuardPosition.ColumnIndex, currentGuardPosition.RowIndex),
};
while (true)
{
var nextMove = MovementDictionary[currentGuardPosition.Direction];
var nextGuardPosition = currentGuardPosition with
{
RowIndex = currentGuardPosition.RowIndex + nextMove.YOffset,
ColumnIndex = currentGuardPosition.ColumnIndex + nextMove.XOffset,
};
if (IsOffGrid(nextGuardPosition))
{
break;
}
if (IsBlocked(nextGuardPosition))
{
var newDirection = TurnRight(currentGuardPosition);
currentGuardPosition = currentGuardPosition with { Direction = newDirection };
continue;
}
currentGuardPosition = nextGuardPosition;
uniquePositions.Add((currentGuardPosition.ColumnIndex, currentGuardPosition.RowIndex));
}
return uniquePositions;
2024-12-07 01:28:15 -06:00
}
private GuardPosition GetGuardPosition()
{
var guardPosition = new GuardPosition(-1, -1, new Direction('X'));
WalkMap((rowIndex, columnIndex) =>
{
var possibleGuard = new Direction(_input[rowIndex][columnIndex]);
if (Directions.Contains(possibleGuard) is false)
{
return;
}
guardPosition = new GuardPosition(rowIndex, columnIndex, possibleGuard);
});
return guardPosition;
}
private void WalkMap(Action<int, int> callback)
{
for (var rowIndex = 0; rowIndex < _input.Length; rowIndex++)
{
var row = _input[rowIndex];
for (var columnIndex = 0; columnIndex < row.Length; columnIndex++)
{
callback(rowIndex, columnIndex);
}
}
}
private bool IsOffGrid(GuardPosition position)
{
return position.RowIndex < 0 ||
position.RowIndex > _input.Length - 1 ||
position.ColumnIndex < 0 ||
position.ColumnIndex > _input[0].Length - 1;
}
private bool IsBlocked(GuardPosition position)
{
return _input[position.RowIndex][position.ColumnIndex] is '#';
}
private bool IsBlocked(char character)
{
return character is '#';
}
private bool IsGuard(char currentCharacter)
{
return Directions.Contains(new Direction(currentCharacter));
}
private static Direction TurnRight(GuardPosition guardPosition)
{
if (guardPosition.Direction == Direction.Up)
{
return Direction.Right;
}
if (guardPosition.Direction == Direction.Right)
{
return Direction.Down;
}
if (guardPosition.Direction == Direction.Down)
{
return Direction.Left;
}
return Direction.Up;
}
2024-12-07 01:49:28 -06:00
}