Files
AdventOfCode/Days/Day12.cs
2025-01-24 10:19:12 +01:00

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);
}
}