在二十一点游戏中计算手牌价值

6
我正在使用C#实现一个Black Jack小游戏,但是计算玩家手牌价值时遇到以下问题:A可以根据玩家的手牌价值为1或11。如果玩家有三张牌和一张A,则如果牌的总和小于等于10,则A的值为11,否则为1。

现在我们假设我不知道玩家有多少个A,并且该游戏实现了为荷官提供使用多副牌的可能性。用户可能在一只手中拥有5、6、7、8...个ACE。

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

我知道玩家的牌,并且想要计算他们的价值,使用ACE来达到尽可能接近21的值。


9
这是作业吗? - Yuriy Faktorovich
你能换个方式问问题吗?或者你想要达到什么目的?你是想知道用户需要多少张A才能得到21点吗?比如说,如果他手上有5、2、4,那么用户需要10张A吗? - RvdK
这不是很清楚 - 你知道玩家手中有哪些牌,然后尝试计算他的手牌价值吗?还是你正在猜测玩家手中有什么牌? - RickL
5个回答

5
将所有非A牌的点数加起来,再加上A牌的数量:2、Q、A、A = 2 + 10 + (2) = 14。
然后用21减去这个点数:21 - 14 = 7。
这个数字是否小于10(如果只有1张A牌等于11)?小于20(如果两张A牌都等于11)?
由于这感觉像是作业,所以这并不是完整的答案,但应该能帮助你。

4

这似乎并不复杂,

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

(从未使用过C#,因此此答案是元代码)


0

如上所述,您应该能够使用Aggregate扩展方法来实现此功能。

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

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

0

从我的角度来看,你必须考虑到当玩家有一张或多张A时,他或她在任何时候都有两个可能的分数。试图计算最接近21的单个值是对于在二十一点中持有A的含义的错误抽象。

作为一名玩家,我不希望程序告诉我当我有A和5时我有16分,因为我可能不会在16分时要牌,但如果我有A和5,我绝对会要牌。从概念上讲,我实际上有6 或者 16分。

我认为手牌的价值应该表示为一个或两个值。显然,在没有A的情况下,只会有一个值。同样,当A作为11意味着爆牌时,手牌只有一个值,因为那张A必须计为1。你也可以说,任何A + 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;
   }
}

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,因此用A-5打牌永远不会导致玩家爆牌。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接