239 lines
6.2 KiB
C#
239 lines
6.2 KiB
C#
void Main1()
|
|
{
|
|
(var map, var pos) = LoadMap(Path.Join("..", "..", "06a.txt"));
|
|
Guard guard = new(pos, Direction.North);
|
|
HashSet<(int,int)> visited = new();
|
|
while (map.InBounds(guard.position))
|
|
{
|
|
var next = Next(guard);
|
|
if (map.Check(next.position))
|
|
{
|
|
guard = new(guard.position, guard.direction.Turn());
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
visited.Add(guard.position);
|
|
guard = next;
|
|
}
|
|
}
|
|
Console.WriteLine(visited.Count());
|
|
}
|
|
|
|
void Main2()
|
|
{
|
|
(var map, var pos) = LoadMap(Path.Join("..", "..", "06a.txt"));
|
|
Guard guard = new(pos, Direction.North);
|
|
// for (int i = 0; i < 4; i++)
|
|
// {
|
|
// foreach (var obs in map.Obstacles)
|
|
// {
|
|
// var row = map.GetRow(obs.Item1 + 1).Where(c => c > obs.Item2);
|
|
// foreach (var candidate in row)
|
|
// {
|
|
// var col = map.GetColumn(candidate - 1).Where(r => r > candidate);
|
|
// foreach (var third in col)
|
|
// {
|
|
// var idea = (third - 1, obs.Item2 - 1);
|
|
// if (!map.Check(idea))
|
|
// map.Ideas.Add(idea);
|
|
// }
|
|
// }
|
|
// }
|
|
// map = map.Rotated();
|
|
// }
|
|
// Console.WriteLine($"Ideas {map.Ideas.Count()}");
|
|
int count = 0;
|
|
// foreach (var idea in map.Ideas)
|
|
// {
|
|
// Guard guard = new(pos, Direction.North);
|
|
// // the 5th time the guard hits the obstacle, he must have hit twice from the same side
|
|
// int hits = 0;
|
|
// while (map.InBounds(guard.position))
|
|
// {
|
|
// var next = Next(guard);
|
|
// if (next.position == idea)
|
|
// {
|
|
// hits++;
|
|
// if (hits >= 5)
|
|
// {
|
|
// count++;
|
|
// break;
|
|
// }
|
|
// guard = new(guard.position, guard.direction.Turn());
|
|
// }
|
|
// else if (map.Check(next.position))
|
|
// {
|
|
// guard = new(guard.position, guard.direction.Turn());
|
|
// }
|
|
// else
|
|
// {
|
|
// guard = next;
|
|
// }
|
|
// }
|
|
// }
|
|
HashSet<(int,int)> visited = new();
|
|
int ideaIndex = 0;
|
|
while (map.InBounds(guard.position))
|
|
{
|
|
ideaIndex++;
|
|
var next = Next(guard);
|
|
if (map.Check(next.position))
|
|
{
|
|
guard = new(guard.position, guard.direction.Turn());
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
visited.Add(guard.position);
|
|
if (!visited.Contains(next.position) && TestIdea(next.position, guard, map))
|
|
count++;
|
|
// Console.WriteLine($"Idea {ideaIndex}");
|
|
guard = next;
|
|
}
|
|
}
|
|
Console.WriteLine($"Solution {count}");
|
|
}
|
|
|
|
// Main1();
|
|
Main2();
|
|
|
|
(Map,(int,int)) LoadMap(string filename)
|
|
{
|
|
var lines = File.ReadAllLines(filename)
|
|
.Where(s => !string.IsNullOrWhiteSpace(s))
|
|
.ToList();
|
|
var guard = (-1,-1);
|
|
Map map = new();
|
|
for (int i = 0; i < lines.Count(); i++)
|
|
{
|
|
for (int j = 0; j < lines[i].Count(); j++)
|
|
{
|
|
if (lines[i][j] == '#')
|
|
map.Add((i, j));
|
|
else if (lines[i][j] == '^')
|
|
guard = (i, j);
|
|
}
|
|
}
|
|
map.XBound = lines[0].Count();
|
|
map.YBound = lines.Count();
|
|
return (map, guard);
|
|
}
|
|
|
|
bool TestIdea((int,int) idea, Guard guard, Map map)
|
|
{
|
|
HashSet<Guard> history = new();
|
|
while (map.InBounds(guard.position))
|
|
{
|
|
if (history.Contains(guard))
|
|
return true;
|
|
history.Add(guard);
|
|
var next = Next(guard);
|
|
if (map.Check(next.position) || next.position == idea)
|
|
{
|
|
guard = new(guard.position, guard.direction.Turn());
|
|
}
|
|
else
|
|
{
|
|
guard = next;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//next position IF NO OBSTACLE
|
|
Guard Next(Guard guard)
|
|
{
|
|
var pos = guard.position;
|
|
return new(guard.direction switch
|
|
{
|
|
Direction.North => (pos.Item1-1, pos.Item2),
|
|
Direction.East => (pos.Item1, pos.Item2+1),
|
|
Direction.South => (pos.Item1+1, pos.Item2),
|
|
Direction.West => (pos.Item1, pos.Item2-1),
|
|
_ => throw new Exception(),
|
|
}, guard.direction);
|
|
}
|
|
|
|
class Map
|
|
{
|
|
public HashSet<(int,int)> Obstacles = new();
|
|
//1 greater than largest value
|
|
public int XBound = 0;
|
|
public int YBound = 0;
|
|
public HashSet<(int,int)> Ideas = new();
|
|
public Map()
|
|
{
|
|
|
|
}
|
|
public void Add((int,int) obstacle)
|
|
{
|
|
Obstacles.Add(obstacle);
|
|
}
|
|
public bool Check((int,int) pos)
|
|
{
|
|
return Obstacles.Contains(pos);
|
|
}
|
|
public bool InBounds((int,int) pos)
|
|
{
|
|
return pos.Item1 >= 0 && pos.Item2 >= 0
|
|
&& pos.Item1 < XBound && pos.Item2 < YBound;
|
|
}
|
|
//get list of columns with an obstacle in this row
|
|
public List<int> GetRow(int row)
|
|
{
|
|
List<int> items = [];
|
|
foreach (var pos in Obstacles)
|
|
{
|
|
if (pos.Item1 == row)
|
|
items.Add(pos.Item2);
|
|
}
|
|
items.Sort();
|
|
return items;
|
|
}
|
|
//get list of rows with an obstacle in this column
|
|
public List<int> GetColumn(int column)
|
|
{
|
|
List<int> items = [];
|
|
foreach (var pos in Obstacles)
|
|
{
|
|
if (pos.Item2 == column)
|
|
items.Add(pos.Item1);
|
|
}
|
|
items.Sort();
|
|
return items;
|
|
}
|
|
//counterclockwise rotation
|
|
public Map Rotated()
|
|
{
|
|
(int,int) rotate((int,int) o) => (o.Item2, XBound - o.Item1);
|
|
Map newmap = new();
|
|
newmap.Obstacles = new(Obstacles.Select(rotate));
|
|
newmap.Ideas = new(Ideas.Select(rotate));
|
|
newmap.XBound = YBound;
|
|
newmap.YBound = XBound;
|
|
return newmap;
|
|
}
|
|
}
|
|
|
|
enum Direction
|
|
{
|
|
North,
|
|
East,
|
|
South,
|
|
West,
|
|
}
|
|
readonly record struct Guard((int,int) position, Direction direction);
|
|
|
|
static class Extensions
|
|
{
|
|
public static Direction Turn(this Direction direction)
|
|
{
|
|
return direction switch
|
|
{
|
|
Direction.West => Direction.North,
|
|
Direction d => d + 1,
|
|
};
|
|
}
|
|
}
|