[2k25] Add day 9
This commit is contained in:
192
Days/Day9.cs
Normal file
192
Days/Day9.cs
Normal file
@@ -0,0 +1,192 @@
|
||||
using Spectre.Console;
|
||||
|
||||
namespace AdventOfCode.Days;
|
||||
|
||||
public class Day9 : Day
|
||||
{
|
||||
public override int Number => 9;
|
||||
public override string Name => "Movie Theater";
|
||||
|
||||
public override void RunPart1(bool display = true)
|
||||
{
|
||||
var tilePositions = ParseTilePositions(Input);
|
||||
|
||||
var maxArea = 0L;
|
||||
|
||||
for (var firstIndex = 0; firstIndex < tilePositions.Count - 1; firstIndex++)
|
||||
{
|
||||
for (var secondIndex = firstIndex + 1; secondIndex < tilePositions.Count; secondIndex++)
|
||||
{
|
||||
var firstTile = tilePositions[firstIndex];
|
||||
var secondTile = tilePositions[secondIndex];
|
||||
|
||||
var area = (Math.Abs(secondTile.I - firstTile.I) + 1) *
|
||||
(Math.Abs(secondTile.J - firstTile.J) + 1);
|
||||
|
||||
if (area > maxArea)
|
||||
{
|
||||
maxArea = area;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (display)
|
||||
{
|
||||
AnsiConsole.MarkupLine($"[green]Max tile area is: [yellow]{maxArea}[/][/]");
|
||||
}
|
||||
}
|
||||
|
||||
public override void RunPart2(bool display = true)
|
||||
{
|
||||
var tilePositions = ParseTilePositions(Input);
|
||||
|
||||
// Make a list of possible areas in descending order
|
||||
var tileAreas = new List<TileArea>();
|
||||
|
||||
for (var firstIndex = 0; firstIndex < tilePositions.Count - 1; firstIndex++)
|
||||
{
|
||||
for (var secondIndex = firstIndex + 1; secondIndex < tilePositions.Count; secondIndex++)
|
||||
{
|
||||
var firstTile = tilePositions[firstIndex];
|
||||
var secondTile = tilePositions[secondIndex];
|
||||
|
||||
var area = (Math.Abs(secondTile.I - firstTile.I) + 1) *
|
||||
(Math.Abs(secondTile.J - firstTile.J) + 1);
|
||||
|
||||
tileAreas.Add(new TileArea(firstTile, secondTile, area));
|
||||
}
|
||||
}
|
||||
|
||||
// Sort list in descending order (biggest area first)
|
||||
tileAreas.Sort((left, right) => right.Area.CompareTo(left.Area));
|
||||
|
||||
// Compute polygon bounds with green tiles
|
||||
var jBoundsAtI = new Dictionary<long, PositionBounds>();
|
||||
var iBoundsAtJ = new Dictionary<long, PositionBounds>();
|
||||
foreach (var (firstTile, secondTile) in tilePositions.Zip(tilePositions.Skip(1).Append(tilePositions[0])))
|
||||
{
|
||||
// Tiles are on same line, set bounds for columns (j)
|
||||
if (firstTile.I == secondTile.I)
|
||||
{
|
||||
var start = Math.Min(firstTile.J, secondTile.J);
|
||||
var end = Math.Max(firstTile.J, secondTile.J);
|
||||
|
||||
for (var j = start; j <= end; j++)
|
||||
{
|
||||
// Update bounds
|
||||
if (iBoundsAtJ.TryGetValue(j, out var bounds))
|
||||
{
|
||||
iBoundsAtJ[j] = new PositionBounds(
|
||||
Math.Min(firstTile.I, bounds.Min),
|
||||
Math.Max(firstTile.I, bounds.Max)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
iBoundsAtJ[j] = new PositionBounds(
|
||||
firstTile.I,
|
||||
firstTile.I
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Tiles are on same column, set bounds for rows (i)
|
||||
else if (firstTile.J == secondTile.J)
|
||||
{
|
||||
var start = Math.Min(firstTile.I, secondTile.I);
|
||||
var end = Math.Max(firstTile.I, secondTile.I);
|
||||
|
||||
for (var i = start; i<= end; i++)
|
||||
{
|
||||
// Update bounds
|
||||
if (jBoundsAtI.TryGetValue(i, out var bounds))
|
||||
{
|
||||
jBoundsAtI[i] = new PositionBounds(
|
||||
Math.Min(firstTile.J, bounds.Min),
|
||||
Math.Max(firstTile.J, bounds.Max)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
jBoundsAtI[i] = new PositionBounds(
|
||||
firstTile.J,
|
||||
firstTile.J
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find the first area that is valid (composed of green or red tiles)
|
||||
var maxValidArea = -1L;
|
||||
foreach (var tileArea in tileAreas)
|
||||
{
|
||||
// For each point in this area, check if it is within bounds
|
||||
var iStart = Math.Min(tileArea.First.I, tileArea.Second.I);
|
||||
var iEnd = Math.Max(tileArea.First.I, tileArea.Second.I);
|
||||
|
||||
var jStart = Math.Min(tileArea.First.J, tileArea.Second.J);
|
||||
var jEnd = Math.Max(tileArea.First.J, tileArea.Second.J);
|
||||
|
||||
// Check if any point is out of bounds
|
||||
var outOfBounds = false;
|
||||
for (var i = iStart; i <= iEnd; i++)
|
||||
{
|
||||
for (var j = jStart; j <= jEnd; j++)
|
||||
{
|
||||
var iBound = iBoundsAtJ[j];
|
||||
var jBound = jBoundsAtI[i];
|
||||
|
||||
if (i < iBound.Min || i > iBound.Max ||
|
||||
j < jBound.Min || j > jBound.Max)
|
||||
{
|
||||
outOfBounds = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (outOfBounds)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If no points are out of bounds, we have our biggest valid area
|
||||
if (!outOfBounds)
|
||||
{
|
||||
maxValidArea = tileArea.Area;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (display)
|
||||
{
|
||||
AnsiConsole.MarkupLine($"[green]Max valid tile area is: [yellow]{maxValidArea}[/][/]");
|
||||
}
|
||||
}
|
||||
|
||||
private static List<TilePosition> ParseTilePositions(string input)
|
||||
{
|
||||
var tilePositions = new List<TilePosition>();
|
||||
|
||||
foreach (var line in input.EnumerateLines())
|
||||
{
|
||||
var splitIndex = line.IndexOf(',');
|
||||
|
||||
var j = long.Parse(line[..splitIndex]);
|
||||
var i = long.Parse(line[(splitIndex + 1)..]);
|
||||
|
||||
tilePositions.Add(new TilePosition(i, j));
|
||||
}
|
||||
|
||||
return tilePositions;
|
||||
}
|
||||
|
||||
private record TilePosition(long I, long J);
|
||||
|
||||
private record TileArea(TilePosition First, TilePosition Second, long Area);
|
||||
|
||||
private record PositionBounds(long Min, long Max);
|
||||
}
|
||||
Reference in New Issue
Block a user