From 950922d6e8136c4936cf9577d3db3ec8b9f25d37 Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Sat, 9 Dec 2023 00:43:17 -0600 Subject: [PATCH] feat: solve part 2 --- 08/HauntedWasteland.Tests/MapTests.cs | 54 ++++++++++++++- 08/HauntedWasteland/Program.cs | 95 ++++++++++++++++++++++++++- 2 files changed, 143 insertions(+), 6 deletions(-) diff --git a/08/HauntedWasteland.Tests/MapTests.cs b/08/HauntedWasteland.Tests/MapTests.cs index 92462b2..8b307f7 100644 --- a/08/HauntedWasteland.Tests/MapTests.cs +++ b/08/HauntedWasteland.Tests/MapTests.cs @@ -10,12 +10,31 @@ public class MapTests } [Theory] - [MemberData(nameof(TestData.CountTurnsTestData), MemberType = typeof(TestData))] + [MemberData(nameof(TestData.CountStepsTestData), MemberType = typeof(TestData))] public void CountStepsToZ_WhenGivenMap_ItShouldReturnNumberOfSteps(string[] input, int expected) { Map.Parse(input).CountStepsToZ().Should().Be(expected); } + [Theory] + [MemberData(nameof(TestData.CountStepsToAllZNodesData), MemberType = typeof(TestData))] + public void CountStepsToAllZNodes_WhenGivenMap_ItShouldReturnNumberOfSteps(string[] input, long expected) + { + Map.Parse(input).CountStepsToAllZNodes().Should().Be(expected); + } + + [Fact] + public void FindPrimeFactors_WhenGivenNumber_ItShouldReturnPrimeFactors() + { + new Map([], []).FindPrimeFactors(11911).Should().BeEquivalentTo([43, 277]); + } + + [Fact] + public void FindLeastCommonMultiple_WhenGivenNumbers_ItShouldReturnLeastCommonMultiple() + { + new Map([], []).FindLeastCommonMultiple([16343, 11911, 20221, 21883, 13019, 19667]).Should().Be(13524038372771); + } + public static class TestData { private static readonly string[] MapInput = @@ -31,7 +50,9 @@ public class MapTests "ZZZ = (ZZZ, ZZZ)", ]; - public static IEnumerable CountTurnsTestData => + private static readonly string[] Input = File.ReadAllLines("INPUT.txt"); + + public static IEnumerable CountStepsTestData => new List { new object[] @@ -41,11 +62,38 @@ public class MapTests }, new object[] { - File.ReadAllLines("INPUT.txt"), + Input, 13019 } }; + public static IEnumerable CountStepsToAllZNodesData => + new List + { + new object[] + { + new string[] + { + "LR", + "", + "11A = (11B, XXX)", + "11B = (XXX, 11Z)", + "11Z = (11B, XXX)", + "22A = (22B, XXX)", + "22B = (22C, 22C)", + "22C = (22Z, 22Z)", + "22Z = (22B, 22B)", + "XXX = (XXX, XXX)", + }, + 6 + }, + new object[] + { + Input, + 13524038372771 + } + }; + public static IEnumerable ParseMapTestData => new List { diff --git a/08/HauntedWasteland/Program.cs b/08/HauntedWasteland/Program.cs index 9f7c8a1..98ce232 100644 --- a/08/HauntedWasteland/Program.cs +++ b/08/HauntedWasteland/Program.cs @@ -18,18 +18,22 @@ public class Program return -2; } + var isPart2 = args.Length > 1 && args[1] == "part2"; var input = await File.ReadAllLinesAsync(args[0]); var stopwatch = new Stopwatch(); stopwatch.Start(); - var result = Map.Parse(input).CountStepsToZ(); + var map = Map.Parse(input); + var result = isPart2 + ? map.CountStepsToAllZNodes() + : map.CountStepsToZ(); stopwatch.Stop(); - Console.WriteLine($"The number of steps to Z is {result}. ({stopwatch.ElapsedMilliseconds}ms)"); + Console.WriteLine($"The number of steps is {result}. ({stopwatch.ElapsedMilliseconds}ms)"); - return result; + return (int)result; } } @@ -70,6 +74,91 @@ public class Map( return steps; } + + // This method finds the prime factors of a given number. + // It takes an integer 'number' as input and returns a list of prime factors. + + public List FindPrimeFactors(long number) + { + var factors = new List(); + + // Start with the smallest prime number, 2. + var divisor = 2; + + // Continue until the number is reduced to 2 or less. + while (number >= 2) + { + // If the number is divisible by the current divisor, + if (number % divisor == 0) + { + // Add the divisor to the list of factors. + factors.Add(divisor); + // Divide the number by the divisor to reduce it. + number /= divisor; + } + else + { + // If the number is not divisible by the current divisor, increment the divisor. + divisor++; + } + } + + return factors; + } + + public long FindLeastCommonMultiple(List numbers) + { + var primeFactors = numbers.Select(FindPrimeFactors).ToList(); + + var uniquePrimeFactors = primeFactors + .SelectMany(pf => pf) + .Distinct() + .ToList(); + + var maxPrimeFactors = uniquePrimeFactors + .Select(upf => primeFactors.Max(pf => pf.Count(f => f == upf))) + .ToList(); + + var result = uniquePrimeFactors + .Zip(maxPrimeFactors) + .Aggregate( + (long)1, + (acc, b) => + // b.First is the prime factor + // b.Second is the number of times it occurs + acc * (long)Math.Pow(b.First, b.Second) + ); + + return result; + } + + public long CountStepsToAllZNodes() + { + var startNodes = Nodes.Where(n => n.Current.EndsWith('A')).ToList(); + var nodeSteps = new List(); + + foreach (var startNode in startNodes) + { + var current = startNode; + var steps = 0; + + while (current.Current.EndsWith('Z') is false) + { + var next = Turns[steps % Turns.Count] switch + { + 'R' => current.Right, + 'L' => current.Left, + _ => throw new Exception("Invalid turn") + }; + current = Nodes.First(n => n.Current == next); + steps++; + } + + nodeSteps.Add(steps); + } + + return FindLeastCommonMultiple(nodeSteps); + } } public class Node(