using AdvenOfCode.Contracts; using AdventOfCode.HelperClasses; namespace AoC_2025; public class Day05 : IPuzzleSolver { private (List freshIdRanges, List 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 ParseIds(List ids) { var parsedIds = ids.Select(id => long.Parse(id)); return parsedIds; } private IntegerRange[] ParseRanges(IEnumerable 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 FilterFreshIds(IEnumerable ids, IntegerRange[] freshIdRanges) { var freshIds = ids.Where(id => IsIdInRanges(id, freshIdRanges)); return freshIds; } private bool IsIdInRanges(long id, IEnumerable ranges) { return ranges.Any(range => range.Contains(id)); } private long SumIdsInRanges(IEnumerable 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 CombineOverlappingRanges(IntegerRange[] ranges) { var optimizedRanges = new List(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 CountIdsInRanges(IEnumerable combinedRanges) { var countIdsInRanges = combinedRanges.Select(range => range.Count); return countIdsInRanges; } }