advent_of_code_2024/Level5/Level5Solver.cs

253 lines
7.0 KiB
C#
Raw Permalink Normal View History

2024-12-13 16:04:54 +01:00
namespace AoC24;
using AoC24.Common;
using AoCLevelInputProvider;
using Parsing;
using Parsing.Schema;
public class Rule
{
public string NumLeft { get; set; }
public string NumRight { get; set; }
public Rule(string numLeft, string numRight)
{
NumLeft = numLeft;
NumRight = numRight;
}
public bool IsApplicable(List<string> inputs)
{
return inputs.Contains(NumLeft) && inputs.Contains(NumRight);
}
public bool IsValid(List<string> inputs)
{
if(!IsApplicable(inputs))
{
return true;
}
for(int i = 0; i < inputs.Count; i++)
{
if(inputs[i].Equals(NumRight))
{
//Console.WriteLine("Matched NumRight:" + inputs[i]);
return false;
}
if(inputs[i].Equals(NumLeft))
{
//Console.WriteLine("Matched NumLeft:" + inputs[i]);
return true;
}
}
return true;
}
}
public class RuleSet
{
public List<Rule> Rules { get; set; } = new List<Rule>();
public RuleSet()
{}
public bool IsValid(List<string> inputs)
{
foreach(var rule in Rules)
{
if(!rule.IsValid(inputs))
{
return false;
}
}
return true;
}
}
public class RuleOrderer
{
private List<Rule> rules;
public RuleOrderer(List<Rule> rules)
{
this.rules = rules;
}
public bool RuleExistsThatPutsThisPageFirst(string page, string pageToCompareTo)
{
foreach (var rule in rules)
{
if(rule.NumLeft == page && rule.NumRight == pageToCompareTo)
{
return true;
}
}
return false;
}
public List<string> OrderViaRules(List<string> input)
{
var sortedList = new List<string>();
foreach(string num in input)
{
if(sortedList.Count == 0)
{
sortedList.Add(num);
}
else
{
for(int i = 0; i < sortedList.Count; i++)
{
var compareNum = sortedList[i];
if(this.RuleExistsThatPutsThisPageFirst(num, compareNum))
{
sortedList.Insert(i, num);
//Console.WriteLine(string.Join(",", sortedList));
break;
}
if( i == sortedList.Count - 1)
{
sortedList.Add(num);
//Console.WriteLine(string.Join(",", sortedList));
break;
}
}
}
}
// Console.WriteLine("=================");
// Console.WriteLine("Input: " + string.Join(",", input));
// Console.WriteLine("Applicable rules: ");
// foreach(var rule in rules.ToList().OrderBy(x => x.NumLeft))
// {
// Console.WriteLine(rule.NumLeft + "|" + rule.NumRight);
// }
// Console.WriteLine("Output: " + string.Join(",", sortedList));
// Console.ReadLine();
return sortedList;
}
}
public class Level5Solver: FragmentLevelSolverBase
{
public override int LevelNumber
{
get { return 5; }
}
protected override FragmentSchemaBuilder DefineInputSchema(FragmentSchemaBuilder schemaBuilder)
{
return schemaBuilder
.StartOptions()
.Option()
.Expect(InputType.Integer, "rule_left")
.Expect("|")
.Expect(InputType.Integer, "rule_right")
.Option()
.Expect(InputType.Integer, "pages")
.Repeat()
.Expect(",")
.Expect(InputType.Integer, "pages")
.EndRepetition()
.EndOptions();
}
public override string SolveFirstStar()
{
var data = this.GetData()
.AsFragments();
var validSequences = new List<List<string>>();
var ruleset = new RuleSet();
foreach(var fragment in data)
{
if(fragment["rule_left"].Count > 0)
{
//Console.WriteLine("Adding rule: " + fragment["rule_left"][0] + "|" + fragment["rule_right"][0]);
ruleset.Rules.Add(new Rule(fragment["rule_left"][0], fragment["rule_right"][0]));
}
else
{
//Console.WriteLine(string.Join(",", fragment["pages"]));
if(ruleset.IsValid(fragment["pages"]))
{
//Console.WriteLine("Adding fragment: " + string.Join(",", fragment["pages"]));
validSequences.Add(fragment["pages"]);
}
}
}
var count = 0;
foreach(var sequence in validSequences)
{
var middleItem = sequence[sequence.Count/2];
count += int.Parse(middleItem);
}
return count.ToString();
}
public override string SolveSecondStar()
{
var data = this.GetData()
.AsFragments();
var invalidSequences = new List<List<string>>();
var ruleset = new RuleSet();
foreach(var fragment in data)
{
if(fragment["rule_left"].Count > 0)
{
//Console.WriteLine("Adding rule: " + fragment["rule_left"][0] + "|" + fragment["rule_right"][0]);
ruleset.Rules.Add(new Rule(fragment["rule_left"][0], fragment["rule_right"][0]));
}
else
{
//Console.WriteLine(string.Join(",", fragment["pages"]));
if(!ruleset.IsValid(fragment["pages"]))
{
//Console.WriteLine("Adding fragment: " + string.Join(",", fragment["pages"]));
invalidSequences.Add(fragment["pages"]);
}
}
}
var orderedSequences = new List<List<string>>();
foreach(var sequence in invalidSequences)
{
var applicableRules = new List<Rule>();
foreach(var rule in ruleset.Rules)
{
if(rule.IsApplicable(sequence))
{
applicableRules.Add(rule);
}
}
var orderer = new RuleOrderer(applicableRules);
var orderedSequence = orderer.OrderViaRules(sequence);
if(!ruleset.IsValid(orderedSequence))
{
throw new Exception("badbadbad");
}
orderedSequences.Add(orderedSequence);
}
var count = 0;
foreach(var sequence in orderedSequences)
{
var middleItem = sequence[sequence.Count/2];
count += int.Parse(middleItem);
}
return count.ToString();
}
}