From 9f2ccdf17fc6647894afbe6fb70ba905c1c8eeee Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Mon, 4 Dec 2023 10:32:14 -0600 Subject: [PATCH] feat: solve part 1 of puzzle 3 --- 04/Scratchcards.Tests/CardTests.cs | 105 ++++++++++++++++++ 04/Scratchcards.Tests/GlobalUsings.cs | 3 +- 04/Scratchcards.Tests/PuzzleSolverTests.cs | 42 +++++++ .../Scratchcards.Tests.csproj | 6 + 04/Scratchcards.Tests/UnitTest1.cs | 10 -- 04/Scratchcards/Program.cs | 97 +++++++++++++++- 6 files changed, 250 insertions(+), 13 deletions(-) create mode 100644 04/Scratchcards.Tests/CardTests.cs create mode 100644 04/Scratchcards.Tests/PuzzleSolverTests.cs delete mode 100644 04/Scratchcards.Tests/UnitTest1.cs diff --git a/04/Scratchcards.Tests/CardTests.cs b/04/Scratchcards.Tests/CardTests.cs new file mode 100644 index 0000000..2430574 --- /dev/null +++ b/04/Scratchcards.Tests/CardTests.cs @@ -0,0 +1,105 @@ +namespace Scratchcards.Tests; + +public class CardTests +{ + [Theory] + [MemberData(nameof(TestData.ParseCardData), MemberType = typeof(TestData))] + public void Parse_GivenInput_ItShouldReturnExpectedCard(string input, Card expected) + { + var result = Card.Parse(input); + result.Should().BeEquivalentTo(expected); + } + + [Theory] + [MemberData(nameof(TestData.GetCardValueData), MemberType = typeof(TestData))] + public void GetCardValue_GivenCard_ItShouldReturnExpectedValue(Card card, int expected) + { + var result = card.GetCardValue(); + result.Should().Be(expected); + } + + public static class TestData + { + private static readonly Dictionary TestCards = + new() + { + { + "Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53", + new Card( + 1, + [41, 48, 83, 86, 17], + [83, 86, 6, 31, 17, 9, 48, 53] + ) + }, + { + "Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19", + new Card( + 2, + [13, 32, 20, 16, 61], + [61, 30, 68, 82, 17, 32, 24, 19] + ) + }, + { + "Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1", + new Card( + 3, + [1, 21, 53, 59, 44], + [69, 82, 63, 72, 16, 21, 14, 1] + ) + }, + { + "Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83", + new Card( + 4, + [41, 92, 73, 84, 69], + [59, 84, 76, 51, 58, 5, 54, 83] + ) + }, + { + "Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36", + new Card( + 5, + [87, 83, 26, 28, 32], + [88, 30, 70, 12, 93, 22, 82, 36] + ) + }, + { + "Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11", + new Card( + 6, + [31, 18, 13, 56, 72], + [74, 77, 10, 23, 35, 67, 36, 11] + ) + }, + }; + + public static IEnumerable ParseCardData => + TestCards + .Select(kvp => new object[] { kvp.Key, kvp.Value }) + .ToList(); + + public static IEnumerable GetCardValueData() + { + for (var i = 0; i < TestCards.Count; i++) + { + var currentCard = TestCards.ElementAt(i); + var expectedValue = i switch + { + 0 => 8, + 1 => 2, + 2 => 2, + 3 => 1, + 4 => 0, + 5 => 0, + _ => throw new Exception("Unexpected card index"), + }; + + yield return new object[] + { + currentCard.Value, + expectedValue + }; + } + } + } +} \ No newline at end of file diff --git a/04/Scratchcards.Tests/GlobalUsings.cs b/04/Scratchcards.Tests/GlobalUsings.cs index 8c927eb..7fef4b0 100644 --- a/04/Scratchcards.Tests/GlobalUsings.cs +++ b/04/Scratchcards.Tests/GlobalUsings.cs @@ -1 +1,2 @@ -global using Xunit; \ No newline at end of file +global using Xunit; +global using FluentAssertions; \ No newline at end of file diff --git a/04/Scratchcards.Tests/PuzzleSolverTests.cs b/04/Scratchcards.Tests/PuzzleSolverTests.cs new file mode 100644 index 0000000..2a14baa --- /dev/null +++ b/04/Scratchcards.Tests/PuzzleSolverTests.cs @@ -0,0 +1,42 @@ +namespace Scratchcards.Tests; + +public class PuzzleSolverTests +{ + private readonly PuzzleSolver _sut = new(); + + [Theory] + [MemberData(nameof(TestData.SumCardValuesData), MemberType = typeof(TestData))] + public void SumCardValues_GivenCards_ItShouldReturnExpectedValue(string[] cards, int expected) + { + var result = _sut.SumCardValues(cards); + result.Should().Be(expected); + } + + public static class TestData + { + private static string[] Input => File.ReadAllLines("INPUT.txt"); + + public static IEnumerable SumCardValuesData => + new List + { + new object[] + { + new[] + { + "Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53", + "Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19", + "Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1", + "Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83", + "Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36", + "Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11", + }, + 13, + }, + new object[] + { + Input, + 23235, + }, + }; + } +} \ No newline at end of file diff --git a/04/Scratchcards.Tests/Scratchcards.Tests.csproj b/04/Scratchcards.Tests/Scratchcards.Tests.csproj index 6793136..530763c 100644 --- a/04/Scratchcards.Tests/Scratchcards.Tests.csproj +++ b/04/Scratchcards.Tests/Scratchcards.Tests.csproj @@ -27,4 +27,10 @@ + + + PreserveNewest + + + diff --git a/04/Scratchcards.Tests/UnitTest1.cs b/04/Scratchcards.Tests/UnitTest1.cs deleted file mode 100644 index 822f43f..0000000 --- a/04/Scratchcards.Tests/UnitTest1.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Scratchcards.Tests; - -public class UnitTest1 -{ - [Fact] - public void Test1() - { - - } -} \ No newline at end of file diff --git a/04/Scratchcards/Program.cs b/04/Scratchcards/Program.cs index 3751555..e0acc3b 100644 --- a/04/Scratchcards/Program.cs +++ b/04/Scratchcards/Program.cs @@ -1,2 +1,95 @@ -// See https://aka.ms/new-console-template for more information -Console.WriteLine("Hello, World!"); +namespace Scratchcards; + +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 puzzleSolver = new PuzzleSolver(); + + var input = await File.ReadAllLinesAsync(args[0]); + var result = puzzleSolver.SumCardValues(input); + + Console.WriteLine($"The sum of all card values is {result}."); + + return result; + } +} + +public class PuzzleSolver +{ + public int SumCardValues(string[] cards) => cards + .Select(Card.Parse) + .Sum(c => c.GetCardValue()); +} + +public class Card( + int id, + List winningNumbers, + List numbers +) +{ + public int Id { get; init; } = id; + public List WinningNumbers { get; init; } = winningNumbers; + public List Numbers { get; init; } = numbers; + + public int GetCardValue() + { + var commonNumbers = WinningNumbers.Intersect(Numbers).ToList(); + + return commonNumbers.Count is 1 + ? 1 + : (int)Math.Pow(2, commonNumbers.Count - 1); + } + + public static Card Parse(string input) + { + var parts = input.Split(':'); + var cardId = int.Parse( + parts[0].Split( + ' ', + StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries + )[1] + ); + + var numberStrings = parts[1].Trim(); + var numberParts = numberStrings + .Split('|') + .Select(s => s.Trim()) + .ToArray(); + + var winningNumbersString = numberParts[0]; + var numbersString = numberParts[1]; + + var winningNumbers = winningNumbersString + .Split( + ' ', + StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries + ) + .Select(s => s.Trim()) + .Select(int.Parse) + .ToList(); + + var numbers = numbersString + .Split( + ' ', + StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries + ) + .Select(s => s.Trim()) + .Select(int.Parse) + .ToList(); + + return new Card(cardId, winningNumbers, numbers); + } +} \ No newline at end of file