5

我正在用 C# 实现一个小黑杰克游戏,我在计算玩家的手牌值时遇到了以下问题。根据玩家的手牌,A 的值可能为 1 或 11。如果玩家有三张牌和一张 A,那么如果牌的总和 <= 10,则 A 的值为 11,否则为 1。

现在假设我不知道玩家有多少 A,并且游戏已经实施,让庄家可以使用多于一副牌。用户的一只手甚至可能有 5、6、7、8... A。

评估玩家获得最接近 21 组合(除了其他牌)的所有 A 的最佳方法是什么(可能使用 Linq)?

我知道玩家的牌,我想计算他们的值,使用 A 来达到最接近 21 的值。

4

5 回答 5

5

将所有非 ace 的值相加并添加 ace 的数量:2、Q、A、A = 2 + 10 + (2) = 14

然后从 21 中减去:21 - 14 = 7

这个数字是否小于 10(如果只有 1 个 ace == 11)?小于 20(如果两个 A == 11)?

由于这感觉像是家庭作业,因此故意不是完整的答案,但应该指导您。

于 2010-03-08T15:50:17.117 回答
4

好像没那么复杂

  • 您只需添加所有其他牌并找到手牌的较低值
  • 现在你有两种情况:
    • sum <= 10:所以你检查两个结果如何假设一个 ace 可以被认为是 11:sum + 11 + (numAces-1)*1 <= 21,那么这是最接近 21 的值,否则sum + numAces*1(因为使用 ace 作为 11 会溢出)
    • sum > 10:您可以将 ace 视为 1,因此最终值为sum + numAces*1

(从未使用过C#,所以这个答案是元代码)

于 2010-03-08T15:48:55.460 回答
0

如前所述,您应该能够使用聚合扩展方法来实现这一点。

编写一个实现算法并使用它的函数:

IEnumerable<int> cards = // card values
var f = (int i1, int i2) => // implement algorithm here
var result = cards.Aggregate(f);
于 2010-03-08T15:49:54.090 回答
0

从我的角度来看,你必须考虑这样一个事实,即当玩家有一个或多个 A 时,他或她在任何给定时间都有两个可能的得分。试图计算最接近 21 的单个值是对持有 21 点 A 的错误抽象。

作为一名球员,我不希望程序告诉我,当我有 ace 和 5 时,我有 16,因为我可能不会用 16 击球,但如果我有 ace 和 5,我绝对会击球. 从概念上讲,我真的有 6 个16 个。

我认为手的价值应该可以表示为一两个值。显然,在没有 ace 的情况下,将只有一个值。同样,当 ace-as-11 意味着一手破牌时,这手牌只有一个值,因为该 ace必须计为 1。您也可以说任何 ace + 10 组合只有一个值,因为那是即时的二十一点。

这是一个部分实现——为这只猫剥皮的许多方法之一。我这样写是为了让你以某种方式思考;鉴于只有 A 可以有多个值,并且给定的手牌最多可以有两个可能的值,但是,这可以更简洁地完成。

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;
   }
}
于 2010-03-08T17:15:39.207 回答
0

以这种方式考虑可能是最简单的 - 每发一张牌,将牌面值加到 A 的总计数中为 11。如果牌是 A,而玩家爆牌,则减去 10。示例:

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

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

在您的初始发牌中,您可以使用 GetHit() 来“发牌”牌,也可以自己处理 Ace-Ace(只有 2 张牌的问题)手牌。这将始终为您提供尽可能高的牌。我认为可以假设玩家知道 A 可以是 1 或 11,所以用 Ace-5 击球永远不会导致玩家破产。

于 2010-03-08T17:27:57.627 回答