AdventOfCode/AoC_2025/Day05.cs

121 lines
3.8 KiB
C#

using System.Collections.Generic;
using System.IO;
using System.Linq;
using AdvenOfCode.Contracts;
using Range = (long from, long to);
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 Range[] ParseRanges(IEnumerable<string> ranges)
{
return ranges.Select(range =>
{
var split = range.Split('-', StringSplitOptions.RemoveEmptyEntries);
return (long.Parse(split[0]), long.Parse(split[1]));
})
.OrderBy(range => range.Item1)
.ThenBy(range => range.Item2)
.ToArray();
}
private IEnumerable<long> FilterFreshIds(IEnumerable<long> ids, Range[] freshIdRanges)
{
var freshIds = ids.Where(id => IsIdInRanges(id, freshIdRanges));
return freshIds;
}
private bool IsIdInRanges(long id, IEnumerable<Range> ranges)
{
return ranges.Any(range => IsIdInRange(id, range));
}
private bool IsIdInRange(long id, Range range)
{
return range.from <= id && range.to >= id;
}
private long SumIdsInRanges(IEnumerable<Range> ranges)
{
var sumFreshIds = 0L;
var highestSeenId = -1L;
foreach (var range in ranges)
{
var lowestNewId = Math.Max(highestSeenId + 1, range.from);
highestSeenId = Math.Max(highestSeenId, range.to);
sumFreshIds += Math.Max(0, highestSeenId - lowestNewId + 1);
}
return sumFreshIds;
}
private List<Range> CombineOverlappingRanges(Range[] ranges)
{
var optimizedRanges = new List<Range>(ranges.Length) { ranges[0] };
foreach (var range in ranges)
{
var lastRange = optimizedRanges[^1];
if (range.from > lastRange.to)
{
optimizedRanges.Add(range);
}
else if (IsIdInRange(range.from, lastRange) && ! IsIdInRange(range.to, lastRange))
{
optimizedRanges[^1] = (lastRange.from, range.to);
}
}
return optimizedRanges;
}
private static IEnumerable<long> CountIdsInRanges(IEnumerable<Range> combinedRanges)
{
var countIdsInRanges = combinedRanges.Select(range => range.to - range.from + 1);
return countIdsInRanges;
}
}