diff --git a/11/PlutonianPebbles.Tests/ObserverTests.cs b/11/PlutonianPebbles.Tests/ObserverTests.cs index cdde5d2..41c84cd 100644 --- a/11/PlutonianPebbles.Tests/ObserverTests.cs +++ b/11/PlutonianPebbles.Tests/ObserverTests.cs @@ -3,6 +3,54 @@ public class ObserverTests { private static readonly string[] ExampleInput = ["125", "17"]; + + private async Task GetPuzzleInput() + { + return await File.ReadAllTextAsync(Path.Combine(AppContext.BaseDirectory, "INPUT.txt")); + } + + [Test] + public async Task Blink_WhenCalledWithPuzzleInputAnd25Times_ItShouldReturnCorrectNumberOfStones() + { + var input = await GetPuzzleInput(); + var stones = input + .Split(" ", StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries) + .Select(Stone.From) + .ToList(); + + var observer = Observer.Of(stones); + + var result = observer.Blink(25); + + await Assert.That(result).IsEqualTo(191690); + } + + [Test] + public async Task Blink_WhenCalledWithPuzzleInputAnd75Times_ItShouldReturnCorrectNumberOfStones() + { + var input = await GetPuzzleInput(); + var stones = input + .Split(" ", StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries) + .Select(Stone.From) + .ToList(); + + var observer = Observer.Of(stones); + + var result = observer.Blink(75); + + await Assert.That(result).IsEqualTo(228651922369703); + } + + [Test] + public async Task Blink_WhenCalledWithExampleInputAnd25Times_ItShouldReturnCorrectNumberOfStones() + { + var stones = ExampleInput.Select(Stone.From).ToList(); + var observer = Observer.Of(stones); + + var result = observer.Blink(25); + + await Assert.That(result).IsEqualTo(55312); + } [Test] [MethodDataSource(nameof(BlinkTestCases))] @@ -12,14 +60,20 @@ public class ObserverTests var observer = Observer.Of(stones); var result = observer.Blink(testCase.NumberOfBlinks); - - await Assert.That(result).IsEqualTo(testCase.ExpectedLineOfStones); + + await Assert.That(result).IsEqualTo(testCase.ExpectedNumberOfStones); } public static IEnumerable> BlinkTestCases() { - yield return () => new(ExampleInput, 0, "125 17"); + yield return () => new(ExampleInput, 0, 2); + yield return () => new(ExampleInput, 1, 3); + yield return () => new(ExampleInput, 2, 4); + yield return () => new(ExampleInput, 3, 5); + yield return () => new(ExampleInput, 4, 9); + yield return () => new(ExampleInput, 5, 13); + yield return () => new(ExampleInput, 6, 22); } - public record BlinkTestCase(string[] Stones, int NumberOfBlinks, string ExpectedLineOfStones); + public record BlinkTestCase(string[] Stones, int NumberOfBlinks, long ExpectedNumberOfStones); } \ No newline at end of file diff --git a/11/PlutonianPebbles/Observer.cs b/11/PlutonianPebbles/Observer.cs new file mode 100644 index 0000000..95bb975 --- /dev/null +++ b/11/PlutonianPebbles/Observer.cs @@ -0,0 +1,45 @@ +namespace PlutonianPebbles; + +class Observer +{ + private readonly List _stones; + + private Observer(List stones) + { + _stones = stones; + } + + public static Observer Of(List stones) => new(stones); + + public long Blink(int times) + { + var stoneCounts = _stones.GroupBy(s => s) + .ToDictionary(g => g.Key, g => (long)g.Count()); + + for (var blinks = 0; blinks < times; blinks++) + { + var nextCounts = new Dictionary(); + + foreach (var (stone, count) in stoneCounts) + { + var transformed = stone.Transform(); + + foreach (var result in transformed) + { + if (nextCounts.ContainsKey(result)) + { + nextCounts[result] += count; + } + else + { + nextCounts[result] = count; + } + } + } + + stoneCounts = nextCounts; + } + + return stoneCounts.Values.Sum(); + } +} \ No newline at end of file diff --git a/11/PlutonianPebbles/Program.cs b/11/PlutonianPebbles/Program.cs index a507b35..fb9fef2 100644 --- a/11/PlutonianPebbles/Program.cs +++ b/11/PlutonianPebbles/Program.cs @@ -1,5 +1,7 @@ using System.Diagnostics; +using PlutonianPebbles; + if (args.Length is 0) { Console.WriteLine("Please provide a path to the input file."); @@ -25,69 +27,9 @@ var stones = input var observer = Observer.Of(stones); -var result = observer.Blink(25); +var times = isPart2 ? 75 : 25; + +var result = observer.Blink(times); stopwatch.Stop(); -Console.WriteLine($". ({stopwatch.ElapsedMilliseconds}ms)"); - -class Observer -{ - private readonly List _stones; - - private Observer(List stones) - { - _stones = stones; - } - - public static Observer Of(List stones) => new(stones); - - public string Blink(int times) - { - if (times < 1) - { - return string.Join(" ", _stones); - } - - return string.Empty; - } -} - -record Stone -{ - private readonly string _engravedValue; - - private Stone(string engravedValue) - { - _engravedValue = engravedValue; - } - - public static Stone From(string engraving) => new(engraving); - - public List Transform() - { - if (_engravedValue is "0") - { - return [new Stone("1")]; - } - - var hasOddNumberOfDigits = _engravedValue.Length % 2 is not 0; - - if (hasOddNumberOfDigits) - { - var engravedNumber = int.Parse(_engravedValue); - var newEngravedValue = engravedNumber * 2024; - return [new(newEngravedValue.ToString())]; - } - - var middleIndex = _engravedValue.Length / 2; - var leftDigits = _engravedValue[..middleIndex].TrimStart('0'); - var rightDigits = _engravedValue[middleIndex..].TrimStart('0'); - - return [new(leftDigits), new(rightDigits)]; - } - - public override string ToString() - { - return _engravedValue; - } -} \ No newline at end of file +Console.WriteLine($"The number of stones is {result}. ({stopwatch.ElapsedMilliseconds}ms)"); \ No newline at end of file diff --git a/11/PlutonianPebbles/Stone.cs b/11/PlutonianPebbles/Stone.cs new file mode 100644 index 0000000..0bc2173 --- /dev/null +++ b/11/PlutonianPebbles/Stone.cs @@ -0,0 +1,41 @@ +namespace PlutonianPebbles; + +record Stone +{ + private readonly string _engravedValue; + + private Stone(string engravedValue) + { + _engravedValue = engravedValue; + } + + public static Stone From(string engraving) => new(engraving); + + public List Transform() + { + if (_engravedValue is "0") + { + return [new Stone("1")]; + } + + var hasOddNumberOfDigits = _engravedValue.Length % 2 is not 0; + + if (hasOddNumberOfDigits) + { + var engravedNumber = long.Parse(_engravedValue); + var newEngravedValue = engravedNumber * 2024; + return [new(newEngravedValue.ToString())]; + } + + var middleIndex = _engravedValue.Length / 2; + var leftDigits = long.Parse(_engravedValue[..middleIndex]); + var rightDigits = long.Parse(_engravedValue[middleIndex..]); + + return [new(leftDigits.ToString()), new(rightDigits.ToString())]; + } + + public override string ToString() + { + return _engravedValue; + } +} \ No newline at end of file diff --git a/README.md b/README.md index fcf2c72..c8270b5 100644 --- a/README.md +++ b/README.md @@ -54,3 +54,4 @@ dotnet build | 08 | [Problem](./08/PROBLEM.md) | [Solution](./08/ResonantCollinearity/) | Without some help from chat I don't know where I'd be...to be fair the description kind of mislead me. | | 09 | [Problem](./09/PROBLEM.md) | [Solution](./09/DiskFragmenter/) | Doing things with indexes is error prone. | | 10 | [Problem](./10/PROBLEM.md) | [Solution](./10/HoofIt/) | I recognized the solution for this based on pattern from last year. Solved using BFS. | +| 11 | [Problem](./11/PROBLEM.md) | [Solution](./11/PlutonianPebbles/) | Dictionary > List |