Files
advent-of-code-2023/04/Scratchcards/Program.cs
T

171 lines
4.3 KiB
C#
Raw Normal View History

2023-12-04 10:32:14 -06:00
namespace Scratchcards;
public class Program
{
public static async Task<int> 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]);
2023-12-04 13:29:25 -06:00
var result = args.Length is 2 && args[1] == "part2"
? puzzleSolver.GetTotalCardCount(input)
: puzzleSolver.SumCardValues(input);
2023-12-04 10:32:14 -06:00
2023-12-04 13:29:25 -06:00
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}.");
}
2023-12-04 10:32:14 -06:00
return result;
}
}
2023-12-04 13:29:25 -06:00
/// <summary>
/// Solves the puzzle.
/// </summary>
2023-12-04 10:32:14 -06:00
public class PuzzleSolver
{
2023-12-04 13:29:25 -06:00
/// <summary>
/// Sums the value of the cards.
/// </summary>
/// <param name="cards">The cards.</param>
/// <returns>The sum of the cards.</returns>
2023-12-04 10:32:14 -06:00
public int SumCardValues(string[] cards) => cards
.Select(Card.Parse)
.Sum(c => c.GetCardValue());
2023-12-04 13:29:25 -06:00
/// <summary>
/// Gets the total number of cards.
/// </summary>
/// <param name="cards">The cards.</param>
/// <returns>The total number of cards.</returns>
public int GetTotalCardCount(string[] cards)
{
var cardStringsToProcess = new List<string>(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;
}
2023-12-04 10:32:14 -06:00
}
2023-12-04 13:29:25 -06:00
/// <summary>
/// Represents a card.
/// </summary>
/// <param name="id">The identifier.</param>
/// <param name="winningNumbers">The winning numbers.</param>
/// <param name="numbers">The numbers.</param>
/// <returns>An instance of <see cref="Card"/>.</returns>
2023-12-04 10:32:14 -06:00
public class Card(
int id,
List<int> winningNumbers,
List<int> numbers
)
{
2023-12-04 13:29:25 -06:00
/// <summary>
/// Gets the identifier.
/// </summary>
2023-12-04 10:32:14 -06:00
public int Id { get; init; } = id;
2023-12-04 13:29:25 -06:00
/// <summary>
/// Gets the winning numbers.
/// </summary>
2023-12-04 10:32:14 -06:00
public List<int> WinningNumbers { get; init; } = winningNumbers;
2023-12-04 13:29:25 -06:00
/// <summary>
/// Gets the numbers.
/// </summary>
2023-12-04 10:32:14 -06:00
public List<int> Numbers { get; init; } = numbers;
2023-12-04 13:29:25 -06:00
/// <summary>
/// Gets the matching numbers.
/// </summary>
public List<int> MatchingNumbers => Numbers.Intersect(WinningNumbers).ToList();
2023-12-04 10:32:14 -06:00
2023-12-04 13:29:25 -06:00
/// <summary>
/// Gets the value of the card.
/// </summary>
/// <returns>The value of the card.</returns>
public int GetCardValue() => MatchingNumbers.Count is 1
? 1
: (int)Math.Pow(2, MatchingNumbers.Count - 1);
2023-12-04 10:32:14 -06:00
2023-12-04 13:29:25 -06:00
/// <summary>
/// Parses the specified input.
/// </summary>
/// <param name="input">The input.</param>
/// <returns>An instance of <see cref="Card"/>.</returns>
2023-12-04 10:32:14 -06:00
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);
}
}