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 = args.Length is 2 && args[1] == "part2" ? puzzleSolver.GetTotalCardCount(input) : puzzleSolver.SumCardValues(input); if (args.Length is 2 && args[1] == "part2") { Console.WriteLine($"The total number of cards is {result}."); } else { Console.WriteLine($"The total value of the cards is {result}."); } return result; } } /// /// Solves the puzzle. /// public class PuzzleSolver { /// /// Sums the value of the cards. /// /// The cards. /// The sum of the cards. public int SumCardValues(string[] cards) => cards .Select(Card.Parse) .Sum(c => c.GetCardValue()); /// /// Gets the total number of cards. /// /// The cards. /// The total number of cards. public int GetTotalCardCount(string[] cards) { var cardStringsToProcess = new List(cards); for (var i = 0; i < cardStringsToProcess.Count; i++) { var currentCardString = cardStringsToProcess[i]; var currentCardStringIndex = Array.IndexOf(cards, currentCardString); var currentCard = Card.Parse(currentCardString); var numOfMatchingNumbersForCurrentCard = currentCard.MatchingNumbers.Count; var cardIndexesToCopy = Enumerable.Range( currentCardStringIndex + 1, Math.Min( numOfMatchingNumbersForCurrentCard, cards.Length - currentCardStringIndex - 1 ) ); foreach (var index in cardIndexesToCopy) { cardStringsToProcess.Add(cards[index]); } } return cardStringsToProcess.Count; } } /// /// Represents a card. /// /// The identifier. /// The winning numbers. /// The numbers. /// An instance of . public class Card( int id, List winningNumbers, List numbers ) { /// /// Gets the identifier. /// public int Id { get; init; } = id; /// /// Gets the winning numbers. /// public List WinningNumbers { get; init; } = winningNumbers; /// /// Gets the numbers. /// public List Numbers { get; init; } = numbers; /// /// Gets the matching numbers. /// public List MatchingNumbers => Numbers.Intersect(WinningNumbers).ToList(); /// /// Gets the value of the card. /// /// The value of the card. public int GetCardValue() => MatchingNumbers.Count is 1 ? 1 : (int)Math.Pow(2, MatchingNumbers.Count - 1); /// /// Parses the specified input. /// /// The input. /// An instance of . 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); } }