diff --git a/Common/FragmentLevelSolverBase.cs b/Common/FragmentLevelSolverBase.cs index 9aef698..ad60b14 100644 --- a/Common/FragmentLevelSolverBase.cs +++ b/Common/FragmentLevelSolverBase.cs @@ -3,6 +3,7 @@ using AoCLevelInputProvider; using Parsing; using Parsing.Schema; +using Parsing.Data; using Parsing.Tokenization; public abstract class FragmentLevelSolverBase diff --git a/Common/FulltextLevelSolverBase.cs b/Common/FulltextLevelSolverBase.cs index bb675a2..7115465 100644 --- a/Common/FulltextLevelSolverBase.cs +++ b/Common/FulltextLevelSolverBase.cs @@ -3,6 +3,7 @@ using AoCLevelInputProvider; using Parsing; using Parsing.Schema; +using Parsing.Data; using Parsing.Tokenization; public abstract class FullTextLevelSolverBase diff --git a/Level4/Level4.csproj b/Level4/Level4.csproj new file mode 100644 index 0000000..34709f5 --- /dev/null +++ b/Level4/Level4.csproj @@ -0,0 +1,14 @@ + + + + Exe + net9.0 + enable + enable + + + + + + + diff --git a/Level4/Level4Solver.cs b/Level4/Level4Solver.cs new file mode 100644 index 0000000..7cdde2c --- /dev/null +++ b/Level4/Level4Solver.cs @@ -0,0 +1,67 @@ +namespace AoC24; + +using AoC24.Common; +using AoCLevelInputProvider; +using Parsing; +using Parsing.Data; +using Parsing.Schema; + +public class Level4Solver : FullTextLevelSolverBase +{ + public override int LevelNumber + { + get { return 4; } + } + + protected override InputSchemaBuilder DefineInputSchema(InputSchemaBuilder schemaBuilder) + { + return schemaBuilder + .Repeat() + .Expect(InputType.Char) + .EndRepetition(); + } + + public override string SolveFirstStar() + { + var data = this.GetData() + .AsListRows(); + + var searchSequence = new List { "X", "M", "A", "S" }; + var manipulator = DefaultTwoDimensionalManipulator.Create(data); + var searchResults = manipulator.FindInSet(searchSequence); + + return searchResults.Count.ToString(); + } + + public override string SolveSecondStar() + { + var data = this.GetData() + .AsListRows(); + + var searchSequence = new List { "M", "A", "S" }; + var manipulator = DefaultTwoDimensionalManipulator.Create(data); + var searchResults = manipulator.FindInSet(searchSequence, Direction.NE | Direction.SE | Direction.NW | Direction.SW); + + var indicesComparator = (IDataIndex index1, IDataIndex index2) => + { + return index1.GetIndices()[0] == index2.GetIndices()[0] && index1.GetIndices()[1] == index2.GetIndices()[1]; + }; + + var foundMatches = 0; + for(int i = 0; i < searchResults.Count; i++) + { + var secondPositionA = manipulator.Move(searchResults[i].DataIndex, searchResults[i].Direction); + for(int j = i+1; j < searchResults.Count; j++) + { + var secondPositionB = manipulator.Move(searchResults[j].DataIndex, searchResults[j].Direction); + if(indicesComparator(secondPositionA, secondPositionB)) + { + foundMatches++; + break; + } + } + } + + return foundMatches.ToString(); + } +} diff --git a/Level4/Program.cs b/Level4/Program.cs new file mode 100644 index 0000000..f05b52f --- /dev/null +++ b/Level4/Program.cs @@ -0,0 +1,24 @@ +// See https://aka.ms/new-console-template for more information + +using AoC24; + +var levelSolver = new Level4Solver(); +var solution1 = levelSolver.SolveFirstStar(); +var solution2 = levelSolver.SolveSecondStar(); + +if (!string.IsNullOrEmpty(solution1)) +{ + Console.WriteLine("Solution for example 1 is: " + solution1); +} +else +{ + Console.WriteLine("Example 1 has not been solved yet!"); +} +if (!string.IsNullOrEmpty(solution2)) +{ + Console.WriteLine("Solution for example 2 is: " + solution2); +} +else +{ + Console.WriteLine("Example 2 has not been solved yet!"); +} diff --git a/Level5/Level5.csproj b/Level5/Level5.csproj new file mode 100644 index 0000000..34709f5 --- /dev/null +++ b/Level5/Level5.csproj @@ -0,0 +1,14 @@ + + + + Exe + net9.0 + enable + enable + + + + + + + diff --git a/Level5/Level5Solver.cs b/Level5/Level5Solver.cs new file mode 100644 index 0000000..67bd2a4 --- /dev/null +++ b/Level5/Level5Solver.cs @@ -0,0 +1,252 @@ +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(); + } +} diff --git a/Level5/Program.cs b/Level5/Program.cs new file mode 100644 index 0000000..910cc6a --- /dev/null +++ b/Level5/Program.cs @@ -0,0 +1,24 @@ +// See https://aka.ms/new-console-template for more information + +using AoC24; + +var levelSolver = new Level5Solver(); +var solution1 = levelSolver.SolveFirstStar(); +var solution2 = levelSolver.SolveSecondStar(); + +if (!string.IsNullOrEmpty(solution1)) +{ + Console.WriteLine("Solution for example 1 is: " + solution1); +} +else +{ + Console.WriteLine("Example 1 has not been solved yet!"); +} +if (!string.IsNullOrEmpty(solution2)) +{ + Console.WriteLine("Solution for example 2 is: " + solution2); +} +else +{ + Console.WriteLine("Example 2 has not been solved yet!"); +} diff --git a/Level6/Level6.csproj b/Level6/Level6.csproj new file mode 100644 index 0000000..34709f5 --- /dev/null +++ b/Level6/Level6.csproj @@ -0,0 +1,14 @@ + + + + Exe + net9.0 + enable + enable + + + + + + + diff --git a/Level6/Level6Solver.cs b/Level6/Level6Solver.cs new file mode 100644 index 0000000..b8fb47d --- /dev/null +++ b/Level6/Level6Solver.cs @@ -0,0 +1,248 @@ +namespace AoC24; + +using AoC24.Common; +using AoCLevelInputProvider; +using Parsing; +using Parsing.Data; +using Parsing.Schema; + +public class LoopDetectionException : Exception +{ + public LoopDetectionException(string message) : base(message) + {} +} + +public class GuardRunner +{ + public IDataIndex currentPosition; + public IDataIndex initialCurrentPosition; + public int TraversedTiles; + public IDictionary>> traversalMap = new Dictionary>>(); + public Direction currentDirection; + public Direction initialDirection; + public List> obstacles; + private DefaultTwoDimensionalManipulator manipulator; + private DefaultDataSetIndexer indexer; + private List> dataSet; + + public GuardRunner(IDataIndex startingPosition, string guardChar, List> obstacles, List> dataSet) + { + switch(guardChar) + { + case "^": + this.currentDirection = Direction.Up; + break; + case ">": + this.currentDirection = Direction.Right; + break; + case "v": + this.currentDirection = Direction.Down; + break; + case "<": + this.currentDirection = Direction.Left; + break; + default: + throw new ArgumentException("Invalid directional parameter given"); + } + + this.initialDirection = currentDirection; + this.currentPosition = startingPosition; + this.initialCurrentPosition = startingPosition; + this.obstacles = obstacles; + this.manipulator = new DefaultTwoDimensionalManipulator(dataSet); + this.indexer = new DefaultDataSetIndexer(); + this.dataSet = dataSet; + } + + private void VisitTile(int x, int y, Direction d) + { + if(!this.traversalMap.ContainsKey(x)) + { + this.traversalMap[x] = new Dictionary>(); + } + if(!this.traversalMap[x].ContainsKey(y)) + { + this.traversalMap[x][y] = new List(); + } + this.traversalMap[x][y].Add(d); + var dirStringList = new List(); + foreach(var direction in this.traversalMap[x][y]) + { + dirStringList.Add(direction.ToString()); + } + //Console.WriteLine($"Check tile ({x},{y}): " + string.Join(",", dirStringList)); + } + + private Direction TurnRight(Direction d) + { + switch(d) + { + case Direction.Up: + return Direction.Right; + case Direction.Right: + return Direction.Down; + case Direction.Down: + return Direction.Left; + case Direction.Left: + return Direction.Up; + default: + throw new InvalidOperationException("This default case should never be reached!"); + } + } + + private bool AreEqual(DirectionalSearchResult di1, DirectionalSearchResult di2) + { + return di1.Direction == di2.Direction + && di1.DataIndex.GetIndices()[0] == di2.DataIndex.GetIndices()[0] + && di1.DataIndex.GetIndices()[1] == di2.DataIndex.GetIndices()[1]; + } + + public void Run() + { + TraversedTiles = 1; + currentPosition = initialCurrentPosition; + traversalMap = new Dictionary>>(); + currentDirection = initialDirection; + + while(true) + { + var nextPosition = currentPosition; + + while(nextPosition == currentPosition) + { + var nextPositionCandidate = manipulator.Move(currentPosition, currentDirection); + + if(!manipulator.IsValidIndex(nextPositionCandidate)) + { + // we just went off the map + return; + } + // if we added an extra obstacle it will be at the beginning of the list + if(this.obstacles[0].DataIndex.GetIndices()[0] == nextPositionCandidate.GetIndices()[0] + && this.obstacles[0].DataIndex.GetIndices()[1] == nextPositionCandidate.GetIndices()[1]) + { + currentDirection = TurnRight(currentDirection); + } + else if(indexer.Get(dataSet, nextPositionCandidate) == "#") + { + currentDirection = TurnRight(currentDirection); + } + else + { + nextPosition = nextPositionCandidate; + } + } + + // we just moved, take into account the tile we just moved on + currentPosition = nextPosition; + + // if we have been here before we have entered a loop + if(this.traversalMap.ContainsKey(currentPosition.GetIndices()[0]) + && this.traversalMap[currentPosition.GetIndices()[0]].ContainsKey(currentPosition.GetIndices()[1]) + && this.traversalMap[currentPosition.GetIndices()[0]][currentPosition.GetIndices()[1]].Contains(currentDirection)) + { + throw new LoopDetectionException(""); + } + + VisitTile(currentPosition.GetIndices()[0], currentPosition.GetIndices()[1], currentDirection); + } + } +} + +public class Level6Solver : FullTextLevelSolverBase +{ + public override int LevelNumber + { + get { return 6; } + } + + protected override InputSchemaBuilder DefineInputSchema(InputSchemaBuilder schemaBuilder) + { + return schemaBuilder + .Repeat() + .Expect(InputType.Char) + .EndRepetition(); + } + + public override string SolveFirstStar() + { + var data = this.GetData() + .AsListRows(); + + var manipulator = DefaultTwoDimensionalManipulator.Create(data); + var obstacles = manipulator.FindInSet("#"); + var possibleGuardCharacters = new List() { ">", "<", "v", "^" }; + var obstacleList = manipulator.FindInSet("#"); + SearchResult guard = null; + foreach(var gchar in possibleGuardCharacters) + { + guard = manipulator.FindInSet(gchar).SingleOrDefault(); + if (guard != null) + { + break; + } + } + var dataAccessor = new DefaultDataSetIndexer(); + var guardChar = dataAccessor.Get(data, guard.DataIndex); + + var guardRunner = new GuardRunner(guard.DataIndex, guardChar, obstacleList, data); + guardRunner.Run(); + + var count = 1; + foreach(var xCoord in guardRunner.traversalMap.Keys) + { + count += guardRunner.traversalMap[xCoord].Count; + } + + return count.ToString(); + } + + public override string SolveSecondStar() + { + var data = this.GetData() + .AsListRows(); + + var manipulator = DefaultTwoDimensionalManipulator.Create(data); + var possibleGuardCharacters = new List() { ">", "<", "v", "^" }; + var obstacleList = manipulator.FindInSet("#"); + SearchResult guard = null; + foreach(var gchar in possibleGuardCharacters) + { + guard = manipulator.FindInSet(gchar).SingleOrDefault(); + if (guard != null) + { + break; + } + } + var dataAccessor = new DefaultDataSetIndexer(); + var guardChar = dataAccessor.Get(data, guard.DataIndex); + + // first determine regular taken path + var guardRunner = new GuardRunner(guard.DataIndex, guardChar, obstacleList, data); + guardRunner.Run(); + + // now for each visited tile, place an obstacle there and see if we run into a loop + int loopCount = 0; + foreach(var xCoord in guardRunner.traversalMap.Keys) + { + foreach(var yCoord in guardRunner.traversalMap[xCoord].Keys) + { + //Console.WriteLine($"Trying obstacle at ({xCoord},{yCoord})"); + var newObstacleList = new List>(); + newObstacleList.Add(new SearchResult(new DefaultPositionalDataIndex(xCoord, yCoord))); + newObstacleList.AddRange(obstacleList); + var testRunner = new GuardRunner(guard.DataIndex, guardChar, newObstacleList, data); + try + { + testRunner.Run(); + } + catch(LoopDetectionException) + { + loopCount += 1; + } + } + } + + return loopCount.ToString(); + } +} diff --git a/Level6/Program.cs b/Level6/Program.cs new file mode 100644 index 0000000..add5bb9 --- /dev/null +++ b/Level6/Program.cs @@ -0,0 +1,24 @@ +// See https://aka.ms/new-console-template for more information + +using AoC24; + +var levelSolver = new Level6Solver(); +var solution1 = levelSolver.SolveFirstStar(); +var solution2 = levelSolver.SolveSecondStar(); + +if (!string.IsNullOrEmpty(solution1)) +{ + Console.WriteLine("Solution for example 1 is: " + solution1); +} +else +{ + Console.WriteLine("Example 1 has not been solved yet!"); +} +if (!string.IsNullOrEmpty(solution2)) +{ + Console.WriteLine("Solution for example 2 is: " + solution2); +} +else +{ + Console.WriteLine("Example 2 has not been solved yet!"); +} diff --git a/Level7/Level7.csproj b/Level7/Level7.csproj new file mode 100644 index 0000000..34709f5 --- /dev/null +++ b/Level7/Level7.csproj @@ -0,0 +1,14 @@ + + + + Exe + net9.0 + enable + enable + + + + + + + diff --git a/Level7/Level7.sln b/Level7/Level7.sln new file mode 100644 index 0000000..e483f54 --- /dev/null +++ b/Level7/Level7.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.002.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Level7", "Level7.csproj", "{B69CB5AF-BF4D-4425-A20B-3E95D2E0EABB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B69CB5AF-BF4D-4425-A20B-3E95D2E0EABB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B69CB5AF-BF4D-4425-A20B-3E95D2E0EABB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B69CB5AF-BF4D-4425-A20B-3E95D2E0EABB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B69CB5AF-BF4D-4425-A20B-3E95D2E0EABB}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {3F192730-CD0E-42EA-89C1-94B84247D113} + EndGlobalSection +EndGlobal diff --git a/Level7/Level7Solver.cs b/Level7/Level7Solver.cs new file mode 100644 index 0000000..826dd43 --- /dev/null +++ b/Level7/Level7Solver.cs @@ -0,0 +1,239 @@ +namespace AoC24; + +using AoC24.Common; +using AoCLevelInputProvider; +using Parsing; +using Parsing.Data; +using Parsing.Schema; + +public enum Operator +{ + Multiply, + Add, + Concatenate, +} + +public class Equation +{ + private List operands; + + private List operators; + + public Equation(List operands) + { + this.operands = new List(); + this.operands.AddRange(operands); + this.operators = new List(); + } + + private Equation(List operands, List operators) + { + this.operands = new List(); + this.operands.AddRange(operands); + this.operators = new List(); + this.operators.AddRange(operators); + } + + public void AddOperator(Operator op) + { + this.operators.Add(op); + } + + public bool CanHoldMoreOperators() + { + return this.operators.Count < (this.operands.Count - 1); + } + + public long Solve() + { + long result = this.operands[0]; + for(int i = 0; i < this.operators.Count; i++) + { + switch(this.operators[i]) + { + case Operator.Add: + result = result + (this.operands[i+1]); + break; + case Operator.Multiply: + result = result * (this.operands[i+1]); + break; + default: + throw new Exception("This should never be reached"); + } + } + return result; + } + + public long Solve2() + { + long result = this.operands[0]; + for(int i = 0; i < this.operators.Count; i++) + { + switch(this.operators[i]) + { + case Operator.Add: + result = result + (this.operands[i+1]); + break; + case Operator.Multiply: + result = result * (this.operands[i+1]); + break; + case Operator.Concatenate: + result = result * (long)Math.Pow(10, (this.operands[i+1].ToString().Length)) + this.operands[i+1]; + break; + default: + throw new Exception("This should never be reached"); + } + } + return result; + } + + public Equation Clone() + { + return new Equation(this.operands, this.operators); + } +} + +public class EquationBuilder +{ + public long TestValue; + + private List operands; + + private List operatorOptions; + + private List SolvableEquations = new List(); + + public EquationBuilder(long testValue, params Operator[] operatorOptions) + { + this.TestValue = testValue; + this.operands = new List(); + this.operatorOptions = new List(); + this.operatorOptions.AddRange(operatorOptions); + } + + public void AddOperand(int operand) + { + this.operands.Add(operand); + } + + private List BuildEquationCandidates(Equation e) + { + List resultEquations = new List(); + if(!e.CanHoldMoreOperators()) + { + resultEquations.Add(e); + } + else + { + foreach(var op in this.operatorOptions) + { + var newEquation = e.Clone(); + newEquation.AddOperator(op); + resultEquations.AddRange(BuildEquationCandidates(newEquation)); + } + } + return resultEquations; + } + + public bool FindSolutions() + { + var allPossibleEquations = BuildEquationCandidates(new Equation(this.operands)); + foreach(var equation in allPossibleEquations) + { + if(equation.Solve() == this.TestValue) + { + this.SolvableEquations.Add(equation); + } + } + return this.SolvableEquations.Any(); + } + + public bool FindSolutions2() + { + var allPossibleEquations = BuildEquationCandidates(new Equation(this.operands)); + foreach(var equation in allPossibleEquations) + { + if(equation.Solve2() == this.TestValue) + { + this.SolvableEquations.Add(equation); + } + } + return this.SolvableEquations.Any(); + } +} + +public class Level7Solver : FullTextLevelSolverBase +{ + public override int LevelNumber + { + get { return 7; } + } + + private long ParseLong(string word) + { + return long.Parse(word.Replace(":", "")); + } + + protected override InputSchemaBuilder DefineInputSchema(InputSchemaBuilder schemaBuilder) + { + return schemaBuilder + .Expect(InputType.Custom, InputType.Long, this.ParseLong) + .Repeat() + .Expect(InputType.Long) + .EndRepetition(); + } + + public override string SolveFirstStar() + { + var equationBuilders = this.GetData() + .Filter(InputType.Long) + .AsListRows() + .TransformData((List inputs) => { + var eb = new EquationBuilder(inputs[0], Operator.Multiply, Operator.Add); + for(int i = 1; i < inputs.Count; i++) + { + eb.AddOperand((int)inputs[i]); + } + return eb; + }); + + long totalSum = 0; + + foreach(var equationBuilder in equationBuilders) + { + if(equationBuilder.FindSolutions()) + { + totalSum += equationBuilder.TestValue; + } + } + + return totalSum.ToString(); + } + + public override string SolveSecondStar() + { + var equationBuilders = this.GetData() + .Filter(InputType.Long) + .AsListRows() + .TransformData((List inputs) => { + var eb = new EquationBuilder(inputs[0], Operator.Multiply, Operator.Add, Operator.Concatenate); + for(int i = 1; i < inputs.Count; i++) + { + eb.AddOperand((int)inputs[i]); + } + return eb; + }); + + long totalSum = 0; + + foreach(var equationBuilder in equationBuilders) + { + if(equationBuilder.FindSolutions2()) + { + totalSum += equationBuilder.TestValue; + } + } + + return totalSum.ToString(); + } +} diff --git a/Level7/Program.cs b/Level7/Program.cs new file mode 100644 index 0000000..8dc97d1 --- /dev/null +++ b/Level7/Program.cs @@ -0,0 +1,24 @@ +// See https://aka.ms/new-console-template for more information + +using AoC24; + +var levelSolver = new Level7Solver(); +var solution1 = levelSolver.SolveFirstStar(); +var solution2 = levelSolver.SolveSecondStar(); + +if (!string.IsNullOrEmpty(solution1)) +{ + Console.WriteLine("Solution for example 1 is: " + solution1); +} +else +{ + Console.WriteLine("Example 1 has not been solved yet!"); +} +if (!string.IsNullOrEmpty(solution2)) +{ + Console.WriteLine("Solution for example 2 is: " + solution2); +} +else +{ + Console.WriteLine("Example 2 has not been solved yet!"); +}