【问题标题】:Calculating hand values in Blackjack在二十一点中计算手牌值
【发布时间】:2011-01-25 00:57:51
【问题描述】:

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

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

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

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

【问题讨论】:

  • 这是作业吗?
  • 你能重新表述这个问题/你想达到什么目的?您想知道用户需要多少 ace 才能获得 21?假设他有 5、2、4,那么用户需要 10 个 A?
  • 不太清楚——你知道玩家手里有什么牌吗,你在计算他的手牌价值吗?还是你想猜测玩家手中的东西?

标签: c# blackjack


【解决方案1】:

将所有非ace的值加起来,再加上ace的数量:2、Q、A、A = 2 + 10 + (2) = 14

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

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

因为这感觉像是家庭作业,所以这不是完整的答案,但应该指导你。

【讨论】:

    【解决方案2】:

    好像没那么复杂,

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

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

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

        【解决方案4】:

        在我看来,您必须考虑这样一个事实,即当玩家有一个或多个 A 时,他或她在任何给定时间都有 两个可能的分数。 尝试计算最接近的单个值到 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;
           }
        }
        

        【讨论】:

          【解决方案5】:

          这样想可能是最简单的 - 每发一张牌,就将牌面值加到 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 击球永远不会导致玩家破产。

          【讨论】:

            猜你喜欢
            • 2011-02-02
            • 1970-01-01
            • 2017-04-05
            • 2011-11-09
            • 2012-01-03
            • 2016-12-29
            • 2017-06-05
            • 2014-07-19
            • 2021-10-04
            相关资源
            最近更新 更多