diff --git a/02/CubeConundrum.Tests/GameTests.cs b/02/CubeConundrum.Tests/GameTests.cs new file mode 100644 index 0000000..a3f8843 --- /dev/null +++ b/02/CubeConundrum.Tests/GameTests.cs @@ -0,0 +1,52 @@ +namespace CubeConundrum.Tests; + +public class GameTests +{ + [Theory, MemberData(nameof(TestData.Games), MemberType = typeof(TestData))] + public void PowerOfMinimumCubesNeeded_GivenAGame_ItShouldReturnTheSumOfTheMinimumCubesNeededForEachResult(Game game, int expected) + { + game.PowerOfMinimumCubesNeeded.Should().Be(expected); + } + + public static class TestData + { + public static readonly IEnumerable Games = new List + { + new object[] + { + new Game + { + Id = 1, + Results = + { + new() + { + Cubes = + { + new() { Count = 3, Color = CubeColor.Blue }, + new() { Count = 4, Color = CubeColor.Red } + } + }, + new() + { + Cubes = + { + new() { Count = 1, Color = CubeColor.Red }, + new() { Count = 2, Color = CubeColor.Green }, + new() { Count = 6, Color = CubeColor.Blue } + } + }, + new() + { + Cubes = + { + new() { Count = 2, Color = CubeColor.Green }, + } + } + } + }, + 48 + } + }; + } +} \ No newline at end of file diff --git a/02/CubeConundrum.Tests/ProgramTests.cs b/02/CubeConundrum.Tests/ProgramTests.cs index 5148b3d..09476f8 100644 --- a/02/CubeConundrum.Tests/ProgramTests.cs +++ b/02/CubeConundrum.Tests/ProgramTests.cs @@ -8,4 +8,11 @@ public class ProgramTests var result = await Program.Main(["INPUT.txt"]); result.Should().Be(2879); } + + [Fact] + public async Task Main_GivenInputAndPart2_ItShouldReturnExpectedSum() + { + var result = await Program.Main(["INPUT.txt", "part2"]); + result.Should().Be(65122); + } } \ No newline at end of file diff --git a/02/CubeConundrum.Tests/PartOnePuzzleSolverTests.cs b/02/CubeConundrum.Tests/PuzzelSolverTests.cs similarity index 97% rename from 02/CubeConundrum.Tests/PartOnePuzzleSolverTests.cs rename to 02/CubeConundrum.Tests/PuzzelSolverTests.cs index ba7acaa..e8ed0ba 100644 --- a/02/CubeConundrum.Tests/PartOnePuzzleSolverTests.cs +++ b/02/CubeConundrum.Tests/PuzzelSolverTests.cs @@ -1,8 +1,8 @@ namespace CubeConundrum.Tests; -public class PartOnePuzzleSolverTests +public class PuzzleSolverTests { - private readonly PartOnePuzzleSolver _sut = new(); + private readonly PuzzleSolver _sut = new(); [Theory, MemberData(nameof(TestData.Results), MemberType = typeof(TestData))] public void IsResultPossible_GivenAResult_ItShouldReturnExpectedOutcome(Result givenResult, bool expected) diff --git a/02/CubeConundrum.Tests/PuzzleParserTests.cs b/02/CubeConundrum.Tests/PuzzleParserTests.cs index 5ac4fa8..23d4066 100644 --- a/02/CubeConundrum.Tests/PuzzleParserTests.cs +++ b/02/CubeConundrum.Tests/PuzzleParserTests.cs @@ -5,7 +5,7 @@ public class PuzzleParserTests private readonly PuzzleParser _sut = new(); [Theory, MemberData(nameof(TestData.CubeStrings), MemberType = typeof(TestData))] - public void ParseCube_GivenAStringThatRepresentsACube_ItShouldReturnTheEquivalentCubeModel(string input, Cube expected) + public void ParseCube_GivenAStringThatRepresentsACube_ItShouldReturnTheEquivalentCubeModel(string input, CubeCollection expected) { var result = _sut.ParseCube(input); result.Should().BeEquivalentTo(expected); @@ -29,9 +29,9 @@ public class PuzzleParserTests { public static readonly IEnumerable CubeStrings = new List { - new object[] { "4 red", new Cube { Count = 4, Color = CubeColor.Red } }, - new object[] { "1 green", new Cube { Count = 1, Color = CubeColor.Green } }, - new object[] { "2 blue", new Cube { Count = 2, Color = CubeColor.Blue } } + new object[] { "4 red", new CubeCollection { Count = 4, Color = CubeColor.Red } }, + new object[] { "1 green", new CubeCollection { Count = 1, Color = CubeColor.Green } }, + new object[] { "2 blue", new CubeCollection { Count = 2, Color = CubeColor.Blue } } }; public static readonly IEnumerable ResultStrings = new List diff --git a/02/CubeConundrum/Program.cs b/02/CubeConundrum/Program.cs index b1d5b08..c9558a4 100644 --- a/02/CubeConundrum/Program.cs +++ b/02/CubeConundrum/Program.cs @@ -7,21 +7,24 @@ public class Program if (args.Length is 0) { Console.WriteLine("Please provide a path to the input file."); - return 1; + return -1; } if (File.Exists(args[0]) is false) { Console.WriteLine("The provided file does not exist."); - return 2; + return -2; } var puzzleParser = new PuzzleParser(); - var puzzleSolver = new PartOnePuzzleSolver(); + var puzzleSolver = new PuzzleSolver(); var input = await File.ReadAllLinesAsync(args[0]); var games = input.Select(puzzleParser.ParseGame); - var result = puzzleSolver.SumPossibleGameIds(games); + + var result = args.Length > 1 && args[1] == "part2" + ? puzzleSolver.SumGameMinimumPowers(games) + : puzzleSolver.SumPossibleGameIds(games); Console.WriteLine($"The sum of all possible game ids is {result}."); @@ -29,28 +32,78 @@ public class Program } } -public class PartOnePuzzleSolver +/// +/// Puzzle solver. +/// +public class PuzzleSolver { + /// + /// The maximum number of cubes that can be used in a game. + /// private readonly int _maxCubeCount = 39; + + /// + /// The maximum number of red cubes that can be used in a game. + /// private readonly int _maxRedCubeCount = 12; + + /// + /// The maximum number of green cubes that can be used in a game. + /// private readonly int _maxGreenCubeCount = 13; + + /// + /// The maximum number of blue cubes that can be used in a game. + /// private readonly int _maxBlueCubeCount = 14; + /// + /// Determines whether a result is possible. + /// + /// The result to check. + /// True if the result is possible, otherwise false. public bool IsResultPossible(Result result) => result.TotalCubeCount <= _maxCubeCount && result.RedCubeCount <= _maxRedCubeCount && result.GreenCubeCount <= _maxGreenCubeCount && result.BlueCubeCount <= _maxBlueCubeCount; + /// + /// Determines whether a game is possible. + /// + /// The game to check. + /// True if the game is possible, otherwise false. public bool IsGamePossible(Game game) => game.Results.All(IsResultPossible); + /// + /// Sums all possible game ids. + /// + /// The games to sum. + /// The sum of all possible game ids. public int SumPossibleGameIds(IEnumerable games) => games .Where(IsGamePossible) .Sum(g => g.Id); + + /// + /// Sums the minimum powers of all games. + /// + /// The games to sum. + /// The sum of the minimum powers of all games. + public int SumGameMinimumPowers(IEnumerable games) => games + .Select(g => g.PowerOfMinimumCubesNeeded) + .Sum(); } +/// +/// Puzzle parser responsible for parsing puzzle input. +/// public class PuzzleParser { - public Cube ParseCube(string cubeString) + /// + /// Parses a cube from a string. + /// + /// The string to parse. + /// An instance of . + public CubeCollection ParseCube(string cubeString) { var parts = cubeString.Split(' '); var count = int.Parse(parts[0]); @@ -63,6 +116,11 @@ public class PuzzleParser }; } + /// + /// Parses a result from a string. + /// + /// The string to parse. + /// An instance of . public Result ParseResult(string resultString) { var cubes = resultString @@ -77,6 +135,11 @@ public class PuzzleParser }; } + /// + /// Parses a game from a string. + /// + /// The string to parse. + /// An instance of . public Game ParseGame(string gameString) { var parts = gameString.Split(':'); @@ -95,30 +158,95 @@ public class PuzzleParser } } +/// +/// Represents a game. +/// public class Game { + /// + /// The id of the game. + /// public int Id { get; set; } + + /// + /// The results of the game. + /// public List Results { get; set; } = []; + + private int MinimumRedCubesNeeded => Results.Max(r => r.RedCubeCount); + private int MinimumGreenCubesNeeded => Results.Max(r => r.GreenCubeCount); + private int MinimumBlueCubesNeeded => Results.Max(r => r.BlueCubeCount); + + /// + /// The power of the minimum number of each cube type needed to play the game. + /// + public int PowerOfMinimumCubesNeeded => MinimumRedCubesNeeded * MinimumGreenCubesNeeded * MinimumBlueCubesNeeded; } +/// +/// Represents a result. +/// public class Result { - public List Cubes { get; set; } = []; + /// + /// The cubes in the result. + /// + public List Cubes { get; set; } = []; + + /// + /// The total number of cubes in the result. + /// public int TotalCubeCount => Cubes.Sum(c => c.Count); + + /// + /// The number of red cubes in the result. + /// public int RedCubeCount => Cubes.Where(c => c.Color == CubeColor.Red).Sum(c => c.Count); + + /// + /// The number of green cubes in the result. + /// public int GreenCubeCount => Cubes.Where(c => c.Color == CubeColor.Green).Sum(c => c.Count); + + /// + /// The number of blue cubes in the result. + /// public int BlueCubeCount => Cubes.Where(c => c.Color == CubeColor.Blue).Sum(c => c.Count); } -public class Cube +/// +/// Represents cubes of a given color. +/// +public class CubeCollection { + /// + /// The number of cubes. + /// public int Count { get; set; } + + /// + /// The color of the cubes. + /// public CubeColor Color { get; set; } } +/// +/// Represents a cube color. +/// public enum CubeColor { + /// + /// The red cube color. + /// Red, + + /// + /// The green cube color. + /// Green, + + /// + /// The blue cube color. + /// Blue } \ No newline at end of file