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 { 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 Range[] ParseRanges(IEnumerable 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 FilterFreshIds(IEnumerable ids, Range[] freshIdRanges) { var freshIds = ids.Where(id => IsIdInRanges(id, freshIdRanges)); return freshIds; } private bool IsIdInRanges(long id, IEnumerable 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 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 CombineOverlappingRanges(Range[] ranges) { var optimizedRanges = new List(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 CountIdsInRanges(IEnumerable combinedRanges) { var countIdsInRanges = combinedRanges.Select(range => range.to - range.from + 1); return countIdsInRanges; } }