mirror of
https://github.com/jcreek/advent-of-code.git
synced 2026-07-13 11:13:47 +00:00
147 lines
3.9 KiB
C#
147 lines
3.9 KiB
C#
namespace AOC.Tests.Y2024;
|
|
|
|
[TestFixture]
|
|
[Parallelizable(ParallelScope.All)]
|
|
public class Day07
|
|
{
|
|
[SetUp]
|
|
public void Setup()
|
|
{
|
|
realData = File.ReadAllLines(Path.Combine(TestContext.CurrentContext.TestDirectory, "Y2024", "Data",
|
|
$"{GetThisClassName()}.dat"));
|
|
}
|
|
|
|
protected string GetThisClassName() { return GetType().Name; }
|
|
private string[] realData;
|
|
|
|
private bool CanAchieveTarget(long[] remainingNumbers, long testValue, long currentIndex, long currentTotal)
|
|
{
|
|
// Base case: if we've used all numbers, check if the total equals the test value
|
|
if (currentIndex == remainingNumbers.Length)
|
|
{
|
|
return currentTotal == testValue;
|
|
}
|
|
|
|
// Try adding the next number
|
|
if (CanAchieveTarget(remainingNumbers, testValue, currentIndex + 1,
|
|
currentTotal + remainingNumbers[currentIndex]))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Try multiplying by the next number
|
|
if (CanAchieveTarget(remainingNumbers, testValue, currentIndex + 1,
|
|
currentTotal * remainingNumbers[currentIndex]))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// If neither operation works, return false
|
|
return false;
|
|
}
|
|
|
|
private bool CanAchieveTargetWithConcatenation(long[] remainingNumbers, long testValue, long currentIndex,
|
|
long currentTotal)
|
|
{
|
|
// If none of the three operations works, return false
|
|
return false;
|
|
}
|
|
|
|
|
|
private (bool, long) CanEquationBeTrue(string equation, bool enableConcatenation = false)
|
|
{
|
|
try
|
|
{
|
|
// Split the equation into its parts
|
|
string[] parts = equation.Split(": ");
|
|
long testValue = long.Parse(parts[0]);
|
|
long[] remainingNumbers = parts[1].Split(" ").Select(long.Parse).ToArray();
|
|
|
|
if (enableConcatenation)
|
|
{
|
|
bool result = CanAchieveTargetWithConcatenation(remainingNumbers, testValue, 1, remainingNumbers[0]);
|
|
|
|
return (result, testValue);
|
|
}
|
|
else
|
|
{
|
|
// Start recursing through the numbers
|
|
bool result = CanAchieveTarget(remainingNumbers, testValue, 1, remainingNumbers[0]);
|
|
|
|
return (result, testValue);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine(equation, ex);
|
|
throw;
|
|
}
|
|
}
|
|
|
|
[TestCase(@"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", 3749)]
|
|
[TestCase(null, 1620690235709)] // The actual answer
|
|
public void Part1(string? input, long? expected)
|
|
{
|
|
string[] lines = input != null ? input.Split("\n") : realData;
|
|
|
|
long result = 0;
|
|
|
|
foreach (string line in lines)
|
|
{
|
|
(bool, long) response = CanEquationBeTrue(line);
|
|
if (response.Item1)
|
|
{
|
|
result += response.Item2;
|
|
}
|
|
}
|
|
|
|
if (expected != null)
|
|
{
|
|
Assert.That(result, Is.EqualTo(expected.Value));
|
|
}
|
|
|
|
Console.WriteLine($"Part 1: {result}");
|
|
}
|
|
|
|
[TestCase(@"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", 11387)]
|
|
[TestCase(null, 1783)] // The actual answer
|
|
public void Part2(string? input, long? expected)
|
|
{
|
|
string[] lines = input != null ? input.Split("\n") : realData;
|
|
|
|
long result = 0;
|
|
|
|
foreach (string line in lines)
|
|
{
|
|
(bool, long) response = CanEquationBeTrue(line, true);
|
|
if (response.Item1)
|
|
{
|
|
result += response.Item2;
|
|
}
|
|
}
|
|
|
|
if (expected != null)
|
|
{
|
|
Assert.That(result, Is.EqualTo(expected.Value));
|
|
}
|
|
|
|
Console.WriteLine($"Part 2: {result}");
|
|
}
|
|
}
|