162 lines
5.6 KiB
C#
162 lines
5.6 KiB
C#
using System.Text.RegularExpressions;
|
|
using AdvenOfCode.Contracts;
|
|
using AdventOfCode.HelperClasses;
|
|
|
|
namespace AoC_2025;
|
|
|
|
public partial class Day02 : IPuzzleSolver<long>
|
|
{
|
|
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<long> FindInvalidIds(string range)
|
|
{
|
|
var ids = Parse(range);
|
|
var halvableIds = FindHalvableIds(ids);
|
|
var invalidIds = GetInvalidIds(halvableIds);
|
|
return invalidIds;
|
|
}
|
|
|
|
private IEnumerable<long> FindInvalidIdsRegex(string range)
|
|
{
|
|
return FindAllInvalidIds(range, RepeatedInputRegex());
|
|
}
|
|
|
|
private IEnumerable<long> FindInvalidSegmentedIdsRegex(string range)
|
|
{
|
|
return FindAllInvalidIds(range, SegmentRepeatedInputRegex());
|
|
}
|
|
|
|
private IEnumerable<long> FindAllInvalidIds(string range, Regex regex)
|
|
{
|
|
var ids = Parse(range);
|
|
var invalidIds = ids
|
|
.Where(id => regex.IsMatch(id.ToString()));
|
|
return invalidIds;
|
|
}
|
|
|
|
private IEnumerable<long> 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<string> FindHalvableIds(IntegerRange ids)
|
|
{
|
|
var idStrings = ids.Select(id => id.ToString());
|
|
var halvableIds = idStrings.Where(id => (id.Length % 2) == 0);
|
|
return halvableIds;
|
|
}
|
|
|
|
private IEnumerable<long> GetInvalidIds(IEnumerable<string> 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<IEnumerable<IEnumerable<string>>> GetIdAsAllSegments(IntegerRange ids)
|
|
{
|
|
var idStrings = ids.Select(id => id.ToString());
|
|
var idSegments = idStrings.Select(id => GetSegments(id));
|
|
return idSegments;
|
|
}
|
|
|
|
private IEnumerable<IEnumerable<string>> 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<IEnumerable<string>> FindIdsWhereAllSegmentsAreEqual(IEnumerable<IEnumerable<IEnumerable<string>>> idAllSegments)
|
|
{
|
|
var segmentsWithOneAllMatching = FilterForAnyAllSegmentsEqual(idAllSegments);
|
|
var idSegments = GetFirstForEachSegments(segmentsWithOneAllMatching);
|
|
return idSegments;
|
|
}
|
|
|
|
private static IEnumerable<IEnumerable<string>> GetFirstForEachSegments(IEnumerable<IEnumerable<IEnumerable<string>>> segmentsWithOneAllMatching)
|
|
{
|
|
var idSegments = segmentsWithOneAllMatching
|
|
.Select(segments => segments.First());
|
|
return idSegments;
|
|
}
|
|
|
|
private IEnumerable<string> MergeSegments(IEnumerable<IEnumerable<string>> segments)
|
|
{
|
|
return segments.Select(segment => string.Concat(segment));
|
|
}
|
|
|
|
private IEnumerable<IEnumerable<IEnumerable<string>>> FilterForAnyAllSegmentsEqual(IEnumerable<IEnumerable<IEnumerable<string>>> idAllSegments)
|
|
{
|
|
var segmentsWithOneAllMatching = idAllSegments
|
|
.Where(idSegments => idSegments.Any(segments => CheckAllSegmentsEqual(segments)));
|
|
return segmentsWithOneAllMatching;
|
|
}
|
|
|
|
private bool CheckAllSegmentsEqual(IEnumerable<string> 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();
|
|
} |