Question

I am implementing a little Black Jack game in C# and I have the following problem calculating the player's hand value. Aces may have a value of 1 or 11 based on the player's hand. If the player has three cards and one ace, then if the sum of the cards is <= 10 the ace will have value of 11, otherwise it will have a value of 1.

Now lets assume I do not know how many aces the player has got and the game is implemented giving the possibility to the dealer to use more than one deck of cards. The user may have in one hand even 5, 6, 7, 8... aces.

What is the best way (possibly using Linq) to evaluate all the aces the player has got to get the closest combination to 21 (in addition to the other cards)?

I know the players' cards and I want to calculate their values, using the aces to reach the closest value to 21.

Was it helpful?

Solution

Add up the value of all the non-aces and add the number of aces: 2, Q, A, A = 2 + 10 + (2) = 14

Then subtract that from 21: 21 - 14 = 7

Is this number less than 10 (if only 1 ace == 11)? Less than 20 (if both aces == 11)?

Since this feels like homework, this is intentionally not the complete answer but should guide you along.

OTHER TIPS

It doesn't seem so complex,

  • you just add all other cards and find the lower value the hand has
  • now you have two cases:
    • sum <= 10: so you check how two outcomes assuming that one ace can be considered as 11 in this way: sum + 11 + (numAces-1)*1 <= 21, then this is the nearest value to 21, otherwise sum + numAces*1 (because using an ace as 11 would overflow)
    • sum > 10: you can just consider aces as 1 so final value is sum + numAces*1

(never used C# so this answer is metacode)

As described, you should be able to implement this with the Aggregate extenstion method.

Write a function that implements your algorithm and use it:

IEnumerable<int> cards = // card values
var f = (int i1, int i2) => // implement algorithm here
var result = cards.Aggregate(f);

From my perspective, you have to account for the fact that when the player has one or more aces, he or she has two possible scores at any given time. Trying to calculate the single value closest to 21 is a faulty abstraction of what it means to hold an ace in blackjack.

As a player, I don't want the program to tell me that I have 16 when I have ace & 5, because I might not take a hit with 16, but if I have ace & 5 I am absolutely going to take that hit. Conceptually, I really have 6 or 16.

I think the value of the hand should be representable as one or two values. Obviously, in the absence of an ace, there will be only one value. Likewise, when ace-as-eleven means a busted hand, there is only one value for the hand, because that ace must be counted as 1. You could also say that any ace + 10 combination has only one value, because that is instant blackjack.

Here is a partial implementation -- one of many, many ways to skin this cat. I wrote it this way to sort of get you thinking in a certain way; given that only aces can have more than one value and a given hand can have at most two possible values, though, this could be done more succinctly.

public interface Hand
{
   IEnumerable<int> PossibleValues { get; set; }
}
public interface Card
{
   CardValues PossibleValues { get; set; }
}
public interface CardValues
{
    int Value1 { get; }
    int Value2 { get; }
}

public class BlackjackHand : Hand
{
    IList<Card> cards;

   public IEnumerable<int> PossibleValues
   {
        IList<int> possible_values = new List<int>();

        int initial_hand_value = cards.Sum(c => c.Value1);
        if(initial_hand_value <= 21)
        {
            possible_values.Add(initial_hand_value);
            yield return initial_hand_value;
        }

        foreach(Card card in cards.Where(c => c.Value2 > 0))
        {
            IList<int> new_possible_values = new List<int>();
            foreach(int value in possible_values)
            {
                var alternate_value = value + card.Value2;
                if(alternate_value <= 21) 
                {
                    new_possible_values.Add(alternate_value);
                    yield return alternate_value;
                }
            }
            possible_values.AddRange(new_possible_values);
        }

        yield break;
   }
}

It may be simplest to think of it this way - with each card dealt add the card value to the total counting ace as 11. If the card is an ace, and the player busted, subtract 10. Example:

int total = 0;
...
int hit = GetHit();
total = total + hit;

if (total > 21 && hit == 11)
{
  total = total - 10
}
// check if player busted, etc

In your initial deal, you could either 'deal' the cards using GetHit(), or handle the Ace-Ace (only problem case with 2 cards) hand on your own. This will always give you the highest hand possible. I'd think it'd be alright to assume that the player knows an ace can be 1 or 11, so hitting with Ace-5 will never cause the player to bust.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top