using AdventOfCode.Core.Shared.IO; namespace AdventOfCode.Solutions._2024 { public class Day05 : IChallange { public int Year => 2024; public int Day => 5; private readonly IInputReader _inputReader; public Day05(IInputReader inputReader) { _inputReader = inputReader; _inputReader.SetInput(this); } // 143 // 5651 public async Task GetSolutionPart1() { int total = 0; await foreach ((Rule[] rules, int[] updates) in GetUpdateWithRules(true)) { total += updates[(updates.Length - 1) / 2]; } return total.ToString(); } // 123 // 4743 public async Task GetSolutionPart2() { int total = 0; await foreach ((Rule[] rules, int[] updates) in GetUpdateWithRules(false)) { Rule[] requiredRules = rules; int A = 0, runs = (updates.Length + 1) / 2; for (int run = 0; run < runs; run++) { int[] B = requiredRules.Select(r => r.B).Distinct().ToArray(); A = requiredRules.Where(r => !B.Contains(r.A)).Select(r => r.A).First(); requiredRules = requiredRules.Where(r => r.A != A).ToArray(); } total += A; } return total.ToString(); } private struct Rule { public int A { get; set; } public int B { get; set; } } private async IAsyncEnumerable<(Rule[] rules, int[] updates)> GetUpdateWithRules(bool returnValidSet = true) { List rules = []; bool inputComplete = false; await foreach (string updateString in _inputReader.ReadAsStringLine()) { if (!inputComplete) { if (string.IsNullOrEmpty(updateString)) inputComplete = true; else rules.Add(ParseRule(updateString)); continue; } int[] updatePages = updateString.Split(',').Select(int.Parse).ToArray(); Rule[] requiredRules = rules .Where(r => updatePages.Contains(r.A)) .Where(r => updatePages.Contains(r.B)) .ToArray(); if (IsValid(requiredRules, updatePages) == returnValidSet) { yield return (requiredRules, updatePages); } } } private static bool IsValid(Rule[] rules, int[] updates) { Rule[] requiredRules = rules; List openRules = []; foreach (int update in updates) { // check if the current update is in the required list as the second value, if so this is an invalid update if (requiredRules.Any(r => r.B == update)) { return false; } // get new rules openRules.AddRange(requiredRules.Where(r => r.A == update)); requiredRules = requiredRules.Where(r => r.A != update).ToArray(); // close open rules openRules = openRules.Where(r => r.B != update).ToList(); } return true; } private static Rule ParseRule(string input) { int[] numbers = input.Split('|').Select(int.Parse).ToArray(); return new Rule { A = numbers[0], B = numbers[1] }; } } }