AdventOfCode/AoC_2025/Day09.cs

87 lines
3.3 KiB
C#

using AdvenOfCode.Contracts;
using AdventOfCode.Extensions;
using AdventOfCode.HelperClasses;
using CoordinatePair = (long minX, long minY, long maxX, long maxY);
namespace AoC_2025;
public class Day09 : IPuzzleSolver<long>
{
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 => new Coordinate(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<long> GetOrderedAreas(IEnumerable<CoordinatePair> containedRectangles)
{
return containedRectangles
.Select(rectangle => GetArea(new Coordinate(rectangle.maxX, rectangle.maxY), new Coordinate(rectangle.minX, rectangle.minY)))
.OrderDescending();
}
private IEnumerable<CoordinatePair> GetRectanglesContainedInBorders(IEnumerable<CoordinatePair> possibleRectangles, CoordinatePair[] borders)
{
return possibleRectangles
.Where(rectangle => IsRectangleInsideBorders(borders, rectangle));
}
private IEnumerable<CoordinatePair> GetAllPossibleRectanglesAsPairs(Coordinate[] redTiles)
{
return redTiles.Combinations(2).Select(x => AsPair(x[0], x[1]));
}
private CoordinatePair[] GetBordersAsPairs(Coordinate[] redTiles)
{
return GetBorders(redTiles).Select(x => AsPair(x.a, x.b)).ToArray();
}
private bool IsRectangleInsideBorders(CoordinatePair[] borders, CoordinatePair rectangle)
{
var bordersCrossed = borders.Any(border => RectangleCrossesBorder(rectangle, border));
return !bordersCrossed;
}
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<(Coordinate a, Coordinate b)> GetBorders(Coordinate[] tiles)
{
return tiles.Zip([..tiles[1..], tiles[0]], (a, b) => (a, b));
}
}