Add day 15
This commit is contained in:
193
Days/Day15.cs
Normal file
193
Days/Day15.cs
Normal file
@@ -0,0 +1,193 @@
|
||||
using System.Collections.Frozen;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
using Spectre.Console;
|
||||
|
||||
namespace AdventOfCode.Days;
|
||||
|
||||
public class Day15 : Day
|
||||
{
|
||||
public override int Number => 15;
|
||||
public override string Name => "Warehouse Woes";
|
||||
|
||||
private const int Size = 50;
|
||||
|
||||
private const char Wall = '#';
|
||||
private const char Box = 'O';
|
||||
private const char Empty = '.';
|
||||
|
||||
private const char InstructionLeft = '<';
|
||||
private const char InstructionRight = '>';
|
||||
private const char InstructionUp = '^';
|
||||
private const char InstructionDown = 'v';
|
||||
|
||||
public override void RunPart1(bool display = true)
|
||||
{
|
||||
var (map, position, instructions) = ParseMap();
|
||||
|
||||
foreach (var instruction in instructions)
|
||||
{
|
||||
var direction = instruction switch
|
||||
{
|
||||
InstructionLeft => new Point(-1, 0),
|
||||
InstructionRight => new Point(1, 0),
|
||||
InstructionUp => new Point(0, -1),
|
||||
InstructionDown => new Point(0, 1),
|
||||
_ => throw new ArgumentException($"Invalid instruction: {instruction}")
|
||||
};
|
||||
|
||||
var destination = position + direction;
|
||||
|
||||
// Destination is free, just move
|
||||
if (map[destination.X, destination.Y] is not (Wall or Box))
|
||||
{
|
||||
position = destination;
|
||||
}
|
||||
// Destination is a box, check if there is a free space further up and move accordingly
|
||||
else if (map[destination.X, destination.Y] is Box)
|
||||
{
|
||||
var pushTarget = destination + direction;
|
||||
|
||||
while (map[pushTarget.X, pushTarget.Y] is Box)
|
||||
{
|
||||
pushTarget += direction;
|
||||
}
|
||||
|
||||
// Cannot move anything since there is a wall
|
||||
if (map[pushTarget.X, pushTarget.Y] is Wall)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Move robot and boxes (only need to move first and last box of a chain)
|
||||
position = destination;
|
||||
|
||||
map[destination.X, destination.Y] = Empty;
|
||||
map[pushTarget.X, pushTarget.Y] = Box;
|
||||
}
|
||||
// Else destination is a wall, do nothing
|
||||
}
|
||||
|
||||
var coordinatesSum = 0;
|
||||
|
||||
// Count gps coordinates
|
||||
for (var x = 0; x < Size; x++)
|
||||
{
|
||||
for (var y = 0; y < Size; y++)
|
||||
{
|
||||
if (map[x, y] is Box)
|
||||
{
|
||||
coordinatesSum += 100 * y + x;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (display)
|
||||
{
|
||||
AnsiConsole.MarkupLine($"[green]Sum of boxes GPS coordinates: [yellow]{coordinatesSum}[/][/]");
|
||||
}
|
||||
}
|
||||
|
||||
private static void DisplayGrid(char[,] map)
|
||||
{
|
||||
for (var y = 0; y < Size; y++)
|
||||
{
|
||||
for (var x = 0; x < Size; x++)
|
||||
{
|
||||
AnsiConsole.Write(map[x, y]);
|
||||
}
|
||||
|
||||
AnsiConsole.WriteLine();
|
||||
}
|
||||
|
||||
AnsiConsole.WriteLine();
|
||||
}
|
||||
|
||||
public override void RunPart2(bool display = true)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private (char[,] Map, Point Start, List<char> Instructions) ParseMap()
|
||||
{
|
||||
var readingMap = true;
|
||||
|
||||
var map = new char[Size, Size];
|
||||
|
||||
Point start = default;
|
||||
|
||||
var instructions = new List<char>();
|
||||
|
||||
var y = 0;
|
||||
foreach (var line in Input.AsSpan().EnumerateLines())
|
||||
{
|
||||
if (line.IsWhiteSpace())
|
||||
{
|
||||
readingMap = false;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (readingMap)
|
||||
{
|
||||
var x = 0;
|
||||
foreach (var symbol in line)
|
||||
{
|
||||
map[x, y] = Empty;
|
||||
|
||||
if (symbol is Wall or Box)
|
||||
{
|
||||
map[x, y] = symbol;
|
||||
}
|
||||
else if (symbol is '@')
|
||||
{
|
||||
start = new Point(x, y);
|
||||
}
|
||||
|
||||
x++;
|
||||
}
|
||||
|
||||
y++;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var instruction in line)
|
||||
{
|
||||
instructions.Add(instruction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (map, start, instructions);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user