119 lines
3.7 KiB
C#
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] };
|
|
}
|
|
}
|
|
} |