diff --git a/AdvendOfCode.Runner/Program.cs b/AdvendOfCode.Runner/Program.cs index 241e5b7..dee3346 100644 --- a/AdvendOfCode.Runner/Program.cs +++ b/AdvendOfCode.Runner/Program.cs @@ -7,9 +7,9 @@ InputReader inputReader = new() //IsDebug = true }; -//inputReader.SetInputByChallange(3); +inputReader.SetInputByChallange(14); -IChallange challange = new Day15(inputReader); +IChallange challange = new Day14(inputReader); Console.WriteLine($"Part 1: {await challange.GetSolutionPart1()}"); diff --git a/AdventOfCode.Solutions/2023/Day 14/Day14.cs b/AdventOfCode.Solutions/2023/Day 14/Day14.cs index 3fc8218..eacf455 100644 --- a/AdventOfCode.Solutions/2023/Day 14/Day14.cs +++ b/AdventOfCode.Solutions/2023/Day 14/Day14.cs @@ -1,9 +1,6 @@ using AdventOfCode.Core; using AdventOfCode.Core.Shared.Grid; -using System.Collections.Generic; -using System.Runtime.ExceptionServices; using System.Text; -using System.Threading.Tasks.Dataflow; namespace AdventOfCode.Solutions._2023 { @@ -19,104 +16,57 @@ namespace AdventOfCode.Solutions._2023 bolders = MoveUp(bolders, cubes); - return bolders.Sum(bolder => grid.Rows - bolder.Y).ToString(); + return CalculateLoad(CreateStringMap(bolders, cubes, grid.Rows, grid.Columns).Split(':'), grid.Rows); } public async Task GetSolutionPart2() { int maxCycles = 1_000_000_000; Dictionary mapStates = []; - bool foundLoop = false; - + Grid grid = await _inputReader.ReadToGrid(); HashSet bolders = grid.FindWithValue('O').Select(p => new Point(p.X, p.Y)).ToHashSet(); HashSet cubes = grid.FindWithValue('#').Select(p => new Point(p.X, p.Y)).ToHashSet(); - int totalBolders = bolders.Count; - - for (int currentCycle = 0; currentCycle < maxCycles; currentCycle++) + for (int currentCycle = 1; currentCycle <= maxCycles; currentCycle++) { - // ensure the state is saved - mapStates.TryAdd(CreateStringMap(bolders, cubes, grid.Rows, grid.Columns), currentCycle); - // add a test to see when we hit the right cycle for the test data - // move the boulders bolders = MoveUp(bolders, cubes); - if (bolders.Count != totalBolders) - { - Console.WriteLine($"lost boulders MoveUp at {currentCycle}, from {totalBolders} to {bolders.Count}"); - return string.Empty; - } - bolders = MoveLeft(bolders, cubes); - if (bolders.Count != totalBolders) - { - Console.WriteLine($"lost boulders MoveLeft at {currentCycle}, from {totalBolders} to {bolders.Count}"); - return string.Empty; - } - bolders = MoveDown(bolders, cubes, grid.Rows); - if (bolders.Count != totalBolders) - { - Console.WriteLine($"lost boulders MoveDown at {currentCycle}, from {totalBolders} to {bolders.Count}"); - return string.Empty; - } - bolders = MoveRight(bolders, cubes, grid.Columns); - if (bolders.Count != totalBolders) - { - Console.WriteLine($"lost boulders MoveRight at {currentCycle}, from {totalBolders} to {bolders.Count}"); - return string.Empty; - } - - // see if we found the loop, if so we continue untill the end - if (foundLoop) continue; - // see if the current layout of the platform already exists - // if so we are repeating our selfs so wel can calculate the remaining steps to get to the end. - // we might even yoink the map from the dic and use that if (mapStates.TryGetValue(CreateStringMap(bolders, cubes, grid.Rows, grid.Columns), out int prevCycle)) { - // calculate remaining cycles to the first exit point - int remainingCycles = maxCycles % (currentCycle + 1); - // set the total the first exit point - int exitMap = remainingCycles + currentCycle; + long cyclesWithoutStartCycles = maxCycles - prevCycle; + long cycleLength = currentCycle - prevCycle; - string[] lines = mapStates.First(kvp => kvp.Value == prevCycle - 1).Key.Split(':', StringSplitOptions.RemoveEmptyEntries); - int totalWeight = 0; - for (int lineIndex = 0; lineIndex < lines.Length; lineIndex++) - { - int weight = lines[lineIndex].Length, lineWeight = 0; - for (int charIndex = 0; charIndex < lines[lineIndex].Length; charIndex++) - { - if (lines[lineIndex][charIndex] is '.') - continue; - - if (lines[lineIndex][charIndex] is '#') - { - weight = lines[lineIndex].Length - charIndex - 1; - continue; - } - - if (lines[lineIndex][charIndex] is 'O') - { - lineWeight += weight; - weight--; - } - } - - totalWeight += lineWeight; - } - - return totalWeight.ToString(); + long remainingCycles = cyclesWithoutStartCycles % cycleLength; + long exitMap = remainingCycles + prevCycle; + string[] lines = mapStates.First(kvp => kvp.Value == exitMap).Key.Split(':'); + return CalculateLoad(lines, grid.Rows); } + + // ensure the state is saved + mapStates.TryAdd(CreateStringMap(bolders, cubes, grid.Rows, grid.Columns), currentCycle); } - return bolders.Sum(bolder => grid.Rows - bolder.Y).ToString(); } + private static string CalculateLoad(string[] lines, long totalRows) + { + long totalWeight = 0; + for (int lineIndex = 0; lineIndex < lines.Length; lineIndex++) + { + int bolders = lines[lineIndex].Where(c => c == 'O').Count(); + totalWeight += bolders * (totalRows - lineIndex); + } + + return totalWeight.ToString(); + } + private HashSet MoveUp(HashSet bolders, HashSet cubes) { HashSet boldersMoved = []; @@ -143,16 +93,14 @@ namespace AdventOfCode.Solutions._2023 HashSet boldersMoved = []; foreach (Point bolder in bolders.OrderByDescending(bolder => bolder.Y)) { - // current location long ySearch = bolder.Y; - while (ySearch + 1 < ySize // ensure in map - && !boldersMoved.Contains(new(bolder.X, ySearch + 1)) // check that the next tile does not have a bolder - && !cubes.Contains(new(bolder.X, ySearch + 1))) // check that the next tile has not cube + while (ySearch + 1 < ySize + && !boldersMoved.Contains(new(bolder.X, ySearch + 1)) + && !cubes.Contains(new(bolder.X, ySearch + 1))) { - ySearch++; // move to next + ySearch++; } - // something found on next location so place bolder here boldersMoved.Add(new(bolder.X, ySearch)); } @@ -164,16 +112,14 @@ namespace AdventOfCode.Solutions._2023 HashSet boldersMoved = []; foreach (Point bolder in bolders.OrderBy(bolder => bolder.X)) { - // current location long xSearch = bolder.X; - while (xSearch - 1 >= 0 // ensure in map - && !boldersMoved.Contains(new(xSearch - 1, bolder.Y)) // check that the next tile does not have a bolder - && !cubes.Contains(new(xSearch - 1, bolder.Y))) // check that the next tile has not cube + while (xSearch - 1 >= 0 + && !boldersMoved.Contains(new(xSearch - 1, bolder.Y)) + && !cubes.Contains(new(xSearch - 1, bolder.Y))) { - xSearch--; // move to next + xSearch--; } - // something found on next location so place bolder here boldersMoved.Add(new(xSearch, bolder.Y)); } @@ -185,16 +131,14 @@ namespace AdventOfCode.Solutions._2023 HashSet boldersMoved = []; foreach (Point bolder in bolders.OrderByDescending(bolder => bolder.X)) { - // current location long xSearch = bolder.X; - while (xSearch + 1 < xSize // ensure in map - && !boldersMoved.Contains(new(xSearch + 1, bolder.Y)) // check that the next tile does not have a bolder - && !cubes.Contains(new(xSearch + 1, bolder.Y))) // check that the next tile has not cube + while (xSearch + 1 < xSize + && !boldersMoved.Contains(new(xSearch + 1, bolder.Y)) + && !cubes.Contains(new(xSearch + 1, bolder.Y))) { - xSearch++; // move to next + xSearch++; } - // something found on next location so place bolder here boldersMoved.Add(new(xSearch, bolder.Y)); }