I've actually made a similar project myself, it's really good fun!
1. Keeping track of scores
First thing I noticed is that you keep track of the sum of the values for the player and presumably also for the dealer, but the score of a hand can actually change dramatically while playing.
1.1. Soft totals in blackjack
Blackjack has this concept called soft totals, which means the total sum can have a different value depending on if there's an ace or not. For example, if a player has an ace (1) and a 7, that actually counts as 18 (11 + 7). But if that same player draws another 7, their total will be 15 (1 + 7 + 7). The value of the ace changes as you draw more cards, so you'll have an easier time keeping scores if you somehow keep the cards separated from each other. This can be done using collections.
1.2. Collections
Collections are things like arrays (which you've already used), lists and dictionaries. A list of integers is a good candidate to represent a player's (or the dealer's) current collection of cards, because they can change sizes without complaining. Moreover, lists have built-in functions for getting sum of all the numbers inside them, the minimum and the maximum values of the list and plenty more. You can use those built-in functions to your advantage, as well as the fact that you always know the numbers inside the list to determine if someone's total is soft or not.
2. Game loop
The game of blackjack is played with a finite number of cards in real life, but of course in code you don't have to worry about that. If an (un)lucky player keeps drawing aces, they'll eventually still hit 21 and end the round. However, since you can't predict when a player (or the dealer) is going to lose, you can use something called a game loop. The game loop for blackjack starts executing all the game logic once a player or the dealer confirms that they want to draw a card, and once it's done executing, it'll ask to repeat if necessary.
2.1. Conditions for choosing another card
You'll notice that the player has a lot of freedom in blackjack, they can keep drawing cards until they get 21 or go over, at which point the round ends for them. The dealer, however, doesn't have that freedom. You can find more information on that online.
Either way, if you think about it, both the player and the dealer at some point make the decision to either draw or not to draw another card. You do a check for "Y"
or "N"
when given an input, which makes sense.
2.2. Translating text input to true
or false
Your DrawChoice
method alters a bool
depending on the player's input, but you could also refactor that method so that it receives a string
and returns a bool
. That way, you can directly translate the user's input to true
(yes, give me another card) or false
(no, I don't want another card). It could look something like this:
// One option
public static bool DrawChoice(string input)
{
if (input == "Y" || input == "y") // You could also use input.ToLower() == "y"
{
return true;
}
else // If it's not "Y" or "y", it's gonna be "N" or "n"
{
return false;
}
// else if (input == "N" || input == "n")
// {
// return false;
// }
}
// Alternative one-liner
public static bool DrawChoice2(string input) => input.ToLower() == "y";
Going back to the idea of a game loop, you now have a condition that dictates whether the game loop continues or not. One possible implementation would be this:
string choice = Console.ReadLine();
while (DrawChoice(choice)) // No need to write "== true" or "== false"
{
// Stuff that happens if a player or the dealer draws another card
choice = Console.ReadLine() // Ask again once the game logic has executed
}
// Stuff that happens when the loop ends
2.3. Drawing cards
Blackjack is a card game, therefore you'll be drawing cards a lot, be it for a player or for the dealer. If something happens often in the game, it's generally a good idea to make it into a method so you don't have to write the same logic in different places.
Your current implementation draws a random value between the minimum and the maximum of your array of cards. From the documentation, we learn the following:
Next(Int32 minValue, Int32 maxValue)
A 32-bit signed integer greater than or equal to minValue
and less than maxValue
; that is, the range of return values includes minValue
but not maxValue
. If minValue
equals maxValue
, minValue
is returned.
So when you write Next(1, 10)
(from min and max), you will at most get a 9. Another issue is that even if you fix the implementation to Next(1, 11)
, you will have equal probabilities to get any value from 1 through 10. But since there's multiple cards in the deck that have the value of 10, they should show up more often than non-10 cards.
Fortunately, your array already has the correct distribution of cards, so instead you could generate a valid random position to get the corresponding value from your array.
At the end of the day, what you'll end up with will look something like this:
public static int DrawCard()
{
int[] cards = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10 };
int card;
// Implement random draw here
return card;
}
And then you could even do something like this to repeatedly draw cards:
// You could also use a list, which is more flexible
public static int[] DrawCard(int count)
{
int[] drawn = new int[count];
for (int i = 0; i < count; i++)
{
drawn[i] = DrawCard();
}
return drawn;
}
Hope this helps! Good luck and have fun!