using System; using System.Collections.Generic; using System.Data.Common; using System.IO; using System.Linq; using AdvenOfCode.Contracts; using Coordinate = (long x, long y); using CoordinatePair = (long minX, long minY, long maxX, long maxY); namespace AoC_2025; public class Day09 : IPuzzleSolver { private Coordinate[] ParsePuzzleInput(string path) { var puzzleInput = File.ReadAllLines(path) .Where(line => !string.IsNullOrWhiteSpace(line)) .Select(line => line.Split(',', StringSplitOptions.RemoveEmptyEntries).Select(str => long.Parse(str)).ToArray()) .Select(numbers => (numbers[0], numbers[1])) .ToArray(); return puzzleInput; } public long SolvePart1(string pathToPuzzleInput) { var redTiles = ParsePuzzleInput(pathToPuzzleInput); var possibleRectangles = GetAllPossibleRectanglesAsPairs(redTiles); var areas = GetOrderedAreas(possibleRectangles); return areas.First(); } public long SolvePart2(string pathToPuzzleInput) { var redTiles = ParsePuzzleInput(pathToPuzzleInput); var borders = GetBordersAsPairs(redTiles); var possibleRectangles = GetAllPossibleRectanglesAsPairs(redTiles); var containedRectangles = GetRectanglesContainedInBorders(possibleRectangles, borders); var areas = GetOrderedAreas(containedRectangles); return areas.First(); } private IOrderedEnumerable GetOrderedAreas(IEnumerable containedRectangles) { return containedRectangles .Select(rectangle => GetArea((rectangle.maxX, rectangle.maxY), (rectangle.minX, rectangle.minY))) .OrderDescending(); } private IEnumerable GetRectanglesContainedInBorders(IEnumerable possibleRectangles, CoordinatePair[] borders) { return possibleRectangles .Where(rectangle => IsRectangleInsideBorders(borders, rectangle)); } private IEnumerable GetAllPossibleRectanglesAsPairs(Coordinate[] redTiles) { return Combinations(redTiles).Select(x => AsPair(x.a, x.b)); } private CoordinatePair[] GetBordersAsPairs(Coordinate[] redTiles) { return GetBorders(redTiles).Select(x => AsPair(x.a, x.b)).ToArray(); } private bool IsRectangleInsideBorders(CoordinatePair[] borders, CoordinatePair rectangle) { return !borders.Any(border => RectangleCrossesBorder(rectangle, border)); } private CoordinatePair AsPair(Coordinate a, Coordinate b) { return (Math.Min(a.x, b.x), Math.Min(a.y, b.y), Math.Max(a.x, b.x), Math.Max(a.y, b.y)); } private bool RectangleCrossesBorder(CoordinatePair rectangle, CoordinatePair borderSegment) { return rectangle.minX < borderSegment.maxX && rectangle.minY < borderSegment.maxY && rectangle.maxX > borderSegment.minX && rectangle.maxY > borderSegment.minY; } private long GetArea(Coordinate tileA, Coordinate tileB) { return (Math.Abs(tileA.x - tileB.x) + 1) * (Math.Abs(tileA.y - tileB.y) + 1); } private IEnumerable<(TValue a, TValue b)> Combinations(IEnumerable values) { var enumeratedValues = values.Index().ToArray(); var pairs = from a in enumeratedValues from b in enumeratedValues where a.Index < b.Index select (a.Item, b.Item); return pairs; } private IEnumerable<(Coordinate a, Coordinate b)> GetBorders(Coordinate[] tiles) { return tiles.Zip([..tiles[1..], tiles[0]], (a, b) => (a, b)); } }