ben
/
aoc
1
0
Fork 0

2022 day 15 it's pretty slow
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Ben Harris 2023-12-02 22:52:28 -05:00
parent b00e172d38
commit f329cc9e61
2 changed files with 91 additions and 4 deletions

View File

@ -37,6 +37,7 @@ public class Test2022
[DataRow(typeof(Day12), "352", "345")]
[DataRow(typeof(Day13), "5682", "20304")]
[DataRow(typeof(Day14), "674", "24958")]
// [DataRow(typeof(Day15), "4724228", "13622251246513")] // TODO: optimize
public void CheckAllDays(Type dayType, string part1, string part2) =>
Common.CheckDay(dayType, part1, part2);
@ -55,7 +56,7 @@ public class Test2022
[DataRow(typeof(Day12), "31", "29")]
[DataRow(typeof(Day13), "13", "140")]
[DataRow(typeof(Day14), "24", "93")]
[DataRow(typeof(Day15), "", "")]
[DataRow(typeof(Day15), "26", "56000011")]
public void CheckTestInputs(Type dayType, string part1, string part2) =>
Common.CheckDay(dayType, part1, part2, true);
}

View File

@ -3,13 +3,99 @@ namespace AOC2022;
/// <summary>
/// Day 15: <a href="https://adventofcode.com/2022/day/15"/>
/// </summary>
public sealed class Day15() : Day(2022, 15, "Beacon Exclusion Zone")
public sealed partial class Day15() : Day(2022, 15, "Beacon Exclusion Zone")
{
private List<Sensor>? _sensors;
[GeneratedRegex(@"-?\d+")]
private static partial Regex DigitsRegex();
public override void ProcessInput()
{
_sensors = Input.Select(Sensor.FromString).ToList();
}
public override object Part1() => "";
public override object Part1()
{
var targetRow = UseTestInput ? 10 : 2_000_000;
var taken = _sensors!
.Where(t => t.ClosestBeaconPosition.y == targetRow)
.Select(t => t.ClosestBeaconPosition.x);
public override object Part2() => "";
return _sensors!
.SelectMany(s => s.GetSlice(targetRow).Values)
.Except(taken)
.Count();
}
public override object Part2()
{
var size = UseTestInput ? 20 : 4_000_000;
var limit = new SensorRange(0, size);
for (var y = 0; y <= size; y++)
{
var covered = _sensors!.Select(s => s.GetSlice(y));
var gap = FindGap(covered, limit);
if (gap is { } x)
return (x * 4_000_000L) + y;
}
return 0;
}
private static int? FindGap(IEnumerable<SensorRange> covered, SensorRange limit)
{
var ordered = covered
.Select(r => r.Intersect(limit))
.Where(r => !r.IsEmpty)
.OrderBy(r => r.Min)
.ThenBy(r => r.Max);
var max = limit.Min - 1;
foreach (var r in ordered)
{
if (max + 1 < r.Min) return max + 1;
max = Math.Max(max, r.Max);
}
return max < limit.Max ? max + 1 : null;
}
private readonly record struct SensorRange(int Min, int Max)
{
private static readonly SensorRange Empty = new(0, -1);
public bool IsEmpty => Min > Max;
public IEnumerable<int> Values =>
IsEmpty ? Enumerable.Empty<int>() : Enumerable.Range(Min, Max - Min + 1);
private bool Overlaps(SensorRange other) =>
!IsEmpty && !other.IsEmpty && Min <= other.Max && Max >= other.Min;
public SensorRange Intersect(SensorRange other) =>
Overlaps(other) ? new(Math.Max(Min, other.Min), Math.Min(Max, other.Max)) : Empty;
}
private record Sensor((int x, int y) Position, (int x, int y) ClosestBeaconPosition)
{
private int ManhattanDistance =>
Math.Abs(Position.x - ClosestBeaconPosition.x) + Math.Abs(Position.y - ClosestBeaconPosition.y);
public SensorRange GetSlice(int y)
{
var dy = Math.Abs(y - Position.y);
if (dy > ManhattanDistance) return new(0, -1);
var dx = ManhattanDistance - dy;
return new(Position.x - dx, Position.x + dx);
}
public static Sensor FromString(string line)
{
var coords = DigitsRegex().Matches(line).Select(p => int.Parse(p.Value)).ToList();
return new((coords[0], coords[1]), (coords[2], coords[3]));
}
}
}