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 inputs) { return inputs.Contains(NumLeft) && inputs.Contains(NumRight); } public bool IsValid(List 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 Rules { get; set; } = new List(); public RuleSet() {} public bool IsValid(List inputs) { foreach(var rule in Rules) { if(!rule.IsValid(inputs)) { return false; } } return true; } } public class RuleOrderer { private List rules; public RuleOrderer(List 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 OrderViaRules(List input) { var sortedList = new List(); 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>(); 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>(); 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>(); foreach(var sequence in invalidSequences) { var applicableRules = new List(); 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(); } }