Add day 18
This commit is contained in:
204
Days/Day18.cs
Normal file
204
Days/Day18.cs
Normal file
@@ -0,0 +1,204 @@
|
||||
using System.Numerics;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
using Spectre.Console;
|
||||
|
||||
namespace AdventOfCode.Days;
|
||||
|
||||
public class Day18 : Day
|
||||
{
|
||||
public override int Number => 18;
|
||||
public override string Name => "RAM Run";
|
||||
|
||||
private const int Size = 71;
|
||||
|
||||
private const char Corrupted = '#';
|
||||
private const char Empty = ' ';
|
||||
|
||||
public override void RunPart1(bool display = true)
|
||||
{
|
||||
var grid = ParseGrid(1024);
|
||||
|
||||
var visited = new Dictionary<Point, int>();
|
||||
var toVisit = new Queue<(Point Position, int Score)>();
|
||||
|
||||
var end = new Point(Size - 1, Size - 1);
|
||||
|
||||
var minimumScore = int.MaxValue;
|
||||
|
||||
toVisit.Enqueue((new Point(0, 0), 0));
|
||||
|
||||
while (toVisit.Count > 0)
|
||||
{
|
||||
var (position, score) = toVisit.Dequeue();
|
||||
|
||||
// Cannot go out of bounds
|
||||
if (position is { X: < 0 or >= Size } or { Y: < 0 or >= Size })
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Cannot go onto a corrupted space
|
||||
if (grid[position.X, position.Y] is Corrupted)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (visited.TryGetValue(position, out var savedScore) && savedScore <= score)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
visited[position] = score;
|
||||
|
||||
// End
|
||||
if (position == end)
|
||||
{
|
||||
if (score < minimumScore)
|
||||
{
|
||||
minimumScore = score;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
toVisit.Enqueue((position + (1, 0), score + 1));
|
||||
toVisit.Enqueue((position + (-1, 0), score + 1));
|
||||
toVisit.Enqueue((position + (0, 1), score + 1));
|
||||
toVisit.Enqueue((position + (0, -1), score + 1));
|
||||
}
|
||||
|
||||
if (display)
|
||||
{
|
||||
AnsiConsole.MarkupLine($"[green]Minimum number of steps to reach the exit: [yellow]{minimumScore}[/][/]");
|
||||
}
|
||||
}
|
||||
|
||||
public override void RunPart2(bool display = true)
|
||||
{
|
||||
(int X, int Y)[] bytesToFall = Input.ReadAllLines()
|
||||
.Select(line => line.Split(','))
|
||||
.Select(split => (int.Parse(split[0]), int.Parse(split[1])))
|
||||
.ToArray();
|
||||
|
||||
var nextByteIndex = 1024;
|
||||
var grid = ParseGrid(1024);
|
||||
|
||||
while (true)
|
||||
{
|
||||
var nextByte = bytesToFall[nextByteIndex];
|
||||
|
||||
grid[nextByte.X, nextByte.Y] = Corrupted;
|
||||
|
||||
if (!IsGridCompletable())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
nextByteIndex++;
|
||||
}
|
||||
|
||||
if (display)
|
||||
{
|
||||
AnsiConsole.MarkupLine($"[green]Grid will be blocked at byte n°{nextByteIndex} at position: [yellow]{bytesToFall[nextByteIndex]}[/][/]");
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
bool IsGridCompletable()
|
||||
{
|
||||
var visited = new HashSet<Point>();
|
||||
var toVisit = new Queue<Point>();
|
||||
|
||||
var end = new Point(Size - 1, Size - 1);
|
||||
|
||||
toVisit.Enqueue(new Point(0, 0));
|
||||
|
||||
while (toVisit.Count > 0)
|
||||
{
|
||||
var position = toVisit.Dequeue();
|
||||
|
||||
// Cannot go out of bounds
|
||||
if (position is { X: < 0 or >= Size } or { Y: < 0 or >= Size })
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Cannot go onto a corrupted space
|
||||
if (grid[position.X, position.Y] is Corrupted)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!visited.Add(position))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// End
|
||||
if (position == end)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
toVisit.Enqueue(position + (1, 0));
|
||||
toVisit.Enqueue(position + (-1, 0));
|
||||
toVisit.Enqueue(position + (0, 1));
|
||||
toVisit.Enqueue(position + (0, -1));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private char[,] ParseGrid(int limit)
|
||||
{
|
||||
var grid = new char[Size, Size];
|
||||
|
||||
var counter = 0;
|
||||
foreach (var line in Input.AsSpan().EnumerateLines())
|
||||
{
|
||||
if (counter >= limit)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
var x = int.Parse(line[..line.IndexOf(',')]);
|
||||
var y = int.Parse(line[(line.IndexOf(',') + 1)..]);
|
||||
|
||||
grid[x, y] = Corrupted;
|
||||
|
||||
counter++;
|
||||
}
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
private readonly record struct Point(int X, int Y)
|
||||
: IAdditionOperators<Point, Point, Point>,
|
||||
ISubtractionOperators<Point, Point, Point>,
|
||||
IMultiplyOperators<Point, int, Point>
|
||||
{
|
||||
public static Point operator +(Point left, Point right)
|
||||
{
|
||||
return new Point(left.X + right.X, left.Y + right.Y);
|
||||
}
|
||||
|
||||
public static Point operator -(Point left, Point right)
|
||||
{
|
||||
return new Point(left.X - right.X, left.Y - right.Y);
|
||||
}
|
||||
|
||||
public static Point operator *(Point left, int right)
|
||||
{
|
||||
return new Point(left.X * right, left.Y * right);
|
||||
}
|
||||
|
||||
public static Point operator *(int left, Point right)
|
||||
{
|
||||
return new Point(right.X * left, right.Y * left);
|
||||
}
|
||||
|
||||
public static implicit operator Point((int X, int Y) point)
|
||||
=> new(point.X, point.Y);
|
||||
}
|
||||
}
|
||||
3450
Inputs/Day18.txt
Normal file
3450
Inputs/Day18.txt
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user