From 8822e2f94471710223a6c66570f9952956f33f85 Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Sat, 9 Dec 2023 23:39:38 -0600 Subject: [PATCH 1/5] chore: scaffold for day 10 puzzle --- 10/PipeMaze.Tests/GlobalUsings.cs | 2 ++ 10/PipeMaze.Tests/PipeMaze.Tests.csproj | 30 +++++++++++++++++++++++++ 10/PipeMaze.Tests/UnitTest1.cs | 10 +++++++++ 10/PipeMaze/PipeMaze.csproj | 10 +++++++++ 10/PipeMaze/Program.cs | 2 ++ AdventOfCode2023.sln | 16 +++++++++++++ 6 files changed, 70 insertions(+) create mode 100644 10/PipeMaze.Tests/GlobalUsings.cs create mode 100644 10/PipeMaze.Tests/PipeMaze.Tests.csproj create mode 100644 10/PipeMaze.Tests/UnitTest1.cs create mode 100644 10/PipeMaze/PipeMaze.csproj create mode 100644 10/PipeMaze/Program.cs diff --git a/10/PipeMaze.Tests/GlobalUsings.cs b/10/PipeMaze.Tests/GlobalUsings.cs new file mode 100644 index 0000000..7fef4b0 --- /dev/null +++ b/10/PipeMaze.Tests/GlobalUsings.cs @@ -0,0 +1,2 @@ +global using Xunit; +global using FluentAssertions; \ No newline at end of file diff --git a/10/PipeMaze.Tests/PipeMaze.Tests.csproj b/10/PipeMaze.Tests/PipeMaze.Tests.csproj new file mode 100644 index 0000000..ee3cd62 --- /dev/null +++ b/10/PipeMaze.Tests/PipeMaze.Tests.csproj @@ -0,0 +1,30 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/10/PipeMaze.Tests/UnitTest1.cs b/10/PipeMaze.Tests/UnitTest1.cs new file mode 100644 index 0000000..2ae55c5 --- /dev/null +++ b/10/PipeMaze.Tests/UnitTest1.cs @@ -0,0 +1,10 @@ +namespace PipeMaze.Tests; + +public class UnitTest1 +{ + [Fact] + public void Test1() + { + + } +} \ No newline at end of file diff --git a/10/PipeMaze/PipeMaze.csproj b/10/PipeMaze/PipeMaze.csproj new file mode 100644 index 0000000..2150e37 --- /dev/null +++ b/10/PipeMaze/PipeMaze.csproj @@ -0,0 +1,10 @@ + + + + Exe + net8.0 + enable + enable + + + diff --git a/10/PipeMaze/Program.cs b/10/PipeMaze/Program.cs new file mode 100644 index 0000000..3751555 --- /dev/null +++ b/10/PipeMaze/Program.cs @@ -0,0 +1,2 @@ +// See https://aka.ms/new-console-template for more information +Console.WriteLine("Hello, World!"); diff --git a/AdventOfCode2023.sln b/AdventOfCode2023.sln index f963b6c..6ea177f 100644 --- a/AdventOfCode2023.sln +++ b/AdventOfCode2023.sln @@ -57,6 +57,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MirageMaintenance", "09\Mir EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MirageMaintenance.Tests", "09\MirageMaintenance.Tests\MirageMaintenance.Tests.csproj", "{5C39C115-ACBF-458A-9409-FBD23637A789}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "10", "10", "{9703A36A-A019-4ADC-93A7-9DF4EFBCBFBC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PipeMaze", "10\PipeMaze\PipeMaze.csproj", "{B46ADCFF-35FF-496D-A035-FE2B9FFC185A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PipeMaze.Tests", "10\PipeMaze.Tests\PipeMaze.Tests.csproj", "{B1DA407F-DA29-4BDA-B10E-8B9A976B0C5E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -138,6 +144,14 @@ Global {5C39C115-ACBF-458A-9409-FBD23637A789}.Debug|Any CPU.Build.0 = Debug|Any CPU {5C39C115-ACBF-458A-9409-FBD23637A789}.Release|Any CPU.ActiveCfg = Release|Any CPU {5C39C115-ACBF-458A-9409-FBD23637A789}.Release|Any CPU.Build.0 = Release|Any CPU + {B46ADCFF-35FF-496D-A035-FE2B9FFC185A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B46ADCFF-35FF-496D-A035-FE2B9FFC185A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B46ADCFF-35FF-496D-A035-FE2B9FFC185A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B46ADCFF-35FF-496D-A035-FE2B9FFC185A}.Release|Any CPU.Build.0 = Release|Any CPU + {B1DA407F-DA29-4BDA-B10E-8B9A976B0C5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B1DA407F-DA29-4BDA-B10E-8B9A976B0C5E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B1DA407F-DA29-4BDA-B10E-8B9A976B0C5E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B1DA407F-DA29-4BDA-B10E-8B9A976B0C5E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {3F8EAC09-4BC7-43AA-B72B-48DDD2710F6D} = {8C29858C-623A-461A-BF0B-254E151CD9C2} @@ -158,5 +172,7 @@ Global {FA8DDDD1-4DD9-4927-A9FB-C4FACDEAF901} = {F21CCF39-1F8A-40DA-A0E5-F1426B09BAA2} {6C233DE5-D1D0-46C0-A250-AF0272B495CE} = {79203C8D-F382-4C95-90EA-FECEE65602DA} {5C39C115-ACBF-458A-9409-FBD23637A789} = {79203C8D-F382-4C95-90EA-FECEE65602DA} + {B46ADCFF-35FF-496D-A035-FE2B9FFC185A} = {9703A36A-A019-4ADC-93A7-9DF4EFBCBFBC} + {B1DA407F-DA29-4BDA-B10E-8B9A976B0C5E} = {9703A36A-A019-4ADC-93A7-9DF4EFBCBFBC} EndGlobalSection EndGlobal From 630576c065beb54003e6deb1747a536267df24ea Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Sun, 10 Dec 2023 23:40:12 -0600 Subject: [PATCH 2/5] feat: solve part 1 --- 10/PipeMaze.Tests/MazeTests.cs | 358 +++++++++++++++++++++++++++++++ 10/PipeMaze.Tests/UnitTest1.cs | 10 - 10/PipeMaze/Program.cs | 374 ++++++++++++++++++++++++++++++++- 3 files changed, 730 insertions(+), 12 deletions(-) create mode 100644 10/PipeMaze.Tests/MazeTests.cs delete mode 100644 10/PipeMaze.Tests/UnitTest1.cs diff --git a/10/PipeMaze.Tests/MazeTests.cs b/10/PipeMaze.Tests/MazeTests.cs new file mode 100644 index 0000000..0172ba7 --- /dev/null +++ b/10/PipeMaze.Tests/MazeTests.cs @@ -0,0 +1,358 @@ +namespace PipeMaze.Tests; + +public class MazeTests +{ + + [Theory] + [MemberData(nameof(TestData.ParseTestData), MemberType = typeof(TestData))] + public void Parse_WhenGivenInput_ItShouldReturnExpectedMaze(string[] input, Maze expectedMaze, Pipe? expectedStartingPipe) + { + var maze = Maze.Parse(input); + maze.Should().BeEquivalentTo(expectedMaze); + maze.StartingPipe.Should().BeEquivalentTo(expectedStartingPipe); + } + + [Theory] + [MemberData(nameof(TestData.IdentifyPipeTypeTestData), MemberType = typeof(TestData))] + public void IdentifyPipeType_WhenGivenInput_ItShouldReturnExpectedPipeType(Maze maze, PipeType expectedPipeType) + { + maze + .IdentifyStartPipeType() + .Should() + .Be(expectedPipeType); + } + + [Theory] + [MemberData(nameof(TestData.GetLoopTestData), MemberType = typeof(TestData))] + public void GetLoop_WhenGivenInput_ItShouldReturnExpectedLoop(Maze maze, List expectedLoop) + { + maze + .GetLoop() + .Should() + .BeEquivalentTo(expectedLoop); + } + + [Theory] + [MemberData(nameof(TestData.FurthestStepFromStartTestData), MemberType = typeof(TestData))] + public void FurthestStepFromStart_WhenGivenInput_ItShouldReturnExpectedFurthestStepFromStart(Maze maze, int expectedFurthestStepFromStart) + { + maze.FarthestStepFromStart + .Should() + .Be(expectedFurthestStepFromStart); + } + + public static class TestData + { + private static readonly string[] TestMazeInput = + { + ".....", + ".S-7.", + ".|.|.", + ".L-J.", + ".....", + }; + + private static readonly Maze TestMaze = + new( + 5, + 5, + [ + new('S', PipeType.Unknown, 1, 1), + new('-', PipeType.LeftAndRight, 1, 2), + new('7', PipeType.DownAndLeft, 1, 3), + new('|', PipeType.UpAndDown, 2, 1), + new('|', PipeType.UpAndDown, 2, 3), + new('L', PipeType.UpAndRight, 3, 1), + new('-', PipeType.LeftAndRight, 3, 2), + new('J', PipeType.UpAndLeft, 3, 3), + ] + ); + + public static IEnumerable FurthestStepFromStartTestData => + new List + { + new object[] + { + TestMaze, + 4 + }, + new object[] + { + new Maze( + 5, + 5, + [ + new('7', PipeType.DownAndLeft, 0, 0), + new('-', PipeType.UpAndRight, 0, 1), + new('F', PipeType.DownAndRight, 0, 2), + new('7', PipeType.DownAndLeft, 0, 3), + new('-', PipeType.LeftAndRight, 0, 4), + + new('F', PipeType.DownAndRight, 1, 1), + new('J', PipeType.UpAndLeft, 1, 2), + new('|', PipeType.UpAndDown, 1, 3), + new('7', PipeType.DownAndLeft, 1, 4), + + new('S', PipeType.Unknown, 2, 0), + new('J', PipeType.UpAndLeft, 2, 1), + new('L', PipeType.UpAndRight, 2, 2), + new('L', PipeType.UpAndRight, 2, 3), + new('7', PipeType.DownAndLeft, 2, 4), + + new('|', PipeType.UpAndDown, 3, 0), + new('F', PipeType.DownAndRight, 3, 1), + new('-', PipeType.LeftAndRight, 3, 2), + new('-', PipeType.LeftAndRight, 3, 3), + new('J', PipeType.UpAndLeft, 3, 4), + + new('L', PipeType.UpAndRight, 4, 0), + new('J', PipeType.UpAndLeft, 4, 1), + new('L', PipeType.UpAndRight, 4, 3), + new('J', PipeType.UpAndLeft, 4, 4), + ] + ), + 8, + } + }; + + public static IEnumerable GetLoopTestData => + new List + { + new object[] + { + TestMaze, + new List + { + new('S', PipeType.DownAndRight, 1, 1), + new('-', PipeType.LeftAndRight, 1, 2), + new('7', PipeType.DownAndLeft, 1, 3), + new('|', PipeType.UpAndDown, 2, 1), + new('|', PipeType.UpAndDown, 2, 3), + new('L', PipeType.UpAndRight, 3, 1), + new('-', PipeType.LeftAndRight, 3, 2), + new('J', PipeType.UpAndLeft, 3, 3), + } + }, + new object[] + { + new Maze( + 5, + 5, + [ + new('-', PipeType.LeftAndRight, 0, 0), + new('L', PipeType.UpAndRight, 0, 1), + new('|', PipeType.UpAndDown, 0, 2), + new('F', PipeType.DownAndRight, 0, 3), + new('7', PipeType.DownAndLeft, 0, 4), + + new('7', PipeType.DownAndLeft, 1, 0), + new('S', PipeType.Unknown, 1, 1), + new('-', PipeType.LeftAndRight, 1, 2), + new('7', PipeType.DownAndLeft, 1, 3), + new('|', PipeType.UpAndDown, 1, 4), + + new('L', PipeType.UpAndRight, 2, 0), + new('|', PipeType.UpAndDown, 2, 1), + new('7', PipeType.DownAndLeft, 2, 2), + new('|', PipeType.UpAndDown, 2, 3), + new('|', PipeType.UpAndDown, 2, 4), + + new('-', PipeType.LeftAndRight, 3, 0), + new('L', PipeType.UpAndRight, 3, 1), + new('-', PipeType.LeftAndRight, 3, 2), + new('J', PipeType.UpAndLeft, 3, 3), + new('|', PipeType.UpAndDown, 3, 4), + + new('L', PipeType.UpAndRight, 4, 0), + new('|', PipeType.UpAndDown, 4, 1), + new('-', PipeType.LeftAndRight, 4, 2), + new('J', PipeType.UpAndLeft, 4, 3), + new('F', PipeType.DownAndRight, 4, 4), + ] + ), + new List + { + new('S', PipeType.DownAndRight, 1, 1), + new('-', PipeType.LeftAndRight, 1, 2), + new('7', PipeType.DownAndLeft, 1, 3), + new('|', PipeType.UpAndDown, 2, 1), + new('|', PipeType.UpAndDown, 2, 3), + new('L', PipeType.UpAndRight, 3, 1), + new('-', PipeType.LeftAndRight, 3, 2), + new('J', PipeType.UpAndLeft, 3, 3), + } + }, + new object[] + { + new Maze( + 5, + 5, + [ + new('F', PipeType.DownAndRight, 0, 2), + new('7', PipeType.DownAndLeft, 0, 3), + + new('F', PipeType.DownAndRight, 1, 1), + new('J', PipeType.UpAndLeft, 1, 2), + new('|', PipeType.UpAndDown, 1, 3), + + new('S', PipeType.Unknown, 2, 0), + new('J', PipeType.UpAndLeft, 2, 1), + new('L', PipeType.UpAndRight, 2, 3), + new('7', PipeType.DownAndLeft, 2, 4), + + new('|', PipeType.UpAndDown, 3, 0), + new('F', PipeType.DownAndRight, 3, 1), + new('-', PipeType.LeftAndRight, 3, 2), + new('-', PipeType.LeftAndRight, 3, 3), + new('J', PipeType.UpAndLeft, 3, 4), + + new('L', PipeType.UpAndRight, 4, 0), + new('J', PipeType.UpAndLeft, 4, 1), + ] + ), + new List + { + new('F', PipeType.DownAndRight, 0, 2), + new('7', PipeType.DownAndLeft, 0, 3), + + new('F', PipeType.DownAndRight, 1, 1), + new('J', PipeType.UpAndLeft, 1, 2), + new('|', PipeType.UpAndDown, 1, 3), + + new('S', PipeType.DownAndRight, 2, 0), + new('J', PipeType.UpAndLeft, 2, 1), + new('L', PipeType.UpAndRight, 2, 3), + new('7', PipeType.DownAndLeft, 2, 4), + + new('|', PipeType.UpAndDown, 3, 0), + new('F', PipeType.DownAndRight, 3, 1), + new('-', PipeType.LeftAndRight, 3, 2), + new('-', PipeType.LeftAndRight, 3, 3), + new('J', PipeType.UpAndLeft, 3, 4), + + new('L', PipeType.UpAndRight, 4, 0), + new('J', PipeType.UpAndLeft, 4, 1), + } + }, + new object[] + { + new Maze( + 5, + 5, + [ + new('7', PipeType.DownAndLeft, 0, 0), + new('-', PipeType.UpAndRight, 0, 1), + new('F', PipeType.DownAndRight, 0, 2), + new('7', PipeType.DownAndLeft, 0, 3), + new('-', PipeType.LeftAndRight, 0, 4), + + new('F', PipeType.DownAndRight, 1, 1), + new('J', PipeType.UpAndLeft, 1, 2), + new('|', PipeType.UpAndDown, 1, 3), + new('7', PipeType.DownAndLeft, 1, 4), + + new('S', PipeType.Unknown, 2, 0), + new('J', PipeType.UpAndLeft, 2, 1), + new('L', PipeType.UpAndRight, 2, 2), + new('L', PipeType.UpAndRight, 2, 3), + new('7', PipeType.DownAndLeft, 2, 4), + + new('|', PipeType.UpAndDown, 3, 0), + new('F', PipeType.DownAndRight, 3, 1), + new('-', PipeType.LeftAndRight, 3, 2), + new('-', PipeType.LeftAndRight, 3, 3), + new('J', PipeType.UpAndLeft, 3, 4), + + new('L', PipeType.UpAndRight, 4, 0), + new('J', PipeType.UpAndLeft, 4, 1), + new('L', PipeType.UpAndRight, 4, 3), + new('J', PipeType.UpAndLeft, 4, 4), + ] + ), + new List + { + new('F', PipeType.DownAndRight, 0, 2), + new('7', PipeType.DownAndLeft, 0, 3), + + new('F', PipeType.DownAndRight, 1, 1), + new('J', PipeType.UpAndLeft, 1, 2), + new('|', PipeType.UpAndDown, 1, 3), + + new('S', PipeType.DownAndRight, 2, 0), + new('J', PipeType.UpAndLeft, 2, 1), + new('L', PipeType.UpAndRight, 2, 3), + new('7', PipeType.DownAndLeft, 2, 4), + + new('|', PipeType.UpAndDown, 3, 0), + new('F', PipeType.DownAndRight, 3, 1), + new('-', PipeType.LeftAndRight, 3, 2), + new('-', PipeType.LeftAndRight, 3, 3), + new('J', PipeType.UpAndLeft, 3, 4), + + new('L', PipeType.UpAndRight, 4, 0), + new('J', PipeType.UpAndLeft, 4, 1), + } + } + }; + + public static IEnumerable IdentifyPipeTypeTestData => + new List + { + new object[] + { + TestMaze, + PipeType.DownAndRight, + } + }; + + public static IEnumerable ParseTestData => + new List + { + new object?[] + { + new string[] + { + ".....", + ".F-7.", + ".|.|.", + ".L-J.", + ".....", + }, + new Maze( + 5, + 5, + [ + new('F', PipeType.DownAndRight, 1, 1), + new('-', PipeType.LeftAndRight, 1, 2), + new('7', PipeType.DownAndLeft, 1, 3), + new('|', PipeType.UpAndDown, 2, 1), + new('|', PipeType.UpAndDown, 2, 3), + new('L', PipeType.UpAndRight, 3, 1), + new('-', PipeType.LeftAndRight, 3, 2), + new('J', PipeType.UpAndLeft, 3, 3), + ] + ), + null + }, + new object?[] + { + TestMazeInput, + new Maze( + 5, + 5, + [ + new('S', PipeType.Unknown, 1, 1), + new('-', PipeType.LeftAndRight, 1, 2), + new('7', PipeType.DownAndLeft, 1, 3), + new('|', PipeType.UpAndDown, 2, 1), + new('|', PipeType.UpAndDown, 2, 3), + new('L', PipeType.UpAndRight, 3, 1), + new('-', PipeType.LeftAndRight, 3, 2), + new('J', PipeType.UpAndLeft, 3, 3), + ] + ), + new Pipe('S', PipeType.Unknown, 1, 1) + } + }; + } +} \ No newline at end of file diff --git a/10/PipeMaze.Tests/UnitTest1.cs b/10/PipeMaze.Tests/UnitTest1.cs deleted file mode 100644 index 2ae55c5..0000000 --- a/10/PipeMaze.Tests/UnitTest1.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace PipeMaze.Tests; - -public class UnitTest1 -{ - [Fact] - public void Test1() - { - - } -} \ No newline at end of file diff --git a/10/PipeMaze/Program.cs b/10/PipeMaze/Program.cs index 3751555..ef145e1 100644 --- a/10/PipeMaze/Program.cs +++ b/10/PipeMaze/Program.cs @@ -1,2 +1,372 @@ -// See https://aka.ms/new-console-template for more information -Console.WriteLine("Hello, World!"); +using System.Diagnostics; + +namespace PipeMaze; + +public class Program +{ + public static async Task Main(string[] args) + { + if (args.Length is 0) + { + Console.WriteLine("Please provide a path to the input file."); + return -1; + } + + if (File.Exists(args[0]) is false) + { + Console.WriteLine("The provided file does not exist."); + return -2; + } + + var input = await File.ReadAllLinesAsync(args[0]); + + var stopwatch = new Stopwatch(); + stopwatch.Start(); + + var result = Maze.Parse(input).FarthestStepFromStart; + + stopwatch.Stop(); + + Console.WriteLine($"The farthest step from the starting pipe is {result}. ({stopwatch.ElapsedMilliseconds}ms)"); + + return result; + } +} + +public class Maze( + int width, + int height, + List pipes +) +{ + private static readonly Dictionary _pipes = new() + { + { '|', PipeType.UpAndDown }, + { '-', PipeType.LeftAndRight }, + { 'L', PipeType.UpAndRight }, + { 'J', PipeType.UpAndLeft }, + { '7', PipeType.DownAndLeft }, + { 'F', PipeType.DownAndRight }, + { 'S', PipeType.Unknown }, + }; + + public int Width { get; init; } = width; + public int Height { get; init; } = height; + public List Pipes { get; init; } = pipes; + + public Pipe? StartingPipe => Pipes.FirstOrDefault(p => p.Type is PipeType.Unknown); + + public int FarthestStepFromStart => GetLoop().Count / 2; + + public List GetLoop() + { + if (StartingPipe is null) + { + return []; + } + + var loop = new List(); + var startingPipeType = IdentifyStartPipeType(); + var currentPipe = new Pipe( + StartingPipe.Symbol, + startingPipeType, + StartingPipe.Coordinate.Row, + StartingPipe.Coordinate.Column + ); + + do + { + loop.Add(currentPipe); + + var connectingPipes = GetConnectingPipes(currentPipe); + currentPipe = connectingPipes + .FirstOrDefault( + p => + p is not null && + loop.Any(pipe => pipe.Coordinate.Equals(p.Coordinate)) is false + ); + + } while (currentPipe?.Equals(StartingPipe) is false); + + return loop; + } + + public PipeType IdentifyStartPipeType() + { + if (StartingPipe is null) + { + return PipeType.Unknown; + } + + var connectingPipes = GetConnectingPipes(StartingPipe); + var pipeAbove = connectingPipes.FirstOrDefault(p => p?.Coordinate.Row < StartingPipe.Coordinate.Row); + var pipeBelow = connectingPipes.FirstOrDefault(p => p?.Coordinate.Row > StartingPipe.Coordinate.Row); + var pipeToTheLeft = connectingPipes.FirstOrDefault(p => p?.Coordinate.Column < StartingPipe.Coordinate.Column); + var pipeToTheRight = connectingPipes.FirstOrDefault(p => p?.Coordinate.Column > StartingPipe.Coordinate.Column); + + var isPipeAboveConnected = pipeAbove is not null && + pipeAbove.Type is PipeType.UpAndDown or PipeType.DownAndRight or PipeType.DownAndLeft; + + var isPipeBelowConnected = pipeBelow is not null && + pipeBelow.Type is PipeType.UpAndDown or PipeType.UpAndRight or PipeType.UpAndLeft; + + var isPipeToTheLeftConnected = pipeToTheLeft is not null && + pipeToTheLeft.Type is PipeType.LeftAndRight or PipeType.DownAndRight or PipeType.UpAndRight; + + var isPipeToTheRightConnected = pipeToTheRight is not null && + pipeToTheRight.Type is PipeType.LeftAndRight or PipeType.DownAndLeft or PipeType.UpAndLeft; + + if (isPipeAboveConnected && isPipeBelowConnected && isPipeToTheLeftConnected && isPipeToTheRightConnected) + { + return PipeType.Unknown; + } + + if (isPipeAboveConnected && isPipeBelowConnected) + { + return PipeType.UpAndDown; + } + + if (isPipeToTheLeftConnected && isPipeToTheRightConnected) + { + return PipeType.LeftAndRight; + } + + if (isPipeAboveConnected && isPipeToTheRightConnected) + { + return PipeType.UpAndRight; + } + + if (isPipeAboveConnected && isPipeToTheLeftConnected) + { + return PipeType.UpAndLeft; + } + + if (isPipeBelowConnected && isPipeToTheRightConnected) + { + return PipeType.DownAndRight; + } + + if (isPipeBelowConnected && isPipeToTheLeftConnected) + { + return PipeType.DownAndLeft; + } + + return PipeType.Unknown; + } + + public List GetConnectingPipes(Pipe pipe) + { + var connectingPipes = new List(); + var isNotOnFirstRow = pipe.Coordinate.Row > 0; + var isNotOnFirstColumn = pipe.Coordinate.Column > 0; + var isNotOnLastRow = pipe.Coordinate.Row < Height - 1; + var isNotOnLastColumn = pipe.Coordinate.Column < Width - 1; + + switch (pipe.Type) + { + case PipeType.UpAndDown: + { + if (isNotOnFirstRow) + { + connectingPipes.Add( + Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column && p.Coordinate.Row == pipe.Coordinate.Row - 1) + ); + } + + if (isNotOnLastRow) + { + connectingPipes.Add( + Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column && p.Coordinate.Row == pipe.Coordinate.Row + 1) + ); + } + + break; + } + case PipeType.LeftAndRight: + { + if (isNotOnFirstColumn) + { + connectingPipes.Add( + Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column - 1 && p.Coordinate.Row == pipe.Coordinate.Row) + ); + } + + if (isNotOnLastColumn) + { + connectingPipes.Add( + Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column + 1 && p.Coordinate.Row == pipe.Coordinate.Row) + ); + } + + break; + } + case PipeType.UpAndRight: + { + if (isNotOnFirstRow) + { + connectingPipes.Add( + Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column && p.Coordinate.Row == pipe.Coordinate.Row - 1) + ); + } + + if (isNotOnLastColumn) + { + connectingPipes.Add( + Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column + 1 && p.Coordinate.Row == pipe.Coordinate.Row) + ); + } + + break; + } + case PipeType.UpAndLeft: + { + if (isNotOnFirstRow) + { + connectingPipes.Add( + Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column && p.Coordinate.Row == pipe.Coordinate.Row - 1) + ); + } + + if (isNotOnFirstColumn) + { + connectingPipes.Add( + Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column - 1 && p.Coordinate.Row == pipe.Coordinate.Row) + ); + } + + break; + } + case PipeType.DownAndRight: + { + if (isNotOnLastRow) + { + connectingPipes.Add( + Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column && p.Coordinate.Row == pipe.Coordinate.Row + 1) + ); + } + + if (isNotOnLastColumn) + { + connectingPipes.Add( + Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column + 1 && p.Coordinate.Row == pipe.Coordinate.Row) + ); + } + + break; + } + case PipeType.DownAndLeft: + { + if (isNotOnLastRow) + { + connectingPipes.Add( + Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column && p.Coordinate.Row == pipe.Coordinate.Row + 1) + ); + } + + if (isNotOnFirstColumn) + { + connectingPipes.Add( + Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column - 1 && p.Coordinate.Row == pipe.Coordinate.Row) + ); + } + + break; + } + case PipeType.Unknown: + { + if (isNotOnFirstRow) + { + connectingPipes.Add( + Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column && p.Coordinate.Row == pipe.Coordinate.Row - 1) + ); + } + + if (isNotOnLastColumn) + { + connectingPipes.Add( + Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column + 1 && p.Coordinate.Row == pipe.Coordinate.Row) + ); + } + + if (isNotOnLastRow) + { + connectingPipes.Add( + Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column && p.Coordinate.Row == pipe.Coordinate.Row + 1) + ); + } + + if (isNotOnFirstColumn) + { + connectingPipes.Add( + Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column - 1 && p.Coordinate.Row == pipe.Coordinate.Row) + ); + } + + break; + } + default: + break; + } + + return connectingPipes; + } + + public static Maze Parse(string[] input) + { + var width = input[0].Length; + var height = input.Length; + var pipes = new List(); + + for (var row = 0; row < height; row++) + { + for (var column = 0; column < width; column++) + { + var symbol = input[row][column]; + + if (_pipes.TryGetValue(symbol, out PipeType value)) + { + pipes.Add(new(symbol, value, row, column)); + } + } + } + + return new Maze(width, height, pipes); + } +} + +public class Pipe( + char symbol, + PipeType type, + int row, + int column +) +{ + public char Symbol { get; init; } = symbol; + public PipeType Type { get; init; } = type; + public PipeCoordinate Coordinate { get; init; } = new(column, row); +} + +public class PipeCoordinate( + int column, + int row +) : IEquatable +{ + public int Column { get; init; } = column; + public int Row { get; init; } = row; + + public bool Equals(PipeCoordinate? other) => + other is not null && + Column == other.Column && + Row == other.Row; +} + +public enum PipeType +{ + UpAndDown, // Vertical Pipe + LeftAndRight, // Horizontal Pipe + UpAndRight, // North-East Pipe + UpAndLeft, // North-West Pipe + DownAndRight, // South-East Pipe + DownAndLeft, // South-West Pipe + Unknown, // Starting Pipe +} \ No newline at end of file From 77e5ab80183dbce5411e2e4f79409494c5e7667a Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Mon, 11 Dec 2023 02:03:46 -0600 Subject: [PATCH 3/5] feat: solve part 2 --- 08/HauntedWasteland.Tests/GlobalUsings.cs | 2 +- 09/MirageMaintenance.Tests/GlobalUsings.cs | 2 +- 10/PipeMaze.Tests/GlobalUsings.cs | 3 +- 10/PipeMaze.Tests/MazeTests.cs | 79 +++++++++++++++++++++- 10/PipeMaze.Tests/PipeMaze.Tests.csproj | 6 ++ 10/PipeMaze/Program.cs | 53 ++++++++++++++- 6 files changed, 138 insertions(+), 7 deletions(-) diff --git a/08/HauntedWasteland.Tests/GlobalUsings.cs b/08/HauntedWasteland.Tests/GlobalUsings.cs index 2d5b473..d6f0167 100644 --- a/08/HauntedWasteland.Tests/GlobalUsings.cs +++ b/08/HauntedWasteland.Tests/GlobalUsings.cs @@ -1,3 +1,3 @@ global using FluentAssertions; -global using Xunit; +global using Xunit; \ No newline at end of file diff --git a/09/MirageMaintenance.Tests/GlobalUsings.cs b/09/MirageMaintenance.Tests/GlobalUsings.cs index 2d5b473..d6f0167 100644 --- a/09/MirageMaintenance.Tests/GlobalUsings.cs +++ b/09/MirageMaintenance.Tests/GlobalUsings.cs @@ -1,3 +1,3 @@ global using FluentAssertions; -global using Xunit; +global using Xunit; \ No newline at end of file diff --git a/10/PipeMaze.Tests/GlobalUsings.cs b/10/PipeMaze.Tests/GlobalUsings.cs index 7fef4b0..2d5b473 100644 --- a/10/PipeMaze.Tests/GlobalUsings.cs +++ b/10/PipeMaze.Tests/GlobalUsings.cs @@ -1,2 +1,3 @@ +global using FluentAssertions; + global using Xunit; -global using FluentAssertions; \ No newline at end of file diff --git a/10/PipeMaze.Tests/MazeTests.cs b/10/PipeMaze.Tests/MazeTests.cs index 0172ba7..30e6f0c 100644 --- a/10/PipeMaze.Tests/MazeTests.cs +++ b/10/PipeMaze.Tests/MazeTests.cs @@ -36,13 +36,25 @@ public class MazeTests [MemberData(nameof(TestData.FurthestStepFromStartTestData), MemberType = typeof(TestData))] public void FurthestStepFromStart_WhenGivenInput_ItShouldReturnExpectedFurthestStepFromStart(Maze maze, int expectedFurthestStepFromStart) { - maze.FarthestStepFromStart + maze.GetFarthestStepFromStart() .Should() .Be(expectedFurthestStepFromStart); } + [Theory] + [MemberData(nameof(TestData.AreaTestData), MemberType = typeof(TestData))] + public void Area_WhenGivenInput_ItShouldReturnExpectedArea(string[] input, int expectedArea) + { + var maze = Maze.Parse(input); + maze.GetAreaOfLoop() + .Should() + .Be(expectedArea); + } + public static class TestData { + private static readonly string[] Input = File.ReadAllLines("INPUT.txt"); + private static readonly string[] TestMazeInput = { ".....", @@ -68,6 +80,66 @@ public class MazeTests ] ); + public static IEnumerable AreaTestData => + new List + { + new object[] + { + new string[] + { + "...........", + ".S-------7.", + ".|F-----7|.", + ".||.....||.", + ".||.....||.", + ".|L-7.F-J|.", + ".|..|.|..|.", + ".L--J.L--J.", + "...........", + }, + 4, + }, + new object[] + { + new string[] + { + ".F----7F7F7F7F-7....", + ".|F--7||||||||FJ....", + ".||.FJ||||||||L7....", + "FJL7L7LJLJ||LJ.L-7..", + "L--J.L7...LJS7F-7L7.", + "....F-J..F7FJ|L7L7L7", + "....L7.F7||L7|.L7L7|", + ".....|FJLJ|FJ|F7|.LJ", + "....FJL-7.||.||||...", + "....L---J.LJ.LJLJ...", + }, + 8 + }, + new object[] + { + new string[] + { + "FF7FSF7F7F7F7F7F---7", + "L|LJ||||||||||||F--J", + "FL-7LJLJ||||||LJL-77", + "F--JF--7||LJLJ7F7FJ-", + "L---JF-JLJ.||-FJLJJ7", + "|F|F-JF---7F7-L7L|7|", + "|FFJF7L7F-JF7|JL---7", + "7-L-JL7||F7|L7F-7F7|", + "L.L7LFJ|||||FJL7||LJ", + "L7JLJL-JLJLJL--JLJ.L", + }, + 10 + }, + new object[] + { + Input, + 287, + } + }; + public static IEnumerable FurthestStepFromStartTestData => new List { @@ -112,6 +184,11 @@ public class MazeTests ] ), 8, + }, + new object[] + { + Maze.Parse(Input), + 6870, } }; diff --git a/10/PipeMaze.Tests/PipeMaze.Tests.csproj b/10/PipeMaze.Tests/PipeMaze.Tests.csproj index ee3cd62..29d03a6 100644 --- a/10/PipeMaze.Tests/PipeMaze.Tests.csproj +++ b/10/PipeMaze.Tests/PipeMaze.Tests.csproj @@ -27,4 +27,10 @@ + + + PreserveNewest + + + diff --git a/10/PipeMaze/Program.cs b/10/PipeMaze/Program.cs index ef145e1..0963e43 100644 --- a/10/PipeMaze/Program.cs +++ b/10/PipeMaze/Program.cs @@ -1,4 +1,5 @@ using System.Diagnostics; +using System.Runtime.CompilerServices; namespace PipeMaze; @@ -18,21 +19,31 @@ 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 = Maze.Parse(input).FarthestStepFromStart; + var maze = Maze.Parse(input); + var result = isPart2 ? maze.GetAreaOfLoop() : maze.GetFarthestStepFromStart(); stopwatch.Stop(); - Console.WriteLine($"The farthest step from the starting pipe is {result}. ({stopwatch.ElapsedMilliseconds}ms)"); + if (isPart2) + { + Console.WriteLine($"The area of the loop is {result}. ({stopwatch.ElapsedMilliseconds}ms)"); + } + else + { + Console.WriteLine($"The farthest step from the start is {result}. ({stopwatch.ElapsedMilliseconds}ms)"); + } return result; } } + public class Maze( int width, int height, @@ -56,7 +67,43 @@ public class Maze( public Pipe? StartingPipe => Pipes.FirstOrDefault(p => p.Type is PipeType.Unknown); - public int FarthestStepFromStart => GetLoop().Count / 2; + public int GetFarthestStepFromStart() => GetLoop().Count / 2; + + public int GetAreaOfLoop() + { + var count = 0; + var loop = GetLoop(); + var areInsideLoop = false; + var verticalBoundaries = new List() + { + PipeType.UpAndDown, + PipeType.UpAndRight, + PipeType.UpAndLeft, + }; + + for (var row = 0; row < Height; row++) + { + for (var column = 0; column < Width; column++) + { + var pipe = loop.FirstOrDefault(p => p.Coordinate.Column == column && p.Coordinate.Row == row); + + if (pipe is null && areInsideLoop is true) + { + count++; + } + + if ( + pipe is not null && + verticalBoundaries.Contains(pipe.Type) is true + ) + { + areInsideLoop = !areInsideLoop; + } + } + } + + return count; + } public List GetLoop() { From 307dc92ec97f99d4bb66284f39b99c4b3a124b45 Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Mon, 11 Dec 2023 02:19:07 -0600 Subject: [PATCH 4/5] chore: dotnet format --- 10/PipeMaze.Tests/GlobalUsings.cs | 2 +- 10/PipeMaze.Tests/MazeTests.cs | 15 ++- 10/PipeMaze/Program.cs | 190 +++++++++++++++++++++++++++--- 3 files changed, 183 insertions(+), 24 deletions(-) diff --git a/10/PipeMaze.Tests/GlobalUsings.cs b/10/PipeMaze.Tests/GlobalUsings.cs index 2d5b473..d6f0167 100644 --- a/10/PipeMaze.Tests/GlobalUsings.cs +++ b/10/PipeMaze.Tests/GlobalUsings.cs @@ -1,3 +1,3 @@ global using FluentAssertions; -global using Xunit; +global using Xunit; \ No newline at end of file diff --git a/10/PipeMaze.Tests/MazeTests.cs b/10/PipeMaze.Tests/MazeTests.cs index 30e6f0c..87caba6 100644 --- a/10/PipeMaze.Tests/MazeTests.cs +++ b/10/PipeMaze.Tests/MazeTests.cs @@ -8,8 +8,14 @@ public class MazeTests public void Parse_WhenGivenInput_ItShouldReturnExpectedMaze(string[] input, Maze expectedMaze, Pipe? expectedStartingPipe) { var maze = Maze.Parse(input); - maze.Should().BeEquivalentTo(expectedMaze); - maze.StartingPipe.Should().BeEquivalentTo(expectedStartingPipe); + + maze + .Should() + .BeEquivalentTo(expectedMaze); + + maze.StartingPipe + .Should() + .BeEquivalentTo(expectedStartingPipe); } [Theory] @@ -45,8 +51,9 @@ public class MazeTests [MemberData(nameof(TestData.AreaTestData), MemberType = typeof(TestData))] public void Area_WhenGivenInput_ItShouldReturnExpectedArea(string[] input, int expectedArea) { - var maze = Maze.Parse(input); - maze.GetAreaOfLoop() + Maze + .Parse(input) + .GetAreaOfLoop() .Should() .Be(expectedArea); } diff --git a/10/PipeMaze/Program.cs b/10/PipeMaze/Program.cs index 0963e43..b85b6ff 100644 --- a/10/PipeMaze/Program.cs +++ b/10/PipeMaze/Program.cs @@ -43,7 +43,13 @@ public class Program } } - +/// +/// Represents a maze of pipes. +/// +/// The width of the maze. +/// The height of the maze. +/// The pipes in the maze. +/// An instance of . public class Maze( int width, int height, @@ -61,14 +67,29 @@ public class Maze( { 'S', PipeType.Unknown }, }; - public int Width { get; init; } = width; - public int Height { get; init; } = height; + private int Width { get; init; } = width; + private int Height { get; init; } = height; + + /// + /// Gets the pipes in the maze. + /// public List Pipes { get; init; } = pipes; + /// + /// Gets the starting pipe in the maze. + /// public Pipe? StartingPipe => Pipes.FirstOrDefault(p => p.Type is PipeType.Unknown); + /// + /// Gets the farthest step from the start. + /// + /// The farthest step from the start. public int GetFarthestStepFromStart() => GetLoop().Count / 2; + /// + /// Gets the area of the loop. + /// + /// The area of the loop. public int GetAreaOfLoop() { var count = 0; @@ -81,17 +102,24 @@ public class Maze( PipeType.UpAndLeft, }; + // Loop through each row for (var row = 0; row < Height; row++) { + // Loop through each column in the row for (var column = 0; column < Width; column++) { + // Check if a pipe in loop exists at the current coordinate var pipe = loop.FirstOrDefault(p => p.Coordinate.Column == column && p.Coordinate.Row == row); + // If a pipe does not exist at the current coordinate + // and we are inside the loop, increment the count if (pipe is null && areInsideLoop is true) { count++; } + // If a pipe exists at the current coordinate and the pipe is + // representative of a vertical boundary, toggle the areInsideLoop flag if ( pipe is not null && verticalBoundaries.Contains(pipe.Type) is true @@ -105,6 +133,10 @@ public class Maze( return count; } + /// + /// Gets the loop in the maze. + /// + /// The loop in the maze. public List GetLoop() { if (StartingPipe is null) @@ -138,6 +170,10 @@ public class Maze( return loop; } + /// + /// Identifies the type of the starting pipe. + /// + /// The type of the starting pipe. public PipeType IdentifyStartPipeType() { if (StartingPipe is null) @@ -201,6 +237,11 @@ public class Maze( return PipeType.Unknown; } + /// + /// Gets the connecting pipes of the provided pipe. + /// + /// The pipe to get the connecting pipes of. + /// The connecting pipes of the provided pipe. public List GetConnectingPipes(Pipe pipe) { var connectingPipes = new List(); @@ -208,6 +249,10 @@ public class Maze( var isNotOnFirstColumn = pipe.Coordinate.Column > 0; var isNotOnLastRow = pipe.Coordinate.Row < Height - 1; var isNotOnLastColumn = pipe.Coordinate.Column < Width - 1; + var nextRow = pipe.Coordinate.Row + 1; + var nextColumn = pipe.Coordinate.Column + 1; + var previousRow = pipe.Coordinate.Row - 1; + var previousColumn = pipe.Coordinate.Column - 1; switch (pipe.Type) { @@ -216,14 +261,22 @@ public class Maze( if (isNotOnFirstRow) { connectingPipes.Add( - Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column && p.Coordinate.Row == pipe.Coordinate.Row - 1) + Pipes.FirstOrDefault( + p => + p.Coordinate.Column == pipe.Coordinate.Column && + p.Coordinate.Row == previousRow + ) ); } if (isNotOnLastRow) { connectingPipes.Add( - Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column && p.Coordinate.Row == pipe.Coordinate.Row + 1) + Pipes.FirstOrDefault( + p => + p.Coordinate.Column == pipe.Coordinate.Column && + p.Coordinate.Row == nextRow + ) ); } @@ -234,14 +287,22 @@ public class Maze( if (isNotOnFirstColumn) { connectingPipes.Add( - Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column - 1 && p.Coordinate.Row == pipe.Coordinate.Row) + Pipes.FirstOrDefault( + p => + p.Coordinate.Column == previousColumn && + p.Coordinate.Row == pipe.Coordinate.Row + ) ); } if (isNotOnLastColumn) { connectingPipes.Add( - Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column + 1 && p.Coordinate.Row == pipe.Coordinate.Row) + Pipes.FirstOrDefault( + p => + p.Coordinate.Column == nextColumn && + p.Coordinate.Row == pipe.Coordinate.Row + ) ); } @@ -252,14 +313,22 @@ public class Maze( if (isNotOnFirstRow) { connectingPipes.Add( - Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column && p.Coordinate.Row == pipe.Coordinate.Row - 1) + Pipes.FirstOrDefault( + p => + p.Coordinate.Column == pipe.Coordinate.Column && + p.Coordinate.Row == previousRow + ) ); } if (isNotOnLastColumn) { connectingPipes.Add( - Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column + 1 && p.Coordinate.Row == pipe.Coordinate.Row) + Pipes.FirstOrDefault( + p => + p.Coordinate.Column == nextColumn && + p.Coordinate.Row == pipe.Coordinate.Row + ) ); } @@ -270,14 +339,22 @@ public class Maze( if (isNotOnFirstRow) { connectingPipes.Add( - Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column && p.Coordinate.Row == pipe.Coordinate.Row - 1) + Pipes.FirstOrDefault( + p => + p.Coordinate.Column == pipe.Coordinate.Column && + p.Coordinate.Row == previousRow + ) ); } if (isNotOnFirstColumn) { connectingPipes.Add( - Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column - 1 && p.Coordinate.Row == pipe.Coordinate.Row) + Pipes.FirstOrDefault( + p => + p.Coordinate.Column == previousColumn && + p.Coordinate.Row == pipe.Coordinate.Row + ) ); } @@ -288,14 +365,22 @@ public class Maze( if (isNotOnLastRow) { connectingPipes.Add( - Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column && p.Coordinate.Row == pipe.Coordinate.Row + 1) + Pipes.FirstOrDefault( + p => + p.Coordinate.Column == pipe.Coordinate.Column && + p.Coordinate.Row == nextRow + ) ); } if (isNotOnLastColumn) { connectingPipes.Add( - Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column + 1 && p.Coordinate.Row == pipe.Coordinate.Row) + Pipes.FirstOrDefault( + p => + p.Coordinate.Column == nextColumn && + p.Coordinate.Row == pipe.Coordinate.Row + ) ); } @@ -306,14 +391,22 @@ public class Maze( if (isNotOnLastRow) { connectingPipes.Add( - Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column && p.Coordinate.Row == pipe.Coordinate.Row + 1) + Pipes.FirstOrDefault( + p => + p.Coordinate.Column == pipe.Coordinate.Column && + p.Coordinate.Row == nextRow + ) ); } if (isNotOnFirstColumn) { connectingPipes.Add( - Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column - 1 && p.Coordinate.Row == pipe.Coordinate.Row) + Pipes.FirstOrDefault( + p => + p.Coordinate.Column == previousColumn && + p.Coordinate.Row == pipe.Coordinate.Row + ) ); } @@ -324,28 +417,44 @@ public class Maze( if (isNotOnFirstRow) { connectingPipes.Add( - Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column && p.Coordinate.Row == pipe.Coordinate.Row - 1) + Pipes.FirstOrDefault( + p => + p.Coordinate.Column == pipe.Coordinate.Column && + p.Coordinate.Row == previousRow + ) ); } if (isNotOnLastColumn) { connectingPipes.Add( - Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column + 1 && p.Coordinate.Row == pipe.Coordinate.Row) + Pipes.FirstOrDefault( + p => + p.Coordinate.Column == nextColumn && + p.Coordinate.Row == pipe.Coordinate.Row + ) ); } if (isNotOnLastRow) { connectingPipes.Add( - Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column && p.Coordinate.Row == pipe.Coordinate.Row + 1) + Pipes.FirstOrDefault( + p => + p.Coordinate.Column == pipe.Coordinate.Column && + p.Coordinate.Row == nextRow + ) ); } if (isNotOnFirstColumn) { connectingPipes.Add( - Pipes.FirstOrDefault(p => p.Coordinate.Column == pipe.Coordinate.Column - 1 && p.Coordinate.Row == pipe.Coordinate.Row) + Pipes.FirstOrDefault( + p => + p.Coordinate.Column == previousColumn && + p.Coordinate.Row == pipe.Coordinate.Row + ) ); } @@ -358,6 +467,11 @@ public class Maze( return connectingPipes; } + /// + /// Parses the provided input into a maze. + /// + /// The input to parse. + /// An instance of . public static Maze Parse(string[] input) { var width = input[0].Length; @@ -381,6 +495,14 @@ public class Maze( } } +/// +/// Represents a pipe in a maze. +/// +/// The symbol of the pipe. +/// The type of the pipe. +/// The row of the pipe. +/// The column of the pipe. +/// An instance of . public class Pipe( char symbol, PipeType type, @@ -388,25 +510,55 @@ public class Pipe( int column ) { + /// + /// Gets the symbol of the pipe. + /// public char Symbol { get; init; } = symbol; + + /// + /// Gets the type of the pipe. + /// public PipeType Type { get; init; } = type; + + /// + /// Gets the coordinate of the pipe. + /// public PipeCoordinate Coordinate { get; init; } = new(column, row); } +/// +/// Represents a coordinate of a pipe in a maze. +/// +/// The column of the pipe. +/// The row of the pipe. +/// An instance of . public class PipeCoordinate( int column, int row ) : IEquatable { + /// + /// Gets the column of the pipe. + /// public int Column { get; init; } = column; + + /// + /// Gets the row of the pipe. + /// public int Row { get; init; } = row; + /// + /// Determines whether the provided object is equal to the current object. + /// public bool Equals(PipeCoordinate? other) => other is not null && Column == other.Column && Row == other.Row; } +/// +/// Represents the type of a pipe in a maze. +/// public enum PipeType { UpAndDown, // Vertical Pipe From dc5d18bbef7bfe1d942528ac901e5e437913fdad Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Mon, 11 Dec 2023 02:20:35 -0600 Subject: [PATCH 5/5] docs: update README.md --- README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index df65687..7ceeeee 100644 --- a/README.md +++ b/README.md @@ -42,18 +42,18 @@ dotnet build ## Challenges -| Day | Problem | Solution | Status | Notes | -| --- | -------------------------- | :---------------------------------: | :----: | ------------------------------------------------------------------------------------------------------------------------------------ | -| 01 | [Problem](./01/PROBLEM.md) | [Solution](./01/Trebuchet/) | ✅ | The trickiest part here was accounting for overlapping digit words. | -| 02 | [Problem](./02/PROBLEM.md) | [Solution](./02/CubeConundrum/) | ✅ | The key to me here was to parse the input into a useful model. | -| 03 | [Problem](./03/PROBLEM.md) | [Solution](./03/GearRatios/) | ✅ | The edge case that got me here was lines ending with a part number. | -| 04 | [Problem](./04/PROBLEM.md) | [Solution](./04/Scratchcards/) | ✅ | Part 2 gets out of hand quickly with just 200 cards. | -| 05 | [Problem](./05/PROBLEM.md) | [Solution](./05/IYGASAF/) | ✅ | I brute forced part 2 using parallelism. I know shame. | -| 06 | [Problem](./06/PROBLEM.md) | [Solution](./06/WaitForIt/) | ✅ | Thank goodness part 2 was not like 5's part 2. 😅 | -| 07 | [Problem](./07/PROBLEM.md) | [Solution](./07/CamelCards/) | ✅ | What took me longest here was I missed a case when jokers are wild and there are three groups of cards. | -| 08 | [Problem](./08/PROBLEM.md) | [Solution](./08/HauntedWasteland/) | ✅ | Got to implement a least common multiple algorithm for part 2. | -| 09 | [Problem](./09/PROBLEM.md) | [Solution](./09/MirageMaintenance/) | ✅ | Part 1 took me unnecessarily long. The bug was summing a line to check for all zeros is bad idea when negative numbers are involved. | -| 10 | [Problem](./10/PROBLEM.md) | [Solution](./10/) | ⌛ | +| Day | Problem | Solution | Status | Notes | +| --- | -------------------------- | :---------------------------------: | :----: | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| 01 | [Problem](./01/PROBLEM.md) | [Solution](./01/Trebuchet/) | ✅ | The trickiest part here was accounting for overlapping digit words. | +| 02 | [Problem](./02/PROBLEM.md) | [Solution](./02/CubeConundrum/) | ✅ | The key to me here was to parse the input into a useful model. | +| 03 | [Problem](./03/PROBLEM.md) | [Solution](./03/GearRatios/) | ✅ | The edge case that got me here was lines ending with a part number. | +| 04 | [Problem](./04/PROBLEM.md) | [Solution](./04/Scratchcards/) | ✅ | Part 2 gets out of hand quickly with just 200 cards. | +| 05 | [Problem](./05/PROBLEM.md) | [Solution](./05/IYGASAF/) | ✅ | I brute forced part 2 using parallelism. I know shame. | +| 06 | [Problem](./06/PROBLEM.md) | [Solution](./06/WaitForIt/) | ✅ | Thank goodness part 2 was not like 5's part 2. 😅 | +| 07 | [Problem](./07/PROBLEM.md) | [Solution](./07/CamelCards/) | ✅ | What took me longest here was I missed a case when jokers are wild and there are three groups of cards. | +| 08 | [Problem](./08/PROBLEM.md) | [Solution](./08/HauntedWasteland/) | ✅ | Got to implement a least common multiple algorithm for part 2. | +| 09 | [Problem](./09/PROBLEM.md) | [Solution](./09/MirageMaintenance/) | ✅ | Part 1 took me unnecessarily long. The bug was summing a line to check for all zeros is bad idea when negative numbers are involved. | +| 10 | [Problem](./10/PROBLEM.md) | [Solution](./10/PipeMaze/) | ✅ | So...my solutions are rather slow, but they work. Part 2 appears to have a mathematical solution, but scanning is what I came up with on my own. | | 11 | [Problem](./11/PROBLEM.md) | [Solution](./11/) | ⌛ | | 12 | [Problem](./12/PROBLEM.md) | [Solution](./12/) | ⌛ | | 13 | [Problem](./13/PROBLEM.md) | [Solution](./13/) | ⌛ |