155 lines
4.0 KiB
C#
155 lines
4.0 KiB
C#
using System.Collections.Frozen;
|
|
using System.Numerics;
|
|
using Spectre.Console;
|
|
|
|
namespace AdventOfCode.Days;
|
|
|
|
public class Day12 : Day
|
|
{
|
|
public override int Number => 12;
|
|
public override string Name => "Garden Groups";
|
|
|
|
private const int GridSize = 140;
|
|
|
|
public override void RunPart1(bool display = true)
|
|
{
|
|
var areas = ParseAreas();
|
|
|
|
var visited = new HashSet<Point>();
|
|
var totalPrice = 0;
|
|
|
|
var currentArea = 0;
|
|
var currentPerimeter = 0;
|
|
|
|
for (var y = 0; y < GridSize; y++)
|
|
{
|
|
for (var x = 0; x < GridSize; x++)
|
|
{
|
|
// Skip already visited points
|
|
if (visited.Contains(new Point(x, y)))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var id = areas[x, y];
|
|
|
|
ComputeAreaPrice(new Point(x, y), id, ref currentArea, ref currentPerimeter);
|
|
|
|
// Add price of fencing this area
|
|
totalPrice += currentArea * currentPerimeter;
|
|
|
|
currentArea = 0;
|
|
currentPerimeter = 0;
|
|
}
|
|
}
|
|
|
|
if (display)
|
|
{
|
|
AnsiConsole.MarkupLine($"[green]Total pricing: [yellow]{totalPrice}[/][/]");
|
|
}
|
|
|
|
return;
|
|
|
|
void ComputeAreaPrice(Point position, byte id, ref int area, ref int perimeter)
|
|
{
|
|
if (!visited.Add(position))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Update area and perimeter
|
|
area++;
|
|
perimeter += 4;
|
|
|
|
var left = position with { X = position.X - 1 };
|
|
var right = position with { X = position.X + 1 };
|
|
var up = position with { Y = position.Y - 1 };
|
|
var down = position with { Y = position.Y + 1 };
|
|
|
|
if (left is { X: >= 0 and < GridSize } && areas[left.X, left.Y] == id)
|
|
{
|
|
perimeter--;
|
|
|
|
ComputeAreaPrice(left, id, ref area, ref perimeter);
|
|
}
|
|
|
|
if (right is { X: >= 0 and < GridSize } && areas[right.X, right.Y] == id)
|
|
{
|
|
perimeter--;
|
|
|
|
ComputeAreaPrice(right, id, ref area, ref perimeter);
|
|
}
|
|
|
|
if (up is { Y: >= 0 and < GridSize } && areas[up.X, up.Y] == id)
|
|
{
|
|
perimeter--;
|
|
|
|
ComputeAreaPrice(up, id, ref area, ref perimeter);
|
|
}
|
|
|
|
if (down is { Y: >= 0 and < GridSize } && areas[down.X, down.Y] == id)
|
|
{
|
|
perimeter--;
|
|
|
|
ComputeAreaPrice(down, id, ref area, ref perimeter);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void RunPart2(bool display = true)
|
|
{
|
|
|
|
}
|
|
|
|
private byte[,] ParseAreas()
|
|
{
|
|
var areas = new byte[GridSize, GridSize];
|
|
|
|
int y = 0;
|
|
|
|
foreach (var line in Input.AsSpan().EnumerateLines())
|
|
{
|
|
int x = 0;
|
|
|
|
foreach (var area in line)
|
|
{
|
|
areas[x, y] = (byte)(area - 'A');
|
|
|
|
x++;
|
|
}
|
|
|
|
y++;
|
|
}
|
|
|
|
return areas;
|
|
}
|
|
|
|
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);
|
|
}
|
|
} |