implement level1 and level2
This commit is contained in:
212
Level2/DataStreamConstraintVerifier.cs
Normal file
212
Level2/DataStreamConstraintVerifier.cs
Normal file
@@ -0,0 +1,212 @@
|
||||
namespace AoC24;
|
||||
|
||||
using AoC24.Common;
|
||||
using AoCLevelInputProvider;
|
||||
using Parsing;
|
||||
using Parsing.Schema;
|
||||
|
||||
public class DataStreamConstraintVerifier<T>
|
||||
{
|
||||
public interface IIntegerDataStreamConstraint
|
||||
{
|
||||
public int Verify(T leftValue, T rightValue);
|
||||
}
|
||||
|
||||
private class DefaultTrendChecker : IIntegerDataStreamConstraint
|
||||
{
|
||||
public int Verify(T leftValue, T rightValue)
|
||||
{
|
||||
return string.Compare(leftValue?.ToString(), rightValue?.ToString()) < 0 ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
private class DefaultDistanceChecker : IIntegerDataStreamConstraint
|
||||
{
|
||||
public int Verify(T leftValue, T rightValue)
|
||||
{
|
||||
return string.Compare(leftValue?.ToString(), rightValue?.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private List<T> dataSet = new List<T>();
|
||||
private int distanceLowerLimit = 0;
|
||||
private int distanceUpperLimit = 1;
|
||||
private int faultTolerance = int.MaxValue;
|
||||
private int allowedIgnores = 0;
|
||||
private int numFaults = 0;
|
||||
private bool checkFaults = false;
|
||||
|
||||
private IIntegerDataStreamConstraint trendChecker = new DefaultTrendChecker();
|
||||
private IIntegerDataStreamConstraint distanceChecker = new DefaultDistanceChecker();
|
||||
|
||||
// compute a trend value between two items in the dataset
|
||||
// the same trend has to be returned by all checks for the constraint to pass
|
||||
public DataStreamConstraintVerifier<T> WithTrendChecker(IIntegerDataStreamConstraint trendChecker)
|
||||
{
|
||||
this.trendChecker = trendChecker;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DataStreamConstraintVerifier<T> OnData(List<T> dataSet)
|
||||
{
|
||||
this.dataSet = dataSet;
|
||||
return this;
|
||||
}
|
||||
|
||||
// set number of faults that get ignored until check is considered failed
|
||||
public DataStreamConstraintVerifier<T> WithFaultTolerance(int faultTolerance)
|
||||
{
|
||||
if(this.allowedIgnores > 0)
|
||||
{
|
||||
throw new Exception("Cannot enable fault tolerance along with allowed ignores!");
|
||||
}
|
||||
this.faultTolerance = faultTolerance;
|
||||
this.checkFaults = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
// set number of faults that get ignored until check is considered failed
|
||||
public DataStreamConstraintVerifier<T> WithAllowedIgnores(int allowedIgnores)
|
||||
{
|
||||
if(this.checkFaults)
|
||||
{
|
||||
throw new Exception("Cannot enable allowed ignores along with fault tolerance!");
|
||||
}
|
||||
this.allowedIgnores = allowedIgnores;
|
||||
return this;
|
||||
}
|
||||
|
||||
// set specific limits for the distance checks
|
||||
public DataStreamConstraintVerifier<T> WithDistanceLimits(int lowerLimit, int upperLimit)
|
||||
{
|
||||
this.distanceLowerLimit = lowerLimit;
|
||||
this.distanceUpperLimit = upperLimit;
|
||||
return this;
|
||||
}
|
||||
|
||||
// compute a distance value between two items in the dataset
|
||||
// the distance returned by all checks has to be within distance limits for constraint to pass
|
||||
public DataStreamConstraintVerifier<T> WithDistanceChecker(IIntegerDataStreamConstraint distanceChecker)
|
||||
{
|
||||
this.distanceChecker = distanceChecker;
|
||||
return this;
|
||||
}
|
||||
|
||||
private int TranslateIndex(int index, List<int> indicesToIgnore)
|
||||
{
|
||||
var newIndex = index;
|
||||
foreach(var value in indicesToIgnore)
|
||||
{
|
||||
if(value <= index)
|
||||
{
|
||||
newIndex++;
|
||||
}
|
||||
}
|
||||
return newIndex;
|
||||
}
|
||||
|
||||
private bool VerifyDistance(int remainingAllowedIgnores, List<int> indicesToIgnore)
|
||||
{
|
||||
for(int i = 0; i < (this.dataSet.Count-indicesToIgnore.Count-1); i++)
|
||||
{
|
||||
T comparisonLeft = this.dataSet[TranslateIndex(i,indicesToIgnore)];
|
||||
T comparisonRight = this.dataSet[TranslateIndex(i+1,indicesToIgnore)];
|
||||
int distance = this.distanceChecker.Verify(comparisonLeft, comparisonRight);
|
||||
if(distance < this.distanceLowerLimit || distance > this.distanceUpperLimit)
|
||||
{
|
||||
this.numFaults++;
|
||||
// small optimization:
|
||||
if (!this.checkFaults || this.numFaults > this.faultTolerance)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool VerifyTrend(int remainingAllowedIgnores, List<int> indicesToIgnore)
|
||||
{
|
||||
T firstComparisonLeft = this.dataSet[TranslateIndex(0,indicesToIgnore)];
|
||||
T firstComparisonRight = this.dataSet[TranslateIndex(1,indicesToIgnore)];
|
||||
int initialTrend = this.trendChecker.Verify(firstComparisonLeft, firstComparisonRight);
|
||||
|
||||
|
||||
for(int i = 0; i < (this.dataSet.Count-indicesToIgnore.Count-1); i++)
|
||||
{
|
||||
T comparisonLeft = this.dataSet[TranslateIndex(i,indicesToIgnore)];
|
||||
T comparisonRight = this.dataSet[TranslateIndex(i+1,indicesToIgnore)];
|
||||
int trend = this.trendChecker.Verify(comparisonLeft, comparisonRight);
|
||||
if(initialTrend != trend)
|
||||
{
|
||||
this.numFaults++;
|
||||
// small optimization:
|
||||
if (!this.checkFaults || this.numFaults > this.faultTolerance)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool Verify(int remainingAllowedIgnores, List<int> indicesToIgnore)
|
||||
{
|
||||
if(remainingAllowedIgnores > 0)
|
||||
{
|
||||
bool success = this.Verify(0, indicesToIgnore);
|
||||
if (success)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
for(int i = 0; i < this.dataSet.Count; i++)
|
||||
{
|
||||
if(indicesToIgnore.Contains(i))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
List<int> newIndicesToIgnore = new List<int>();
|
||||
newIndicesToIgnore.AddRange(indicesToIgnore);
|
||||
newIndicesToIgnore.Add(i);
|
||||
success = this.Verify(remainingAllowedIgnores-1, newIndicesToIgnore);
|
||||
if (success)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.numFaults = 0;
|
||||
bool success = true;
|
||||
if(this.distanceChecker != null)
|
||||
{
|
||||
success = this.VerifyDistance(this.allowedIgnores, indicesToIgnore);
|
||||
}
|
||||
if (!success || (this.checkFaults && this.numFaults > this.faultTolerance))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(this.trendChecker != null)
|
||||
{
|
||||
success = this.VerifyTrend(this.allowedIgnores, indicesToIgnore);
|
||||
}
|
||||
if (this.checkFaults && this.numFaults > this.faultTolerance)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Verify()
|
||||
{
|
||||
return this.Verify(this.allowedIgnores, new List<int>());
|
||||
}
|
||||
}
|
||||
14
Level2/Level2.csproj
Normal file
14
Level2/Level2.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>
|
||||
93
Level2/Level2Solver.cs
Normal file
93
Level2/Level2Solver.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
namespace AoC24;
|
||||
|
||||
using AoC24.Common;
|
||||
using AoCLevelInputProvider;
|
||||
using Parsing;
|
||||
using Parsing.Schema;
|
||||
|
||||
public class Level2Solver : LevelSolverBase
|
||||
{
|
||||
public override int LevelNumber
|
||||
{
|
||||
get { return 2; }
|
||||
}
|
||||
|
||||
protected override InputSchemaBuilder DefineInputSchema(InputSchemaBuilder schemaBuilder)
|
||||
{
|
||||
return schemaBuilder
|
||||
.Repeat()
|
||||
.Expect(InputType.Integer)
|
||||
.EndRepetition();
|
||||
}
|
||||
|
||||
private class MyDistanceChecker : DataStreamConstraintVerifier<int>.IIntegerDataStreamConstraint
|
||||
{
|
||||
public int Verify(int leftValue, int rightValue)
|
||||
{
|
||||
return Math.Abs(leftValue - rightValue);
|
||||
}
|
||||
}
|
||||
|
||||
private class MyTrendChecker : DataStreamConstraintVerifier<int>.IIntegerDataStreamConstraint
|
||||
{
|
||||
public int Verify(int leftValue, int rightValue)
|
||||
{
|
||||
return (leftValue - rightValue) < 0 ? -1 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
public override string SolveFirstStar()
|
||||
{
|
||||
var data = this.GetData()
|
||||
.AsListRows<int>();
|
||||
|
||||
var distanceChecker = new MyDistanceChecker();
|
||||
|
||||
var trendChecker = new MyTrendChecker();
|
||||
|
||||
var verifier = new DataStreamConstraintVerifier<int>()
|
||||
.WithDistanceChecker(distanceChecker)
|
||||
.WithDistanceLimits(1, 3)
|
||||
.WithTrendChecker(trendChecker);
|
||||
|
||||
int numSafeReports = 0;
|
||||
|
||||
foreach(var row in data)
|
||||
{
|
||||
if(verifier.OnData(row).Verify())
|
||||
{
|
||||
numSafeReports++;
|
||||
}
|
||||
}
|
||||
|
||||
return numSafeReports.ToString();
|
||||
}
|
||||
|
||||
public override string SolveSecondStar()
|
||||
{
|
||||
var data = this.GetData()
|
||||
.AsListRows<int>();
|
||||
|
||||
var distanceChecker = new MyDistanceChecker();
|
||||
|
||||
var trendChecker = new MyTrendChecker();
|
||||
|
||||
var verifier = new DataStreamConstraintVerifier<int>()
|
||||
.WithDistanceChecker(distanceChecker)
|
||||
.WithDistanceLimits(1, 3)
|
||||
.WithTrendChecker(trendChecker)
|
||||
.WithAllowedIgnores(1);
|
||||
|
||||
int numSafeReports = 0;
|
||||
|
||||
foreach(var row in data)
|
||||
{
|
||||
if(verifier.OnData(row).Verify())
|
||||
{
|
||||
numSafeReports++;
|
||||
}
|
||||
}
|
||||
|
||||
return numSafeReports.ToString();
|
||||
}
|
||||
}
|
||||
24
Level2/Program.cs
Normal file
24
Level2/Program.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
// See https://aka.ms/new-console-template for more information
|
||||
|
||||
using AoC24;
|
||||
|
||||
var levelSolver = new Level2Solver();
|
||||
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!");
|
||||
}
|
||||
Reference in New Issue
Block a user