AdventOfCode/AdventOfCode.Solutions/2024/Day 05/Day05.cs
2024-12-05 10:16:30 +01:00

119 lines
3.7 KiB
C#

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<string> 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<string> 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<Rule> 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<Rule> 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] };
}
}
}