feat: solve day 7 part 1 and part 2
This commit is contained in:
@@ -0,0 +1,87 @@
|
|||||||
|
namespace BridgeRepair.Tests;
|
||||||
|
|
||||||
|
public class EquationTests
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
[MethodDataSource(nameof(GeneratePossibleOperatorConfigurationsTestCases))]
|
||||||
|
public async Task GeneratePossibleOperatorConfigurations_WhenCalled_ItShouldGenerateExpectedCombinations(GeneratePossibleOperatorConfigurationsTestCase testCase)
|
||||||
|
{
|
||||||
|
var result = new Equation(testCase.TargetValue, testCase.Numbers).GeneratePossibleOperatorConfigurations().ToList();
|
||||||
|
|
||||||
|
await Assert.That(result).IsEquivalentTo(testCase.ExpectedCombinations);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[MethodDataSource(nameof(EvaluateTestCases))]
|
||||||
|
public async Task Evaluate_WhenCalled_ItShouldReturnExpectedValue(EvaluateTestCase testCase)
|
||||||
|
{
|
||||||
|
var result = new Equation(testCase.TargetValue, testCase.Numbers).Evaluate(testCase.Combinations);
|
||||||
|
|
||||||
|
await Assert.That(result).IsEquivalentTo(testCase.ExpectedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[MethodDataSource(nameof(IsPossibleTestCases))]
|
||||||
|
public async Task IsPossible_WhenCalled_ItShouldReturnExpectedValue(IsPossibleTestCase testCase)
|
||||||
|
{
|
||||||
|
var result = new Equation(testCase.TargetValue, testCase.Numbers).IsPossible();
|
||||||
|
|
||||||
|
await Assert.That(result).IsEquivalentTo(testCase.ExpectedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task IsPossible_WhenCalledWithPart2_ItShouldReturnExpectedValue()
|
||||||
|
{
|
||||||
|
// TODO: Make data driven test
|
||||||
|
var resultOne = new Equation(156, [15, 6]).IsPossible(isPart2: true);
|
||||||
|
var resultTwo = new Equation(7290, [6, 8, 6, 15]).IsPossible(isPart2: true);
|
||||||
|
var resultThree = new Equation(192, [17, 8, 14]).IsPossible(isPart2: true);
|
||||||
|
|
||||||
|
await Assert.That(resultOne).IsTrue();
|
||||||
|
await Assert.That(resultTwo).IsTrue();
|
||||||
|
await Assert.That(resultThree).IsTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<Func<IsPossibleTestCase>> IsPossibleTestCases()
|
||||||
|
{
|
||||||
|
yield return () => new(190, [10, 19], true);
|
||||||
|
yield return () => new(3267, [81, 40, 27], true);
|
||||||
|
yield return () => new(83, [17, 5], false);
|
||||||
|
yield return () => new(156, [15, 6], false);
|
||||||
|
yield return () => new(7290, [6, 8, 6, 15], false);
|
||||||
|
yield return () => new(161011, [16, 10, 13], false);
|
||||||
|
yield return () => new(192, [17, 8, 14], false);
|
||||||
|
yield return () => new(21037, [9, 7, 18, 13], false);
|
||||||
|
yield return () => new(292, [11, 6, 16, 20], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public record IsPossibleTestCase(long TargetValue, List<long> Numbers, bool ExpectedValue);
|
||||||
|
|
||||||
|
public static IEnumerable<Func<EvaluateTestCase>> EvaluateTestCases()
|
||||||
|
{
|
||||||
|
yield return () => new(190, [10, 19], ['+'], 29);
|
||||||
|
yield return () => new(190, [10, 19], ['*'], 190);
|
||||||
|
yield return () => new(3267, [81, 40, 27], ['*', '+'], 3267);
|
||||||
|
yield return () => new(292, [11, 6, 16, 20], ['+', '*', '+'], 292);
|
||||||
|
}
|
||||||
|
|
||||||
|
public record EvaluateTestCase(long TargetValue, List<long> Numbers, char[] Combinations, long ExpectedValue);
|
||||||
|
|
||||||
|
public static IEnumerable<Func<GeneratePossibleOperatorConfigurationsTestCase>> GeneratePossibleOperatorConfigurationsTestCases()
|
||||||
|
{
|
||||||
|
yield return () => new(190, [10, 19], [['+'], ['*']]);
|
||||||
|
yield return () => new(3267, [81, 40, 27], [['+', '+'], ['*', '+'], ['+', '*'], ['*', '*']]);
|
||||||
|
yield return () => new(292, [11, 6, 16, 20], [
|
||||||
|
['+', '+', '+'],
|
||||||
|
['*', '+', '+'],
|
||||||
|
['+', '*', '+'],
|
||||||
|
['*', '*', '+'],
|
||||||
|
['+', '+', '*'],
|
||||||
|
['*', '+', '*'],
|
||||||
|
['+', '*', '*'],
|
||||||
|
['*', '*', '*'],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public record GeneratePossibleOperatorConfigurationsTestCase(long TargetValue, List<long> Numbers, List<char[]> ExpectedCombinations);
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
namespace BridgeRepair.Tests;
|
||||||
|
|
||||||
|
public class PuzzleParserTests
|
||||||
|
{
|
||||||
|
private readonly PuzzleParser _parser = new();
|
||||||
|
private readonly string[] _exampleInput = [
|
||||||
|
"190: 10 19",
|
||||||
|
"3267: 81 40 27",
|
||||||
|
"83: 17 5",
|
||||||
|
"156: 15 6",
|
||||||
|
"7290: 6 8 6 15",
|
||||||
|
"161011: 16 10 13",
|
||||||
|
"192: 17 8 14",
|
||||||
|
"21037: 9 7 18 13",
|
||||||
|
"292: 11 6 16 20",
|
||||||
|
];
|
||||||
|
|
||||||
|
private async Task<string[]> GetPuzzleInput()
|
||||||
|
{
|
||||||
|
return await File.ReadAllLinesAsync(Path.Combine(AppContext.BaseDirectory, "INPUT.txt"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task SolutionPartOne_WhenGivenExampleInput_ItShouldReturnExpectedValue()
|
||||||
|
{
|
||||||
|
var result = _parser.Parse(_exampleInput).Where(e => e.IsPossible()).Sum(e => e.TestValue);
|
||||||
|
|
||||||
|
await Assert.That(result).IsEqualTo(3749);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task SolutionPartOne_WhenGivenPuzzleInput_ItShouldReturnExpectedValue()
|
||||||
|
{
|
||||||
|
var input = await GetPuzzleInput();
|
||||||
|
var result = _parser.Parse(input).Where(e => e.IsPossible()).Sum(e => e.TestValue);
|
||||||
|
|
||||||
|
await Assert.That(result).IsEqualTo(14711933466277);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task SolutionPartTwo_WhenGivenExampleInput_ItShouldReturnExpectedValue()
|
||||||
|
{
|
||||||
|
var result = _parser.Parse(_exampleInput).Where(e => e.IsPossible(isPart2: true)).Sum(e => e.TestValue);
|
||||||
|
|
||||||
|
await Assert.That(result).IsEqualTo(11387);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task SolutionPartTwo_WhenGivenPuzzleInput_ItShouldReturnExpectedValue()
|
||||||
|
{
|
||||||
|
var input = await GetPuzzleInput();
|
||||||
|
var result = _parser.Parse(input).Where(e => e.IsPossible(isPart2: true)).Sum(e => e.TestValue);
|
||||||
|
|
||||||
|
await Assert.That(result).IsEqualTo(286580387663654);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Parse_WhenGivenExampleInput_ItShouldReturnExpectedList()
|
||||||
|
{
|
||||||
|
var result = _parser.Parse(_exampleInput);
|
||||||
|
|
||||||
|
await Assert.That(result).IsEquivalentTo(new List<Equation>()
|
||||||
|
{
|
||||||
|
new(190, [10, 19]),
|
||||||
|
new(3267, [81, 40, 27]),
|
||||||
|
new(83, [17, 5]),
|
||||||
|
new(156, [15, 6]),
|
||||||
|
new(7290, [6, 8, 6, 15]),
|
||||||
|
new(161011, [16, 10, 13]),
|
||||||
|
new(192, [17, 8, 14]),
|
||||||
|
new(21037, [9, 7, 18, 13]),
|
||||||
|
new(292, [11, 6, 16, 20]),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
namespace BridgeRepair;
|
||||||
|
|
||||||
|
// TODO: Look at what the public API should be here.
|
||||||
|
class Equation(long testValue, List<long> numbers)
|
||||||
|
{
|
||||||
|
public readonly long TestValue = testValue;
|
||||||
|
|
||||||
|
public bool IsPossible(bool isPart2 = false)
|
||||||
|
{
|
||||||
|
var configs = GeneratePossibleOperatorConfigurations(isPart2).ToList();
|
||||||
|
return configs.Select(Evaluate).Any(result => result == TestValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long Evaluate(char[] operators)
|
||||||
|
{
|
||||||
|
var result = numbers[0];
|
||||||
|
|
||||||
|
for (var i = 0; i < operators.Length; i++)
|
||||||
|
{
|
||||||
|
var currentOperator = operators[i];
|
||||||
|
var number = numbers[i + 1];
|
||||||
|
|
||||||
|
if (currentOperator is '+')
|
||||||
|
{
|
||||||
|
result += number;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentOperator is '*')
|
||||||
|
{
|
||||||
|
result *= number;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = long.Parse(result + number.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<char[]> GeneratePossibleOperatorConfigurations(bool isPart2 = false)
|
||||||
|
{
|
||||||
|
// TODO: make it possible to pass is operators we can use.
|
||||||
|
var numberOfPositions = numbers.Count - 1;
|
||||||
|
var config = new char[numberOfPositions];
|
||||||
|
var numOfOperators = isPart2 ? 3 : 2;
|
||||||
|
var numberOfPossibleConfigurations = Math.Pow(numOfOperators, numberOfPositions);
|
||||||
|
|
||||||
|
for (var i = 0; i < numberOfPossibleConfigurations; i++)
|
||||||
|
{
|
||||||
|
var j = 0;
|
||||||
|
|
||||||
|
while (j < numberOfPositions)
|
||||||
|
{
|
||||||
|
var currentOperator = config[j];
|
||||||
|
|
||||||
|
if (currentOperator is '+')
|
||||||
|
{
|
||||||
|
config[j] = '*';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPart2 && currentOperator is '*')
|
||||||
|
{
|
||||||
|
config[j] = '|';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
config[j] = '+';
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return config.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
using BridgeRepair;
|
||||||
|
|
||||||
if (args.Length is 0)
|
if (args.Length is 0)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Please provide a path to the input file.");
|
Console.WriteLine("Please provide a path to the input file.");
|
||||||
@@ -18,7 +20,9 @@ var input = await File.ReadAllLinesAsync(args[0]);
|
|||||||
var stopwatch = new Stopwatch();
|
var stopwatch = new Stopwatch();
|
||||||
stopwatch.Start();
|
stopwatch.Start();
|
||||||
|
|
||||||
// TODO: Implement solution
|
var result = new PuzzleParser().Parse(input)
|
||||||
|
.Where(e => e.IsPossible(isPart2))
|
||||||
|
.Sum(e => e.TestValue);
|
||||||
|
|
||||||
stopwatch.Stop();
|
stopwatch.Stop();
|
||||||
Console.WriteLine($". ({stopwatch.ElapsedMilliseconds}ms)");
|
Console.WriteLine($"The sum of the test value for possible equations is {result}. ({stopwatch.ElapsedMilliseconds}ms)");
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
namespace BridgeRepair;
|
||||||
|
|
||||||
|
class PuzzleParser
|
||||||
|
{
|
||||||
|
public List<Equation> Parse(string[] input)
|
||||||
|
{
|
||||||
|
return input.Select(s => s.ToEquation()).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
namespace BridgeRepair;
|
||||||
|
|
||||||
|
static class StringExtensions
|
||||||
|
{
|
||||||
|
public static Equation ToEquation(this string line)
|
||||||
|
{
|
||||||
|
var parts = line.Split(':');
|
||||||
|
var testValue = long.Parse(parts[0]);
|
||||||
|
var numbers = parts[1].Split(" ", StringSplitOptions.RemoveEmptyEntries)
|
||||||
|
.Select(long.Parse)
|
||||||
|
.ToList();
|
||||||
|
return new(testValue, numbers);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -50,3 +50,4 @@ dotnet build
|
|||||||
| 04 | [Problem](./04/PROBLEM.md) | [Solution](./04/CeresSearch/) | This was fun! Definitely was able to see the growth in my abilities here. |
|
| 04 | [Problem](./04/PROBLEM.md) | [Solution](./04/CeresSearch/) | This was fun! Definitely was able to see the growth in my abilities here. |
|
||||||
| 05 | [Problem](./05/PROBLEM.md) | [Solution](./05/PrintQueue/) | A graph to the rescue! |
|
| 05 | [Problem](./05/PROBLEM.md) | [Solution](./05/PrintQueue/) | A graph to the rescue! |
|
||||||
| 06 | [Problem](./06/PROBLEM.md) | [Solution](./06/GuardGallivant/) | I kind of brute forced part two... |
|
| 06 | [Problem](./06/PROBLEM.md) | [Solution](./06/GuardGallivant/) | I kind of brute forced part two... |
|
||||||
|
| 07 | [Problem](./07/PROBLEM.md) | [Solution](./07/BridgeRepair/) | Not perfect or pretty, but good enough |
|
||||||
|
|||||||
Reference in New Issue
Block a user