112 lines
3.5 KiB
C#
112 lines
3.5 KiB
C#
using AdvenOfCode.Contracts;
|
|
using AdventOfCode.HelperClasses;
|
|
|
|
namespace AoC_2025;
|
|
|
|
public class Day05 : IPuzzleSolver<long>
|
|
{
|
|
private (List<string> freshIdRanges, List<string> ids) ParsePuzzleInput(string path)
|
|
{
|
|
var puzzleInput = File.ReadAllLines(path)
|
|
.Select(line => line.Trim())
|
|
.ToList();
|
|
var middle = puzzleInput.IndexOf("");
|
|
var freshIdRanges = puzzleInput[..middle];
|
|
var ids = puzzleInput[(middle + 1)..];
|
|
return (freshIdRanges, ids);
|
|
}
|
|
|
|
public long SolvePart1(string pathToPuzzleInput)
|
|
{
|
|
var database = ParsePuzzleInput(pathToPuzzleInput);
|
|
var freshIdRanges = ParseRanges(database.freshIdRanges);
|
|
var ids = ParseIds(database.ids);
|
|
var freshIds = FilterFreshIds(ids, freshIdRanges);
|
|
return freshIds.Count();
|
|
}
|
|
|
|
public long SolvePart2(string pathToPuzzleInput)
|
|
{
|
|
var database = ParsePuzzleInput(pathToPuzzleInput);
|
|
var freshIdRanges = ParseRanges(database.freshIdRanges);
|
|
var sumIds = SumIdsInRanges(freshIdRanges);
|
|
return sumIds;
|
|
}
|
|
|
|
public long SolvePart2Again(string pathToPuzzleInput)
|
|
{
|
|
var database = ParsePuzzleInput(pathToPuzzleInput);
|
|
var freshIdRanges = ParseRanges(database.freshIdRanges);
|
|
var combinedRanges = CombineOverlappingRanges(freshIdRanges);
|
|
var countIdsInRanges = CountIdsInRanges(combinedRanges);
|
|
var sumIds = countIdsInRanges.Sum();
|
|
return sumIds;
|
|
}
|
|
|
|
private IEnumerable<long> ParseIds(List<string> ids)
|
|
{
|
|
var parsedIds = ids.Select(id => long.Parse(id));
|
|
return parsedIds;
|
|
}
|
|
|
|
private IntegerRange[] ParseRanges(IEnumerable<string> ranges)
|
|
{
|
|
return ranges.Select(range =>
|
|
{
|
|
var split = range.Split('-', StringSplitOptions.RemoveEmptyEntries);
|
|
return new IntegerRange(long.Parse(split[0]), long.Parse(split[1]));
|
|
})
|
|
.OrderBy(range => range.start)
|
|
.ThenBy(range => range.end)
|
|
.ToArray();
|
|
}
|
|
|
|
private IEnumerable<long> FilterFreshIds(IEnumerable<long> ids, IntegerRange[] freshIdRanges)
|
|
{
|
|
var freshIds = ids.Where(id => IsIdInRanges(id, freshIdRanges));
|
|
return freshIds;
|
|
}
|
|
|
|
private bool IsIdInRanges(long id, IEnumerable<IntegerRange> ranges)
|
|
{
|
|
return ranges.Any(range => range.Contains(id));
|
|
}
|
|
|
|
private long SumIdsInRanges(IEnumerable<IntegerRange> ranges)
|
|
{
|
|
var sumFreshIds = 0L;
|
|
var highestSeenId = -1L;
|
|
foreach (var range in ranges)
|
|
{
|
|
var lowestNewId = Math.Max(highestSeenId + 1, range.start);
|
|
highestSeenId = Math.Max(highestSeenId, range.end);
|
|
sumFreshIds += Math.Max(0, highestSeenId - lowestNewId + 1);
|
|
}
|
|
|
|
return sumFreshIds;
|
|
}
|
|
|
|
private List<IntegerRange> CombineOverlappingRanges(IntegerRange[] ranges)
|
|
{
|
|
var optimizedRanges = new List<IntegerRange>(ranges.Length) { ranges[0] };
|
|
foreach (var range in ranges)
|
|
{
|
|
if (optimizedRanges[^1].TryCombine(range, out var combined))
|
|
{
|
|
optimizedRanges[^1] = combined;
|
|
}
|
|
else
|
|
{
|
|
optimizedRanges.Add(range);
|
|
}
|
|
}
|
|
|
|
return optimizedRanges;
|
|
}
|
|
|
|
private static IEnumerable<long> CountIdsInRanges(IEnumerable<IntegerRange> combinedRanges)
|
|
{
|
|
var countIdsInRanges = combinedRanges.Select(range => range.Count);
|
|
return countIdsInRanges;
|
|
}
|
|
} |