add a few more solutions
This commit is contained in:
parent
5b9ad5766b
commit
7ec5c32e47
@ -3,6 +3,7 @@
|
|||||||
using AoCLevelInputProvider;
|
using AoCLevelInputProvider;
|
||||||
using Parsing;
|
using Parsing;
|
||||||
using Parsing.Schema;
|
using Parsing.Schema;
|
||||||
|
using Parsing.Data;
|
||||||
using Parsing.Tokenization;
|
using Parsing.Tokenization;
|
||||||
|
|
||||||
public abstract class FragmentLevelSolverBase
|
public abstract class FragmentLevelSolverBase
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
using AoCLevelInputProvider;
|
using AoCLevelInputProvider;
|
||||||
using Parsing;
|
using Parsing;
|
||||||
using Parsing.Schema;
|
using Parsing.Schema;
|
||||||
|
using Parsing.Data;
|
||||||
using Parsing.Tokenization;
|
using Parsing.Tokenization;
|
||||||
|
|
||||||
public abstract class FullTextLevelSolverBase
|
public abstract class FullTextLevelSolverBase
|
||||||
|
14
Level4/Level4.csproj
Normal file
14
Level4/Level4.csproj
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="../Common/Common.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
67
Level4/Level4Solver.cs
Normal file
67
Level4/Level4Solver.cs
Normal file
@ -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<string>();
|
||||||
|
|
||||||
|
var searchSequence = new List<string> { "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<string>();
|
||||||
|
|
||||||
|
var searchSequence = new List<string> { "M", "A", "S" };
|
||||||
|
var manipulator = DefaultTwoDimensionalManipulator.Create(data);
|
||||||
|
var searchResults = manipulator.FindInSet(searchSequence, Direction.NE | Direction.SE | Direction.NW | Direction.SW);
|
||||||
|
|
||||||
|
var indicesComparator = (IDataIndex<int> index1, IDataIndex<int> 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();
|
||||||
|
}
|
||||||
|
}
|
24
Level4/Program.cs
Normal file
24
Level4/Program.cs
Normal file
@ -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!");
|
||||||
|
}
|
14
Level5/Level5.csproj
Normal file
14
Level5/Level5.csproj
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="../Common/Common.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
252
Level5/Level5Solver.cs
Normal file
252
Level5/Level5Solver.cs
Normal file
@ -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<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();
|
||||||
|
}
|
||||||
|
}
|
24
Level5/Program.cs
Normal file
24
Level5/Program.cs
Normal file
@ -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!");
|
||||||
|
}
|
14
Level6/Level6.csproj
Normal file
14
Level6/Level6.csproj
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="../Common/Common.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
248
Level6/Level6Solver.cs
Normal file
248
Level6/Level6Solver.cs
Normal file
@ -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<int> currentPosition;
|
||||||
|
public IDataIndex<int> initialCurrentPosition;
|
||||||
|
public int TraversedTiles;
|
||||||
|
public IDictionary<int, Dictionary<int, List<Direction>>> traversalMap = new Dictionary<int, Dictionary<int, List<Direction>>>();
|
||||||
|
public Direction currentDirection;
|
||||||
|
public Direction initialDirection;
|
||||||
|
public List<SearchResult<int>> obstacles;
|
||||||
|
private DefaultTwoDimensionalManipulator<string> manipulator;
|
||||||
|
private DefaultDataSetIndexer<string> indexer;
|
||||||
|
private List<List<string>> dataSet;
|
||||||
|
|
||||||
|
public GuardRunner(IDataIndex<int> startingPosition, string guardChar, List<SearchResult<int>> obstacles, List<List<string>> 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<string>(dataSet);
|
||||||
|
this.indexer = new DefaultDataSetIndexer<string>();
|
||||||
|
this.dataSet = dataSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void VisitTile(int x, int y, Direction d)
|
||||||
|
{
|
||||||
|
if(!this.traversalMap.ContainsKey(x))
|
||||||
|
{
|
||||||
|
this.traversalMap[x] = new Dictionary<int, List<Direction>>();
|
||||||
|
}
|
||||||
|
if(!this.traversalMap[x].ContainsKey(y))
|
||||||
|
{
|
||||||
|
this.traversalMap[x][y] = new List<Direction>();
|
||||||
|
}
|
||||||
|
this.traversalMap[x][y].Add(d);
|
||||||
|
var dirStringList = new List<string>();
|
||||||
|
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<int> di1, DirectionalSearchResult<int> 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<int, Dictionary<int, List<Direction>>>();
|
||||||
|
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<string>();
|
||||||
|
|
||||||
|
var manipulator = DefaultTwoDimensionalManipulator.Create(data);
|
||||||
|
var obstacles = manipulator.FindInSet("#");
|
||||||
|
var possibleGuardCharacters = new List<string>() { ">", "<", "v", "^" };
|
||||||
|
var obstacleList = manipulator.FindInSet("#");
|
||||||
|
SearchResult<int> guard = null;
|
||||||
|
foreach(var gchar in possibleGuardCharacters)
|
||||||
|
{
|
||||||
|
guard = manipulator.FindInSet(gchar).SingleOrDefault();
|
||||||
|
if (guard != null)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var dataAccessor = new DefaultDataSetIndexer<string>();
|
||||||
|
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<string>();
|
||||||
|
|
||||||
|
var manipulator = DefaultTwoDimensionalManipulator.Create(data);
|
||||||
|
var possibleGuardCharacters = new List<string>() { ">", "<", "v", "^" };
|
||||||
|
var obstacleList = manipulator.FindInSet("#");
|
||||||
|
SearchResult<int> guard = null;
|
||||||
|
foreach(var gchar in possibleGuardCharacters)
|
||||||
|
{
|
||||||
|
guard = manipulator.FindInSet(gchar).SingleOrDefault();
|
||||||
|
if (guard != null)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var dataAccessor = new DefaultDataSetIndexer<string>();
|
||||||
|
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<SearchResult<int>>();
|
||||||
|
newObstacleList.Add(new SearchResult<int>(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();
|
||||||
|
}
|
||||||
|
}
|
24
Level6/Program.cs
Normal file
24
Level6/Program.cs
Normal file
@ -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!");
|
||||||
|
}
|
14
Level7/Level7.csproj
Normal file
14
Level7/Level7.csproj
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="../Common/Common.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
25
Level7/Level7.sln
Normal file
25
Level7/Level7.sln
Normal file
@ -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
|
239
Level7/Level7Solver.cs
Normal file
239
Level7/Level7Solver.cs
Normal file
@ -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<int> operands;
|
||||||
|
|
||||||
|
private List<Operator> operators;
|
||||||
|
|
||||||
|
public Equation(List<int> operands)
|
||||||
|
{
|
||||||
|
this.operands = new List<int>();
|
||||||
|
this.operands.AddRange(operands);
|
||||||
|
this.operators = new List<Operator>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Equation(List<int> operands, List<Operator> operators)
|
||||||
|
{
|
||||||
|
this.operands = new List<int>();
|
||||||
|
this.operands.AddRange(operands);
|
||||||
|
this.operators = new List<Operator>();
|
||||||
|
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<int> operands;
|
||||||
|
|
||||||
|
private List<Operator> operatorOptions;
|
||||||
|
|
||||||
|
private List<Equation> SolvableEquations = new List<Equation>();
|
||||||
|
|
||||||
|
public EquationBuilder(long testValue, params Operator[] operatorOptions)
|
||||||
|
{
|
||||||
|
this.TestValue = testValue;
|
||||||
|
this.operands = new List<int>();
|
||||||
|
this.operatorOptions = new List<Operator>();
|
||||||
|
this.operatorOptions.AddRange(operatorOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddOperand(int operand)
|
||||||
|
{
|
||||||
|
this.operands.Add(operand);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Equation> BuildEquationCandidates(Equation e)
|
||||||
|
{
|
||||||
|
List<Equation> resultEquations = new List<Equation>();
|
||||||
|
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<long>()
|
||||||
|
.TransformData((List<long> 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<long>()
|
||||||
|
.TransformData((List<long> 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();
|
||||||
|
}
|
||||||
|
}
|
24
Level7/Program.cs
Normal file
24
Level7/Program.cs
Normal file
@ -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!");
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user