From 9a529e60f1892c21e0bf6ec697f9d748e17a1567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Piotr=20Moru=C5=9B?= Date: Wed, 17 Jul 2024 12:41:22 +0200 Subject: [PATCH 1/6] First boilerplate day 12 code --- .run/Day12.run.xml | 20 ++++ AdventOfCode2023.sln | 6 ++ Day12 - Hot Springs/.vscode/launch.json | 18 ++++ Day12 - Hot Springs/.vscode/tasks.json | 21 +++++ Day12 - Hot Springs/Day12.csproj | 22 +++++ Day12 - Hot Springs/Day12Solver.cs | 38 ++++++++ Day12 - Hot Springs/Day12SolverOptions.cs | 10 ++ Day12 - Hot Springs/InputReader.cs | 109 ++++++++++++++++++++++ Day12 - Hot Springs/Program.cs | 45 +++++++++ Day12 - Hot Springs/README.md | 1 + Tests/Day12Tests.cs | 24 +++++ Tests/Inputs/Day12/example-input.txt | 6 ++ Tests/Tests.csproj | 11 ++- 13 files changed, 329 insertions(+), 2 deletions(-) create mode 100644 .run/Day12.run.xml create mode 100644 Day12 - Hot Springs/.vscode/launch.json create mode 100644 Day12 - Hot Springs/.vscode/tasks.json create mode 100644 Day12 - Hot Springs/Day12.csproj create mode 100644 Day12 - Hot Springs/Day12Solver.cs create mode 100644 Day12 - Hot Springs/Day12SolverOptions.cs create mode 100644 Day12 - Hot Springs/InputReader.cs create mode 100644 Day12 - Hot Springs/Program.cs create mode 100644 Day12 - Hot Springs/README.md create mode 100644 Tests/Day12Tests.cs create mode 100644 Tests/Inputs/Day12/example-input.txt diff --git a/.run/Day12.run.xml b/.run/Day12.run.xml new file mode 100644 index 0000000..9603656 --- /dev/null +++ b/.run/Day12.run.xml @@ -0,0 +1,20 @@ + + + + \ No newline at end of file diff --git a/AdventOfCode2023.sln b/AdventOfCode2023.sln index dbefd4f..8083a9e 100644 --- a/AdventOfCode2023.sln +++ b/AdventOfCode2023.sln @@ -41,6 +41,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Day10", "Day10 - Pipe Maze\ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Day11", "Day11 - Cosmic Expansion\Day11.csproj", "{28DC51A6-39A7-4180-B890-D5B5D0AF71EC}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Day12", "Day12 - Hot Springs\Day12.csproj", "{588B94EB-1D61-49FA-ADB2-22DD0A83A172}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -98,6 +100,10 @@ Global {28DC51A6-39A7-4180-B890-D5B5D0AF71EC}.Debug|Any CPU.Build.0 = Debug|Any CPU {28DC51A6-39A7-4180-B890-D5B5D0AF71EC}.Release|Any CPU.ActiveCfg = Release|Any CPU {28DC51A6-39A7-4180-B890-D5B5D0AF71EC}.Release|Any CPU.Build.0 = Release|Any CPU + {588B94EB-1D61-49FA-ADB2-22DD0A83A172}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {588B94EB-1D61-49FA-ADB2-22DD0A83A172}.Debug|Any CPU.Build.0 = Debug|Any CPU + {588B94EB-1D61-49FA-ADB2-22DD0A83A172}.Release|Any CPU.ActiveCfg = Release|Any CPU + {588B94EB-1D61-49FA-ADB2-22DD0A83A172}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {CE8086B8-A3E4-40E0-859F-607F95D25514} = {F6C05A63-6269-425F-B877-9E9F0BC1FC26} diff --git a/Day12 - Hot Springs/.vscode/launch.json b/Day12 - Hot Springs/.vscode/launch.json new file mode 100644 index 0000000..7b4b93c --- /dev/null +++ b/Day12 - Hot Springs/.vscode/launch.json @@ -0,0 +1,18 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Launch (my input)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + "program": "${workspaceFolder}/bin/Debug/net8.0/Day12.dll", + "args": [ + "input.txt" + ], + "cwd": "${workspaceFolder}", + "console": "internalConsole", + "stopAtEntry": false + } + ] +} diff --git a/Day12 - Hot Springs/.vscode/tasks.json b/Day12 - Hot Springs/.vscode/tasks.json new file mode 100644 index 0000000..18c16a6 --- /dev/null +++ b/Day12 - Hot Springs/.vscode/tasks.json @@ -0,0 +1,21 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "process", + "group": { + "kind": "build", + "isDefault": true + }, + "args": [ + "build", + "${workspaceFolder}/Day12.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + } + ] +} diff --git a/Day12 - Hot Springs/Day12.csproj b/Day12 - Hot Springs/Day12.csproj new file mode 100644 index 0000000..a643ece --- /dev/null +++ b/Day12 - Hot Springs/Day12.csproj @@ -0,0 +1,22 @@ + + + + Exe + net8.0 + enable + enable + AdventOfCode.Year2023.Day12 + + + + + + + + + + Always + + + + diff --git a/Day12 - Hot Springs/Day12Solver.cs b/Day12 - Hot Springs/Day12Solver.cs new file mode 100644 index 0000000..9d16a09 --- /dev/null +++ b/Day12 - Hot Springs/Day12Solver.cs @@ -0,0 +1,38 @@ +using AdventOfCode.Abstractions; + +namespace AdventOfCode.Year2023.Day12; + +public sealed class Day12Solver : DaySolver +{ + public override int Year => 2023; + public override int Day => 12; + public override string Title => "Hot Springs"; + + private readonly IReadOnlyList _rows; + + public Day12Solver(Day12SolverOptions options) : base(options) + { + var inputReader = new InputReader(options); + _rows = inputReader.ReadInput(InputLines); + } + + public Day12Solver(Action configure) + : this(DaySolverOptions.FromConfigureAction(configure)) + { + } + + public Day12Solver() : this(new Day12SolverOptions()) + { + } + + public override string SolvePart1() + { + var result = _rows.Select(r => r.Springs.Count(s => s == SpringCondition.Unknown)).Max(); + return result.ToString(); + } + + public override string SolvePart2() + { + return "UNSOLVED"; + } +} diff --git a/Day12 - Hot Springs/Day12SolverOptions.cs b/Day12 - Hot Springs/Day12SolverOptions.cs new file mode 100644 index 0000000..afd10a4 --- /dev/null +++ b/Day12 - Hot Springs/Day12SolverOptions.cs @@ -0,0 +1,10 @@ +using AdventOfCode.Abstractions; + +namespace AdventOfCode.Year2023.Day12; + +public sealed class Day12SolverOptions : DaySolverOptions +{ + public char OperationalSpringChar { get; set; } = '.'; + public char DamagedSpringChar { get; set; } = '#'; + public char UnknownSpringChar { get; set; } = '?'; +} diff --git a/Day12 - Hot Springs/InputReader.cs b/Day12 - Hot Springs/InputReader.cs new file mode 100644 index 0000000..9472366 --- /dev/null +++ b/Day12 - Hot Springs/InputReader.cs @@ -0,0 +1,109 @@ +using System.Text.RegularExpressions; +using AdventOfCode.Common.SpanExtensions; + +namespace AdventOfCode.Year2023.Day12; + +internal sealed class InputReader +{ + private readonly char _operationalSpringChar; + private readonly char _damagedSpringChar; + private readonly char _unknownSpringChar; + + private static readonly Regex SpringRowRegex = new(@"^\s*(.+)\s+([\d,]+)\s*$", RegexOptions.Compiled); + + public InputReader(Day12SolverOptions options) + { + _operationalSpringChar = options.OperationalSpringChar; + _damagedSpringChar = options.DamagedSpringChar; + _unknownSpringChar = options.UnknownSpringChar; + } + + public IReadOnlyList ReadInput(IEnumerable inputLines) + { + List rows = new(1000); + foreach (string line in inputLines) + { + if (string.IsNullOrWhiteSpace(line)) + { + continue; + } + + var match = SpringRowRegex.Match(line); + if (!match.Success) + { + throw new InputException($"Invalid input line ('{line}')"); + } + + var springsSpan = match.Groups[1].ValueSpan; + var springs = ReadSprings(springsSpan); + + var springGroupSizesSpan = match.Groups[2].ValueSpan; + var springGroupSizes = ReadSpringGroupSizes(springGroupSizesSpan); + + rows.Add(new InputRow(springs, springGroupSizes)); + } + + return rows; + } + + private IReadOnlyList ReadSprings(ReadOnlySpan springs) + { + springs = springs.Trim(); + var result = new SpringCondition[springs.Length]; + for (int i = 0; i < springs.Length; i++) + { + result[i] = ParseSpringType(springs[i]); + } + + return result; + } + + private SpringCondition ParseSpringType(char c) + { + if (c == _operationalSpringChar) + { + return SpringCondition.Operational; + } + + if (c == _damagedSpringChar) + { + return SpringCondition.Damaged; + } + + if (c == _unknownSpringChar) + { + return SpringCondition.Unknown; + } + + throw new InputException($"Invalid spring type character ('{c}')"); + } + + private IReadOnlyList ReadSpringGroupSizes(ReadOnlySpan springGroupSizes) + { + int count = springGroupSizes.Count(','); + var result = new List(count + 1); + foreach (var part in springGroupSizes.Split(',')) + { + if (!int.TryParse(part, out int size)) + { + throw new InputException($"Invalid spring group size ('{part}')"); + } + result.Add(size); + } + + return result; + } +} + +internal enum SpringCondition +{ + Unknown, + Operational, + Damaged, +} + +internal class InputRow(IReadOnlyList springs, IReadOnlyList springGroupSizes) +{ + public IReadOnlyList Springs { get; } = springs; + public IReadOnlyList SpringGroupSizes { get; } = springGroupSizes; +} diff --git a/Day12 - Hot Springs/Program.cs b/Day12 - Hot Springs/Program.cs new file mode 100644 index 0000000..8f4c6f2 --- /dev/null +++ b/Day12 - Hot Springs/Program.cs @@ -0,0 +1,45 @@ +using System.Diagnostics; +using AdventOfCode; +using AdventOfCode.Year2023.Day12; + +try +{ + string? filepath = args.Length switch + { + 0 => null, + 1 => args[0], + _ => throw new CommandLineException( + $"Program was called with too many arguments. Proper usage: \"dotnet run []\"." + ) + }; + + Day12Solver solver = new(options => + { + options.InputFilepath = filepath ?? options.InputFilepath; + }); + + Console.WriteLine($"--- Day {solver.Day}: {solver.Title} ---"); + + Console.Write("Part one: "); + string part1 = solver.SolvePart1(); + Console.WriteLine(part1); + + Console.Write("Part two: "); + string part2 = solver.SolvePart2(); + Console.WriteLine(part2); +} +catch (AdventOfCodeException e) +{ + string errorPrefix = e switch + { + CommandLineException => "Command line error", + InputException => "Input error", + DaySolverException => "Day solver error", + _ => throw new UnreachableException($"Unknown exception type \"{e.GetType()}\".") + }; + + Console.ForegroundColor = ConsoleColor.Red; + Console.Error.WriteLine($"{errorPrefix}: {e.Message}"); + Console.ResetColor(); + Environment.Exit(1); +} diff --git a/Day12 - Hot Springs/README.md b/Day12 - Hot Springs/README.md new file mode 100644 index 0000000..9e92340 --- /dev/null +++ b/Day12 - Hot Springs/README.md @@ -0,0 +1 @@ +# [Day 12: Hot Springs](https://adventofcode.com/2023/day/12) diff --git a/Tests/Day12Tests.cs b/Tests/Day12Tests.cs new file mode 100644 index 0000000..3480501 --- /dev/null +++ b/Tests/Day12Tests.cs @@ -0,0 +1,24 @@ +using AdventOfCode.Year2023.Day12; + +namespace AdventOfCode.Year2023.Tests; + +[Trait("Year", "2023")] +[Trait("Day", "12")] +public sealed class Day12Tests : BaseDayTests +{ + protected override string DayInputsDirectory => "Day12"; + + protected override Day12Solver CreateSolver(Day12SolverOptions options) => new(options); + + [Theory] + [InlineData("example-input.txt", "21")] + [InlineData("my-input.txt", "", Skip = "Unsolved yet")] + public void TestPart1(string inputFilename, string expectedResult) + => BaseTestPart1(inputFilename, expectedResult); + + [Theory] + [InlineData("example-input.txt", "", Skip = "Unsolved yet")] + [InlineData("my-input.txt", "", Skip = "Unsolved yet")] + public void TestPart2(string inputFilename, string expectedResult) + => BaseTestPart2(inputFilename, expectedResult); +} diff --git a/Tests/Inputs/Day12/example-input.txt b/Tests/Inputs/Day12/example-input.txt new file mode 100644 index 0000000..28ac192 --- /dev/null +++ b/Tests/Inputs/Day12/example-input.txt @@ -0,0 +1,6 @@ +???.### 1,1,3 +.??..??...?##. 1,1,3 +?#?#?#?#?#?#?#? 1,3,1,6 +????.#...#... 4,1,1 +????.######..#####. 1,6,5 +?###???????? 3,2,1 diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index 335cbf3..43d98fd 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -37,10 +37,17 @@ - + - + + + + + + + Always + From b49690da895e367a98c65cfb5f5409ff30e16c2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Piotr=20Moru=C5=9B?= Date: Wed, 17 Jul 2024 13:07:57 +0200 Subject: [PATCH 2/6] Tweak restore inputs script so that example inputs are copied back from tests --- restore-inputs.ps1 | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/restore-inputs.ps1 b/restore-inputs.ps1 index 6a594ea..cbe47e2 100644 --- a/restore-inputs.ps1 +++ b/restore-inputs.ps1 @@ -87,6 +87,14 @@ foreach ($dayDirectory in $dayDirectories) { $testsInputRelativePath = Resolve-Path -Path $testsInputCreatedDirectory -Relative -RelativeBasePath $originalDirectory Write-Information " Tests directory was not found, created at $testsInputRelativePath" } + else { + # If directory existed, copy back potential example input files in them + $exampleInputFiles = Get-ChildItem -Path $testsInputDirectoryPath -Filter "example-input*.txt" + foreach ($exampleInputFile in $exampleInputFiles) { + $newExampleInputFileName = $exampleInputFile.Name -replace "^example-input-?", "example" + Copy-Item -Path $exampleInputFile.FullName -Destination $newExampleInputFileName + } + } $testsInputPath = Join-Path $testsInputDirectoryPath $testInputFilename if (Test-Path $testsInputPath) { $testFileHash = (Get-FileHash $testsInputPath -Algorithm MD5).Hash From 52c11abbd8cd1cdb10b2cccba094a99ed1f473eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Piotr=20Moru=C5=9B?= Date: Wed, 17 Jul 2024 14:08:17 +0200 Subject: [PATCH 3/6] Update and add missing .run files --- .run/Day01 example 1.run.xml | 20 +++++++++++++++++++ .run/Day01 example 2.run.xml | 20 +++++++++++++++++++ .run/Day01.run.xml | 20 +++++++++++++++++++ .run/Day02 example.run.xml | 20 +++++++++++++++++++ .run/Day02.run.xml | 20 +++++++++++++++++++ .run/Day03 example.run.xml | 20 +++++++++++++++++++ .run/Day03.run.xml | 20 +++++++++++++++++++ .run/Day04 example.run.xml | 20 +++++++++++++++++++ .run/Day04.run.xml | 20 +++++++++++++++++++ .run/Day05 example.run.xml | 20 +++++++++++++++++++ .run/Day05.run.xml | 20 +++++++++++++++++++ .run/Day06 example.run.xml | 20 +++++++++++++++++++ .run/Day06.run.xml | 20 +++++++++++++++++++ .run/Day10 example 6.run.xml | 37 ++++++++++++++++++------------------ .run/Day10 example 7.run.xml | 37 ++++++++++++++++++------------------ .run/Day10 example 8.run.xml | 37 ++++++++++++++++++------------------ .run/Day12 example.run.xml | 20 +++++++++++++++++++ 17 files changed, 334 insertions(+), 57 deletions(-) create mode 100644 .run/Day01 example 1.run.xml create mode 100644 .run/Day01 example 2.run.xml create mode 100644 .run/Day01.run.xml create mode 100644 .run/Day02 example.run.xml create mode 100644 .run/Day02.run.xml create mode 100644 .run/Day03 example.run.xml create mode 100644 .run/Day03.run.xml create mode 100644 .run/Day04 example.run.xml create mode 100644 .run/Day04.run.xml create mode 100644 .run/Day05 example.run.xml create mode 100644 .run/Day05.run.xml create mode 100644 .run/Day06 example.run.xml create mode 100644 .run/Day06.run.xml create mode 100644 .run/Day12 example.run.xml diff --git a/.run/Day01 example 1.run.xml b/.run/Day01 example 1.run.xml new file mode 100644 index 0000000..c3202e8 --- /dev/null +++ b/.run/Day01 example 1.run.xml @@ -0,0 +1,20 @@ + + + + \ No newline at end of file diff --git a/.run/Day01 example 2.run.xml b/.run/Day01 example 2.run.xml new file mode 100644 index 0000000..9daee01 --- /dev/null +++ b/.run/Day01 example 2.run.xml @@ -0,0 +1,20 @@ + + + + \ No newline at end of file diff --git a/.run/Day01.run.xml b/.run/Day01.run.xml new file mode 100644 index 0000000..b742b33 --- /dev/null +++ b/.run/Day01.run.xml @@ -0,0 +1,20 @@ + + + + \ No newline at end of file diff --git a/.run/Day02 example.run.xml b/.run/Day02 example.run.xml new file mode 100644 index 0000000..69106f7 --- /dev/null +++ b/.run/Day02 example.run.xml @@ -0,0 +1,20 @@ + + + + \ No newline at end of file diff --git a/.run/Day02.run.xml b/.run/Day02.run.xml new file mode 100644 index 0000000..cf05699 --- /dev/null +++ b/.run/Day02.run.xml @@ -0,0 +1,20 @@ + + + + \ No newline at end of file diff --git a/.run/Day03 example.run.xml b/.run/Day03 example.run.xml new file mode 100644 index 0000000..bf9215f --- /dev/null +++ b/.run/Day03 example.run.xml @@ -0,0 +1,20 @@ + + + + \ No newline at end of file diff --git a/.run/Day03.run.xml b/.run/Day03.run.xml new file mode 100644 index 0000000..bda1ac4 --- /dev/null +++ b/.run/Day03.run.xml @@ -0,0 +1,20 @@ + + + + \ No newline at end of file diff --git a/.run/Day04 example.run.xml b/.run/Day04 example.run.xml new file mode 100644 index 0000000..70aa4d8 --- /dev/null +++ b/.run/Day04 example.run.xml @@ -0,0 +1,20 @@ + + + + \ No newline at end of file diff --git a/.run/Day04.run.xml b/.run/Day04.run.xml new file mode 100644 index 0000000..6eec148 --- /dev/null +++ b/.run/Day04.run.xml @@ -0,0 +1,20 @@ + + + + \ No newline at end of file diff --git a/.run/Day05 example.run.xml b/.run/Day05 example.run.xml new file mode 100644 index 0000000..a44dca9 --- /dev/null +++ b/.run/Day05 example.run.xml @@ -0,0 +1,20 @@ + + + + \ No newline at end of file diff --git a/.run/Day05.run.xml b/.run/Day05.run.xml new file mode 100644 index 0000000..70b8279 --- /dev/null +++ b/.run/Day05.run.xml @@ -0,0 +1,20 @@ + + + + \ No newline at end of file diff --git a/.run/Day06 example.run.xml b/.run/Day06 example.run.xml new file mode 100644 index 0000000..5a2101c --- /dev/null +++ b/.run/Day06 example.run.xml @@ -0,0 +1,20 @@ + + + + \ No newline at end of file diff --git a/.run/Day06.run.xml b/.run/Day06.run.xml new file mode 100644 index 0000000..4b3713f --- /dev/null +++ b/.run/Day06.run.xml @@ -0,0 +1,20 @@ + + + + \ No newline at end of file diff --git a/.run/Day10 example 6.run.xml b/.run/Day10 example 6.run.xml index 41eaa85..0118012 100644 --- a/.run/Day10 example 6.run.xml +++ b/.run/Day10 example 6.run.xml @@ -1,21 +1,20 @@  - - + + diff --git a/.run/Day10 example 7.run.xml b/.run/Day10 example 7.run.xml index 506b8c8..7137975 100644 --- a/.run/Day10 example 7.run.xml +++ b/.run/Day10 example 7.run.xml @@ -1,21 +1,20 @@  - - + + diff --git a/.run/Day10 example 8.run.xml b/.run/Day10 example 8.run.xml index 8f78360..b0b3729 100644 --- a/.run/Day10 example 8.run.xml +++ b/.run/Day10 example 8.run.xml @@ -1,21 +1,20 @@  - - + + diff --git a/.run/Day12 example.run.xml b/.run/Day12 example.run.xml new file mode 100644 index 0000000..d3bcaed --- /dev/null +++ b/.run/Day12 example.run.xml @@ -0,0 +1,20 @@ + + + + \ No newline at end of file From 2ffa28217ede0babee09e80303c7d2626b0b5db2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Piotr=20Moru=C5=9B?= Date: Thu, 18 Jul 2024 14:42:17 +0200 Subject: [PATCH 4/6] Finished part 1 of the puzzle --- Day12 - Hot Springs/Day12Solver.cs | 7 +- Day12 - Hot Springs/Day12SolverOptions.cs | 3 - Day12 - Hot Springs/InputReader.cs | 65 ++----- .../SpringArrangementCounter.cs | 162 ++++++++++++++++++ Day12 - Hot Springs/SpringArrangementMemo.cs | 31 ++++ Day12 - Hot Springs/SpringCondition.cs | 8 + Day12 - Hot Springs/SpringRow.cs | 7 + Tests/Day12Tests.cs | 2 +- 8 files changed, 230 insertions(+), 55 deletions(-) create mode 100644 Day12 - Hot Springs/SpringArrangementCounter.cs create mode 100644 Day12 - Hot Springs/SpringArrangementMemo.cs create mode 100644 Day12 - Hot Springs/SpringCondition.cs create mode 100644 Day12 - Hot Springs/SpringRow.cs diff --git a/Day12 - Hot Springs/Day12Solver.cs b/Day12 - Hot Springs/Day12Solver.cs index 9d16a09..029e216 100644 --- a/Day12 - Hot Springs/Day12Solver.cs +++ b/Day12 - Hot Springs/Day12Solver.cs @@ -8,11 +8,11 @@ public sealed class Day12Solver : DaySolver public override int Day => 12; public override string Title => "Hot Springs"; - private readonly IReadOnlyList _rows; + private readonly IReadOnlyList _rows; public Day12Solver(Day12SolverOptions options) : base(options) { - var inputReader = new InputReader(options); + var inputReader = new InputReader(); _rows = inputReader.ReadInput(InputLines); } @@ -27,7 +27,8 @@ public Day12Solver() : this(new Day12SolverOptions()) public override string SolvePart1() { - var result = _rows.Select(r => r.Springs.Count(s => s == SpringCondition.Unknown)).Max(); + var counter = new SpringArrangementCounter(); + var result = _rows.Select(r => counter.CountPossibleArrangements(r)).Sum(); return result.ToString(); } diff --git a/Day12 - Hot Springs/Day12SolverOptions.cs b/Day12 - Hot Springs/Day12SolverOptions.cs index afd10a4..7da86b9 100644 --- a/Day12 - Hot Springs/Day12SolverOptions.cs +++ b/Day12 - Hot Springs/Day12SolverOptions.cs @@ -4,7 +4,4 @@ namespace AdventOfCode.Year2023.Day12; public sealed class Day12SolverOptions : DaySolverOptions { - public char OperationalSpringChar { get; set; } = '.'; - public char DamagedSpringChar { get; set; } = '#'; - public char UnknownSpringChar { get; set; } = '?'; } diff --git a/Day12 - Hot Springs/InputReader.cs b/Day12 - Hot Springs/InputReader.cs index 9472366..43bc999 100644 --- a/Day12 - Hot Springs/InputReader.cs +++ b/Day12 - Hot Springs/InputReader.cs @@ -5,22 +5,15 @@ namespace AdventOfCode.Year2023.Day12; internal sealed class InputReader { - private readonly char _operationalSpringChar; - private readonly char _damagedSpringChar; - private readonly char _unknownSpringChar; + private const char OperationalSpringChar = '.'; + private const char DamagedSpringChar = '#'; + private const char UnknownSpringChar = '?'; private static readonly Regex SpringRowRegex = new(@"^\s*(.+)\s+([\d,]+)\s*$", RegexOptions.Compiled); - public InputReader(Day12SolverOptions options) + public SpringRow[] ReadInput(IEnumerable inputLines) { - _operationalSpringChar = options.OperationalSpringChar; - _damagedSpringChar = options.DamagedSpringChar; - _unknownSpringChar = options.UnknownSpringChar; - } - - public IReadOnlyList ReadInput(IEnumerable inputLines) - { - List rows = new(1000); + List rows = new(1000); foreach (string line in inputLines) { if (string.IsNullOrWhiteSpace(line)) @@ -40,13 +33,13 @@ public IReadOnlyList ReadInput(IEnumerable inputLines) var springGroupSizesSpan = match.Groups[2].ValueSpan; var springGroupSizes = ReadSpringGroupSizes(springGroupSizesSpan); - rows.Add(new InputRow(springs, springGroupSizes)); + rows.Add(new SpringRow(springs, springGroupSizes)); } - return rows; + return rows.ToArray(); } - private IReadOnlyList ReadSprings(ReadOnlySpan springs) + private SpringCondition[] ReadSprings(ReadOnlySpan springs) { springs = springs.Trim(); var result = new SpringCondition[springs.Length]; @@ -58,27 +51,16 @@ private IReadOnlyList ReadSprings(ReadOnlySpan springs) return result; } - private SpringCondition ParseSpringType(char c) - { - if (c == _operationalSpringChar) - { - return SpringCondition.Operational; - } - - if (c == _damagedSpringChar) - { - return SpringCondition.Damaged; - } - - if (c == _unknownSpringChar) + private static SpringCondition ParseSpringType(char c) + => c switch { - return SpringCondition.Unknown; - } - - throw new InputException($"Invalid spring type character ('{c}')"); - } + OperationalSpringChar => SpringCondition.Operational, + DamagedSpringChar => SpringCondition.Damaged, + UnknownSpringChar => SpringCondition.Unknown, + _ => throw new InputException($"Invalid spring type character ('{c}')") + }; - private IReadOnlyList ReadSpringGroupSizes(ReadOnlySpan springGroupSizes) + private int[] ReadSpringGroupSizes(ReadOnlySpan springGroupSizes) { int count = springGroupSizes.Count(','); var result = new List(count + 1); @@ -91,19 +73,6 @@ private IReadOnlyList ReadSpringGroupSizes(ReadOnlySpan springGroupSi result.Add(size); } - return result; + return result.ToArray(); } } - -internal enum SpringCondition -{ - Unknown, - Operational, - Damaged, -} - -internal class InputRow(IReadOnlyList springs, IReadOnlyList springGroupSizes) -{ - public IReadOnlyList Springs { get; } = springs; - public IReadOnlyList SpringGroupSizes { get; } = springGroupSizes; -} diff --git a/Day12 - Hot Springs/SpringArrangementCounter.cs b/Day12 - Hot Springs/SpringArrangementCounter.cs new file mode 100644 index 0000000..b6a83a2 --- /dev/null +++ b/Day12 - Hot Springs/SpringArrangementCounter.cs @@ -0,0 +1,162 @@ +namespace AdventOfCode.Year2023.Day12; + +internal sealed class SpringArrangementCounter +{ + private readonly SpringArrangementMemo _memo = new(); + + public int CountPossibleArrangements(SpringRow row) + { + // Extend row with one operational spring at the end, with that making sure that the last spring cannot + // be part of a damaged group, and so we can add a group size of size 0 at the end also + row = new( + [..row.ConditionRecords, SpringCondition.Operational], + [..row.DamagedGroupSizes, 0] + ); + + _memo.ClearAndResizeFor(row); + + for (int springIndex = 0; springIndex < row.ConditionRecords.Length; springIndex++) + { + // Spring index represents the index in condition records of the spring currently being considered + for (int groupIndex = 0; groupIndex < row.DamagedGroupSizes.Length; groupIndex++) + { + // Group index represents the index of damage group currently being considered + for (int groupSize = 0; groupSize <= row.DamagedGroupSizes[groupIndex]; groupSize++) + { + // Group size represents the current size of the damage group currently being considered (it may have + // just started with current group size of 0 all the way to just ended with the full group size) + _memo[springIndex, groupIndex, groupSize] = CalculatePossibleArrangementsAt(springIndex, groupIndex, groupSize, row); + // We can safely use CalculatePossibleArrangementsAt as we are at either springIndex = 0, + // or all values for previous spring springIndex - 1 are already calculated and stored in memo + // since we use that as the outer loop variable. + } + } + } + + // Final answer is stored for the last spring (index = row.ConditionRecords.Length - 1), + // last group (index = row.DamagedGroupSizes.Length - 1) + // and with the last group size of 0 - we started the function with adding that 0 size group at the end. + return _memo[row.ConditionRecords.Length - 1, row.DamagedGroupSizes.Length - 1, 0]; + } + + /// + /// Calculated number of possible arrangements at the given spring index, group index and group size provided that + /// all possible arrangements for previous spring (at currentSpringIndex - 1) are already stored in the memo (base + /// cases for currentSpringIndex = 0 are handled correctly as well). + /// + private int CalculatePossibleArrangementsAt(int currentSpringIndex, int currentGroupIndex, int currentGroupSize, SpringRow row) + { + var springCondition = row.ConditionRecords[currentSpringIndex]; + + if (currentSpringIndex == 0) + { + // Base cases for when we are considering the first spring at index 0 + return CalculateBasePossibleArrangements(currentGroupIndex, currentGroupSize, springCondition); + } + + int possibleArrangementCount = 0; + + if (springCondition is SpringCondition.Operational or SpringCondition.Unknown) + { + possibleArrangementCount += CalculatePossibleArrangementsAssumingCurrentSpringOperational(currentSpringIndex, currentGroupIndex, currentGroupSize, row); + } + + if (springCondition is SpringCondition.Damaged or SpringCondition.Unknown) + { + possibleArrangementCount += CalculatePossibleArrangementsAssumingCurrentSpringDamaged(currentSpringIndex, currentGroupIndex, currentGroupSize); + } + + return possibleArrangementCount; + } + + /// + /// Calculates values for base cases of first spring at index 0, does not use memo as it is not needed. + /// + private static int CalculateBasePossibleArrangements(int currentGroupIndex, int currentGroupSize, SpringCondition firstSpringCondition) + { + // Base arrangements work on an assumption of i = 0 as base only applies to the first spring + + if (currentGroupIndex > 0) + { + // This is not possible as we can't consider group any other that first one if we are on a first character + return 0; + } + + // Based on the first spring condition and size of last group, we can have only either one possible arrangement (1) + // or given arrangement is impossible (0) + + return firstSpringCondition switch + { + // The first spring being damaged is only possible if the last group size is exactly 1 (this spring), otherwise it is not possible + SpringCondition.Damaged => currentGroupSize == 1 ? 1 : 0, + // The first spring being operational is only possible if the last group size is exactly 0 (no damaged spring), otherwise it is not possible + SpringCondition.Operational => currentGroupSize == 0 ? 1 : 0, + // If the first spring is unknown, `k` can be either 0 or 1, since we don't know the state of the first spring, but can't have a group size > 1 as we have only considered single spring + SpringCondition.Unknown => currentGroupSize < 2 ? 1 : 0, + _ => throw new DaySolverException($"Invalid spring condition {firstSpringCondition}") + }; + } + + /// + /// Calculates number of possible arrangements assuming that the current spring (at currentSpringIndex) is operational. + /// This can either be when the state of the spring is known to be operational, or it is unknown and *can* be operational. + /// It may use memo from previous spring (at index currentSpringIndex - 1) to calculate the number of possible arrangements. + /// + private int CalculatePossibleArrangementsAssumingCurrentSpringOperational(int currentSpringIndex, int currentGroupIndex, int currentGroupSize, SpringRow row) + { + if (currentGroupSize > 0) + { + // This is not possible since we cannot have a current group size of more than 0 while considering the last spring as operational. + return 0; + } + + if (currentGroupIndex == 0) + { + // If we are considering first damage group with empty final group (currentGroupSize == 0 asserted by previous condition) + // that means there should be one arrangement possible with no damaged springs before the current spring - otherwise that is not possible. + bool containsDamagedSprings = ContainsDamaged(row.ConditionRecords.AsSpan()[..currentSpringIndex]); + return containsDamagedSprings ? 0 : 1; + } + + // Getting to this arrangement from previous spring (currentSpringIndex - 1) consists of two scenarios, either considering + // previous damage group (currentGroupIndex - 1) ending with its full group size (row.DamagedGroupSizes[j - 1]) or considering + // current damage group (currentGroupIndex) ending with empty group size (0) + return _memo[currentSpringIndex - 1, currentGroupIndex - 1, row.DamagedGroupSizes[currentGroupIndex - 1]] + + _memo[currentSpringIndex - 1, currentGroupIndex, 0]; + } + + /// + /// Calculates number of possible arrangements assuming that the current spring (at currentSpringIndex) is damaged. + /// This can either be when the state of the spring is known to be damaged, or it is unknown and *can* be damaged. + /// It may use memo from previous spring (at index currentSpringIndex - 1) to calculate the number of possible arrangements. + /// + private int CalculatePossibleArrangementsAssumingCurrentSpringDamaged(int currentSpringIndex, int currentGroupIndex, int currentGroupSize) + { + if (currentGroupSize == 0) + { + // This is not possible since we cannot have a current group size of 0 while considering the current spring as damaged. + return 0; + } + + // Number of ways to get to this arrangement is equal as the number of ways to get to the previous spring (currentSpringIndex - 1) + // with the same damage group (currentGroupIndex), but one less size of the current group size (currentGroupIndex - 1) + // as this step is just adding one more damaged spring to the group. + return _memo[currentSpringIndex - 1, currentGroupIndex, currentGroupSize - 1]; + } + + /// + /// Returns whether contains any damaged springs. + /// + private static bool ContainsDamaged(ReadOnlySpan springSpan) + { + foreach (var item in springSpan) + { + if (item is SpringCondition.Damaged) + { + return true; + } + } + + return false; + } +} diff --git a/Day12 - Hot Springs/SpringArrangementMemo.cs b/Day12 - Hot Springs/SpringArrangementMemo.cs new file mode 100644 index 0000000..e0141b7 --- /dev/null +++ b/Day12 - Hot Springs/SpringArrangementMemo.cs @@ -0,0 +1,31 @@ +namespace AdventOfCode.Year2023.Day12; + +internal sealed class SpringArrangementMemo +{ + private int[,,] _memo = new int[0, 0, 0]; + + public void ClearAndResizeFor(SpringRow row) + { + int nofSprings = row.ConditionRecords.Length; + int nofGroups = row.DamagedGroupSizes.Length; + int maxGroupSize = row.DamagedGroupSizes.Max(); + + if (_memo.GetLength(0) < nofSprings || _memo.GetLength(1) < nofGroups || _memo.GetLength(2) <= maxGroupSize) + { + int newSpringsDimension = Math.Max(_memo.GetLength(0), nofSprings); + int newGroupsDimension = Math.Max(_memo.GetLength(1), nofGroups); + int newGroupSizeDimension = Math.Max(_memo.GetLength(2), maxGroupSize) + 1; + _memo = new int[newSpringsDimension, newGroupsDimension, newGroupSizeDimension]; + } + else + { + Array.Clear(_memo); + } + } + + public int this[int springIndex, int groupIndex, int groupSize] + { + get => _memo[springIndex, groupIndex, groupSize]; + set => _memo[springIndex, groupIndex, groupSize] = value; + } +} diff --git a/Day12 - Hot Springs/SpringCondition.cs b/Day12 - Hot Springs/SpringCondition.cs new file mode 100644 index 0000000..cd6e3b2 --- /dev/null +++ b/Day12 - Hot Springs/SpringCondition.cs @@ -0,0 +1,8 @@ +namespace AdventOfCode.Year2023.Day12; + +internal enum SpringCondition +{ + Unknown, + Operational, + Damaged, +} diff --git a/Day12 - Hot Springs/SpringRow.cs b/Day12 - Hot Springs/SpringRow.cs new file mode 100644 index 0000000..c1df563 --- /dev/null +++ b/Day12 - Hot Springs/SpringRow.cs @@ -0,0 +1,7 @@ +namespace AdventOfCode.Year2023.Day12; + +internal class SpringRow(SpringCondition[] conditionRecords, int[] damagedGroupSizes) +{ + public SpringCondition[] ConditionRecords { get; } = conditionRecords; + public int[] DamagedGroupSizes { get; } = damagedGroupSizes; +} diff --git a/Tests/Day12Tests.cs b/Tests/Day12Tests.cs index 3480501..c68adf6 100644 --- a/Tests/Day12Tests.cs +++ b/Tests/Day12Tests.cs @@ -12,7 +12,7 @@ public sealed class Day12Tests : BaseDayTests [Theory] [InlineData("example-input.txt", "21")] - [InlineData("my-input.txt", "", Skip = "Unsolved yet")] + [InlineData("my-input.txt", "7939")] public void TestPart1(string inputFilename, string expectedResult) => BaseTestPart1(inputFilename, expectedResult); From 7f95343039227bcb30fa050ce31c04c3cc81d565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Piotr=20Moru=C5=9B?= Date: Thu, 18 Jul 2024 17:19:57 +0200 Subject: [PATCH 5/6] Solved part two --- Day12 - Hot Springs/Day12Solver.cs | 40 ++++++++++++++++++- Day12 - Hot Springs/Day12SolverOptions.cs | 1 + .../SpringArrangementCounter.cs | 12 +++--- Day12 - Hot Springs/SpringArrangementMemo.cs | 6 +-- Tests/Day12Tests.cs | 4 +- 5 files changed, 50 insertions(+), 13 deletions(-) diff --git a/Day12 - Hot Springs/Day12Solver.cs b/Day12 - Hot Springs/Day12Solver.cs index 029e216..49af522 100644 --- a/Day12 - Hot Springs/Day12Solver.cs +++ b/Day12 - Hot Springs/Day12Solver.cs @@ -9,11 +9,13 @@ public sealed class Day12Solver : DaySolver public override string Title => "Hot Springs"; private readonly IReadOnlyList _rows; + private readonly int _unfoldRepetitions; public Day12Solver(Day12SolverOptions options) : base(options) { var inputReader = new InputReader(); _rows = inputReader.ReadInput(InputLines); + _unfoldRepetitions = options.UnfoldRepetitions; } public Day12Solver(Action configure) @@ -28,12 +30,46 @@ public Day12Solver() : this(new Day12SolverOptions()) public override string SolvePart1() { var counter = new SpringArrangementCounter(); - var result = _rows.Select(r => counter.CountPossibleArrangements(r)).Sum(); + long result = 0; + foreach (var row in _rows) + { + result += counter.CountPossibleArrangements(row); + } + return result.ToString(); } public override string SolvePart2() { - return "UNSOLVED"; + var counter = new SpringArrangementCounter(); + long result = 0; + foreach (var row in _rows) + { + var unfoldedRow = UnfoldRow(row); + result += counter.CountPossibleArrangements(unfoldedRow); + } + + return result.ToString(); + } + + private SpringRow UnfoldRow(SpringRow springRow) + { + var newConditionRecords = new SpringCondition[springRow.ConditionRecords.Length * _unfoldRepetitions + _unfoldRepetitions - 1]; + springRow.ConditionRecords.CopyTo(newConditionRecords, 0); + for (int i = 1; i < _unfoldRepetitions; i++) + { + int destination = i * (springRow.ConditionRecords.Length + 1); + newConditionRecords[destination - 1] = SpringCondition.Unknown; + springRow.ConditionRecords.CopyTo(newConditionRecords, destination); + } + + var newGroupSizes = new int[springRow.DamagedGroupSizes.Length * _unfoldRepetitions]; + for (int i = 0; i < _unfoldRepetitions; i++) + { + int destination = i * springRow.DamagedGroupSizes.Length; + springRow.DamagedGroupSizes.CopyTo(newGroupSizes, destination); + } + + return new(newConditionRecords, newGroupSizes); } } diff --git a/Day12 - Hot Springs/Day12SolverOptions.cs b/Day12 - Hot Springs/Day12SolverOptions.cs index 7da86b9..a8bff23 100644 --- a/Day12 - Hot Springs/Day12SolverOptions.cs +++ b/Day12 - Hot Springs/Day12SolverOptions.cs @@ -4,4 +4,5 @@ namespace AdventOfCode.Year2023.Day12; public sealed class Day12SolverOptions : DaySolverOptions { + public int UnfoldRepetitions { get; set; } = 5; } diff --git a/Day12 - Hot Springs/SpringArrangementCounter.cs b/Day12 - Hot Springs/SpringArrangementCounter.cs index b6a83a2..cf80622 100644 --- a/Day12 - Hot Springs/SpringArrangementCounter.cs +++ b/Day12 - Hot Springs/SpringArrangementCounter.cs @@ -4,7 +4,7 @@ internal sealed class SpringArrangementCounter { private readonly SpringArrangementMemo _memo = new(); - public int CountPossibleArrangements(SpringRow row) + public long CountPossibleArrangements(SpringRow row) { // Extend row with one operational spring at the end, with that making sure that the last spring cannot // be part of a damaged group, and so we can add a group size of size 0 at the end also @@ -44,7 +44,7 @@ public int CountPossibleArrangements(SpringRow row) /// all possible arrangements for previous spring (at currentSpringIndex - 1) are already stored in the memo (base /// cases for currentSpringIndex = 0 are handled correctly as well). /// - private int CalculatePossibleArrangementsAt(int currentSpringIndex, int currentGroupIndex, int currentGroupSize, SpringRow row) + private long CalculatePossibleArrangementsAt(int currentSpringIndex, int currentGroupIndex, int currentGroupSize, SpringRow row) { var springCondition = row.ConditionRecords[currentSpringIndex]; @@ -54,7 +54,7 @@ private int CalculatePossibleArrangementsAt(int currentSpringIndex, int currentG return CalculateBasePossibleArrangements(currentGroupIndex, currentGroupSize, springCondition); } - int possibleArrangementCount = 0; + long possibleArrangementCount = 0; if (springCondition is SpringCondition.Operational or SpringCondition.Unknown) { @@ -72,7 +72,7 @@ private int CalculatePossibleArrangementsAt(int currentSpringIndex, int currentG /// /// Calculates values for base cases of first spring at index 0, does not use memo as it is not needed. /// - private static int CalculateBasePossibleArrangements(int currentGroupIndex, int currentGroupSize, SpringCondition firstSpringCondition) + private static long CalculateBasePossibleArrangements(int currentGroupIndex, int currentGroupSize, SpringCondition firstSpringCondition) { // Base arrangements work on an assumption of i = 0 as base only applies to the first spring @@ -102,7 +102,7 @@ private static int CalculateBasePossibleArrangements(int currentGroupIndex, int /// This can either be when the state of the spring is known to be operational, or it is unknown and *can* be operational. /// It may use memo from previous spring (at index currentSpringIndex - 1) to calculate the number of possible arrangements. /// - private int CalculatePossibleArrangementsAssumingCurrentSpringOperational(int currentSpringIndex, int currentGroupIndex, int currentGroupSize, SpringRow row) + private long CalculatePossibleArrangementsAssumingCurrentSpringOperational(int currentSpringIndex, int currentGroupIndex, int currentGroupSize, SpringRow row) { if (currentGroupSize > 0) { @@ -130,7 +130,7 @@ private int CalculatePossibleArrangementsAssumingCurrentSpringOperational(int cu /// This can either be when the state of the spring is known to be damaged, or it is unknown and *can* be damaged. /// It may use memo from previous spring (at index currentSpringIndex - 1) to calculate the number of possible arrangements. /// - private int CalculatePossibleArrangementsAssumingCurrentSpringDamaged(int currentSpringIndex, int currentGroupIndex, int currentGroupSize) + private long CalculatePossibleArrangementsAssumingCurrentSpringDamaged(int currentSpringIndex, int currentGroupIndex, int currentGroupSize) { if (currentGroupSize == 0) { diff --git a/Day12 - Hot Springs/SpringArrangementMemo.cs b/Day12 - Hot Springs/SpringArrangementMemo.cs index e0141b7..9fa4c03 100644 --- a/Day12 - Hot Springs/SpringArrangementMemo.cs +++ b/Day12 - Hot Springs/SpringArrangementMemo.cs @@ -2,7 +2,7 @@ internal sealed class SpringArrangementMemo { - private int[,,] _memo = new int[0, 0, 0]; + private long[,,] _memo = new long[0, 0, 0]; public void ClearAndResizeFor(SpringRow row) { @@ -15,7 +15,7 @@ public void ClearAndResizeFor(SpringRow row) int newSpringsDimension = Math.Max(_memo.GetLength(0), nofSprings); int newGroupsDimension = Math.Max(_memo.GetLength(1), nofGroups); int newGroupSizeDimension = Math.Max(_memo.GetLength(2), maxGroupSize) + 1; - _memo = new int[newSpringsDimension, newGroupsDimension, newGroupSizeDimension]; + _memo = new long[newSpringsDimension, newGroupsDimension, newGroupSizeDimension]; } else { @@ -23,7 +23,7 @@ public void ClearAndResizeFor(SpringRow row) } } - public int this[int springIndex, int groupIndex, int groupSize] + public long this[int springIndex, int groupIndex, int groupSize] { get => _memo[springIndex, groupIndex, groupSize]; set => _memo[springIndex, groupIndex, groupSize] = value; diff --git a/Tests/Day12Tests.cs b/Tests/Day12Tests.cs index c68adf6..a76f876 100644 --- a/Tests/Day12Tests.cs +++ b/Tests/Day12Tests.cs @@ -17,8 +17,8 @@ public void TestPart1(string inputFilename, string expectedResult) => BaseTestPart1(inputFilename, expectedResult); [Theory] - [InlineData("example-input.txt", "", Skip = "Unsolved yet")] - [InlineData("my-input.txt", "", Skip = "Unsolved yet")] + [InlineData("example-input.txt", "525152")] + [InlineData("my-input.txt", "850504257483930")] public void TestPart2(string inputFilename, string expectedResult) => BaseTestPart2(inputFilename, expectedResult); } From 5d87e9a6a856a2c9b8d345e053d3d923b2211216 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Piotr=20Moru=C5=9B?= Date: Thu, 18 Jul 2024 17:21:47 +0200 Subject: [PATCH 6/6] Fix formatting --- Day12 - Hot Springs/InputReader.cs | 2 +- Day12 - Hot Springs/SpringArrangementCounter.cs | 8 ++++---- Day12 - Hot Springs/SpringArrangementMemo.cs | 2 +- Day12 - Hot Springs/SpringCondition.cs | 2 +- Day12 - Hot Springs/SpringRow.cs | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Day12 - Hot Springs/InputReader.cs b/Day12 - Hot Springs/InputReader.cs index 43bc999..a04de22 100644 --- a/Day12 - Hot Springs/InputReader.cs +++ b/Day12 - Hot Springs/InputReader.cs @@ -1,4 +1,4 @@ -using System.Text.RegularExpressions; +using System.Text.RegularExpressions; using AdventOfCode.Common.SpanExtensions; namespace AdventOfCode.Year2023.Day12; diff --git a/Day12 - Hot Springs/SpringArrangementCounter.cs b/Day12 - Hot Springs/SpringArrangementCounter.cs index cf80622..f889c3d 100644 --- a/Day12 - Hot Springs/SpringArrangementCounter.cs +++ b/Day12 - Hot Springs/SpringArrangementCounter.cs @@ -1,4 +1,4 @@ -namespace AdventOfCode.Year2023.Day12; +namespace AdventOfCode.Year2023.Day12; internal sealed class SpringArrangementCounter { @@ -9,8 +9,8 @@ public long CountPossibleArrangements(SpringRow row) // Extend row with one operational spring at the end, with that making sure that the last spring cannot // be part of a damaged group, and so we can add a group size of size 0 at the end also row = new( - [..row.ConditionRecords, SpringCondition.Operational], - [..row.DamagedGroupSizes, 0] + [.. row.ConditionRecords, SpringCondition.Operational], + [.. row.DamagedGroupSizes, 0] ); _memo.ClearAndResizeFor(row); @@ -122,7 +122,7 @@ private long CalculatePossibleArrangementsAssumingCurrentSpringOperational(int c // previous damage group (currentGroupIndex - 1) ending with its full group size (row.DamagedGroupSizes[j - 1]) or considering // current damage group (currentGroupIndex) ending with empty group size (0) return _memo[currentSpringIndex - 1, currentGroupIndex - 1, row.DamagedGroupSizes[currentGroupIndex - 1]] - + _memo[currentSpringIndex - 1, currentGroupIndex, 0]; + + _memo[currentSpringIndex - 1, currentGroupIndex, 0]; } /// diff --git a/Day12 - Hot Springs/SpringArrangementMemo.cs b/Day12 - Hot Springs/SpringArrangementMemo.cs index 9fa4c03..9b3eb9c 100644 --- a/Day12 - Hot Springs/SpringArrangementMemo.cs +++ b/Day12 - Hot Springs/SpringArrangementMemo.cs @@ -1,4 +1,4 @@ -namespace AdventOfCode.Year2023.Day12; +namespace AdventOfCode.Year2023.Day12; internal sealed class SpringArrangementMemo { diff --git a/Day12 - Hot Springs/SpringCondition.cs b/Day12 - Hot Springs/SpringCondition.cs index cd6e3b2..304d06d 100644 --- a/Day12 - Hot Springs/SpringCondition.cs +++ b/Day12 - Hot Springs/SpringCondition.cs @@ -1,4 +1,4 @@ -namespace AdventOfCode.Year2023.Day12; +namespace AdventOfCode.Year2023.Day12; internal enum SpringCondition { diff --git a/Day12 - Hot Springs/SpringRow.cs b/Day12 - Hot Springs/SpringRow.cs index c1df563..add0c89 100644 --- a/Day12 - Hot Springs/SpringRow.cs +++ b/Day12 - Hot Springs/SpringRow.cs @@ -1,4 +1,4 @@ -namespace AdventOfCode.Year2023.Day12; +namespace AdventOfCode.Year2023.Day12; internal class SpringRow(SpringCondition[] conditionRecords, int[] damagedGroupSizes) {