using System.Text.RegularExpressions; using AdvenOfCode.Contracts; using AdventOfCode.HelperClasses; namespace AoC_2025; public partial class Day02 : IPuzzleSolver { private string[] ParsePuzzleInput(string path) { var puzzleInput = File.ReadAllText(path) .Trim() .Split(',', StringSplitOptions.RemoveEmptyEntries); return puzzleInput; } public long SolvePart1(string pathToPuzzleInput) { var idRanges = ParsePuzzleInput(pathToPuzzleInput); var invalidIds = idRanges.SelectMany(range => FindInvalidIds(range)); var sum = invalidIds.Sum(); return sum; } public long SolvePart1Regex(string pathToPuzzleInput) { var idRanges = ParsePuzzleInput(pathToPuzzleInput); var invalidIds = idRanges.SelectMany(range => FindInvalidIdsRegex(range)); var sum = invalidIds.Sum(); return sum; } public long SolvePart2(string pathToPuzzleInput) { var idRanges = ParsePuzzleInput(pathToPuzzleInput); var invalidIds = idRanges.SelectMany(range => FindInvalidSegmentedIds(range)); var sum = invalidIds.Sum(); return sum; } public long SolvePart2Regex(string pathToPuzzleInput) { var idRanges = ParsePuzzleInput(pathToPuzzleInput); var invalidIds = idRanges.SelectMany(range => FindInvalidSegmentedIdsRegex(range)); var sum = invalidIds.Sum(); return sum; } private IEnumerable FindInvalidIds(string range) { var ids = Parse(range); var halvableIds = FindHalvableIds(ids); var invalidIds = GetInvalidIds(halvableIds); return invalidIds; } private IEnumerable FindInvalidIdsRegex(string range) { return FindAllInvalidIds(range, RepeatedInputRegex()); } private IEnumerable FindInvalidSegmentedIdsRegex(string range) { return FindAllInvalidIds(range, SegmentRepeatedInputRegex()); } private IEnumerable FindAllInvalidIds(string range, Regex regex) { var ids = Parse(range); var invalidIds = ids .Where(id => regex.IsMatch(id.ToString())); return invalidIds; } private IEnumerable FindInvalidSegmentedIds(string range) { var ids = Parse(range); var idsAsAllSegments = GetIdAsAllSegments(ids); var invalidIdSegments = FindIdsWhereAllSegmentsAreEqual(idsAsAllSegments); var invalidIds = MergeSegments(invalidIdSegments); var invalidIdNumbers = invalidIds.Select(id => long.Parse(id)); return invalidIdNumbers; } private IntegerRange Parse(string range) { var parts = range.Split('-', StringSplitOptions.RemoveEmptyEntries); return new IntegerRange(long.Parse(parts[0]), long.Parse(parts[1])); } private IEnumerable FindHalvableIds(IntegerRange ids) { var idStrings = ids.Select(id => id.ToString()); var halvableIds = idStrings.Where(id => (id.Length % 2) == 0); return halvableIds; } private IEnumerable GetInvalidIds(IEnumerable halvableIds) { var idParts = halvableIds.Select(id => (id[..(id.Length / 2)], id[(id.Length / 2)..])); var invalidIds = idParts.Where(parts=> parts.Item1 == parts.Item2); var invalidNumberedIds = invalidIds.Select(id => long.Parse(id.Item1 + id.Item2)); return invalidNumberedIds; } private IEnumerable>> GetIdAsAllSegments(IntegerRange ids) { var idStrings = ids.Select(id => id.ToString()); var idSegments = idStrings.Select(id => GetSegments(id)); return idSegments; } private IEnumerable> GetSegments(string id) { for (int i = id.Length / 2; i > 0; i--) { if (id.Length % i == 0) { yield return id.Chunk(i).Select(chunks => new string(chunks)); } } } private IEnumerable> FindIdsWhereAllSegmentsAreEqual(IEnumerable>> idAllSegments) { var segmentsWithOneAllMatching = FilterForAnyAllSegmentsEqual(idAllSegments); var idSegments = GetFirstForEachSegments(segmentsWithOneAllMatching); return idSegments; } private static IEnumerable> GetFirstForEachSegments(IEnumerable>> segmentsWithOneAllMatching) { var idSegments = segmentsWithOneAllMatching .Select(segments => segments.First()); return idSegments; } private IEnumerable MergeSegments(IEnumerable> segments) { return segments.Select(segment => string.Concat(segment)); } private IEnumerable>> FilterForAnyAllSegmentsEqual(IEnumerable>> idAllSegments) { var segmentsWithOneAllMatching = idAllSegments .Where(idSegments => idSegments.Any(segments => CheckAllSegmentsEqual(segments))); return segmentsWithOneAllMatching; } private bool CheckAllSegmentsEqual(IEnumerable segments) { var (allEqual, _) = segments.Aggregate( (allEqual: true, prev: ""), (tuple, segment) => (tuple.allEqual && (tuple.prev == "" || tuple.prev == segment), segment)); return allEqual; } [GeneratedRegex(@"^(.+)\1+$")] private static partial Regex SegmentRepeatedInputRegex(); [GeneratedRegex(@"^(.+)\1$")] private static partial Regex RepeatedInputRegex(); }