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(); 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, ISubtractionOperators, IMultiplyOperators { 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); } }