如何计算这些卡的值

时间:2013-02-06 23:21:01

标签: php

我正在使用PHP进行一个非常小的二十一点游戏。

我目前正在编写计算卡片的功能,但是ace会踢我的屁股。

我的卡片都是这样的数组:

$card_array = array( "ca", "c10", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9",
    "cj", "ck", "cq", "da", "d10", "d2", "d3", "d4", "d5", "d6", "d7", "d8",
    "d9", "dj", "dk", "dq", "ha", "h2", "h3", "h4", "h5", "h6", "h7", "h8", "h9",
    "hj", "hk", "hq", "sa", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9",
    "s10", "sj", "sk", "sq");`

第一个角色是套装,之后的所有内容都是卡片(j代表杰克等)

这是我到目前为止计算值的原因:

function bj_calculate_values( $cards ) {
    $card_values = 0;
    foreach ($cards as $card) {
        if (substr($card, 1) == "k" || substr($card, 1) == "q" || substr($card, 1) == "j") {
            $card_values += 10;
        }
        else if (substr($card, 1) != "a") {
            $card_values += substr($card, 1);
        }
    }
}

最初,我也有一张价值11的ace,但显然这会引起问题。我觉得我需要继续重新开口,以确保A不会让我们超过21岁,但我并不完全确定这样做的最好方法。

我很感激一些意见,伙计们。 的修改

我能想到的最好的就是将其添加到函数

foreach ($cards as $card) {
    if (substr($card, 1) == "a") {
        if ($card_values + 11 <= 21) {
            $card_values += 11;
        }
        else {
            $card_values += 1;
        }
    }
}

实际上我觉得这可行。给我几分钟的时间来测试一下。

修改

不,不行。 4,ace,ace,6用这个来到了22。

1 个答案:

答案 0 :(得分:3)

我对BlackJack了解不多,但这是我的尝试。

    function bj_calculate_values( $cards ) {
        $card_values = 0;
        $ace = 0;
        foreach ($cards as $card) {
            $val = substr($card, 1);
            if (!is_numeric($val))
            {
                    if ('a' == $val)
                    {
                            $val = 0;
                            $ace ++;
                    }
                    else
                            $val = 10;
            }
            $card_values    += $val;
        }
        while ($ace)
            $card_values += ($card_values + 11*$ace-- <= 21) ? 11: 1;


        return $card_values;
    }

更新

如果我理解你的其他评论,你想要6 4 AAA出来13,6 6 4 AA出来12,6和4 4 A出来21.所以剩余 aces的数量计数。相应地修改了源。

说明

首先,我们计算非一张牌的价值。这些是不变的,所以我们把它解决了。这个总数是(初步)$card_values

然后我们可能有(或没有)一些ace。有一个while($aces)是有道理的,这样如果我们没有王牌,我们什么都不做。

现在的问题是,我们如何处理这些A?这是你的必备条件:总和必须符合21。这意味着我不能只说“我是10岁,我有一个王牌,所以它适合21”因为可能有另一个之后 ace。因此,如果我要添加所有剩余的A,我必须计算最差的情况。这当然是次数,次数11.虽然最坏的情况仍然很好(即$card_values + 11*$ace小于21)我可以加11.虽然不是,但我必须加1。

这是一种“贪婪”的算法:我尽可能地适应所有的1,同时确保留下足够的11,以达到最接近21的不超过。

我似乎记得(我可能错了,嘿)这个实现中有一个讨厌的错误,只要NumberOfItems * LowestValue&gt; = HighestValue就会出现(虽然我不太确定“等于”) 。但是在这种情况下,它需要NumberOfItems超过11/1 = 11个ace,并且牌组中没有那么多A,所以我们很酷。可以肯定的是,可能的情况是五个 - 从手中的“不”到“四个” - 并且很容易测试所有其他卡的数量:

    // J Q K are worth 10, so we can use 10 instead.
    // And a fake card with value of 0 stands for "nothing".
    // We use the suit of Klingon, with up to four identical aces :-D

    for ($first = 0; $first <= 21; $first++)
    {
        $hand = array("k$first");
        for ($aces = 1; $aces < 5; $aces++)
        {
            $hand[] = "ka";
            $value  = bj_calculate_values($hand);

            // Let us ponder the possible values of $value.

            if ($value <= 11)
            {
                    // This is an error: we could have gotten closer to 21
                    // by upvaluing an ace. A correct implementation will
                    // never enter here except in the case of a LONE ACE.
                    if (($first != 0) || ($aces != 1))
                        print "ERROR: " . implode(" ", $hand) . " = $value\n";
            }
            // We have a value from 12 to 21.
            // Could we have done better? What cards do we have?
            // If no aces, of course no. All card values are then fixed.

            // If at least one ace, interpreted as 11, again not:
            // cannot interpret it above 11, and interpret as 1 would LESSEN the score.

            // If at least one ace, interpreted as 1, were we to interpret it
            // as 11, we would be summing 10. And 12 would become 22, and blow.

            // So, from 12 to 21, the result MUST be correct.

            // Finally, $value more than 21.
            if ($value > 21)
            {
                   // This is admissible ONLY if we could have done no better, which
                   // means $value is given by the fixed cards' value, $first, plus 
                   // ALL ACES COUNTED AS ONES.
                   if ($value != ($first + $aces))
                        print "ERROR: " . implode(" ", $hand) . " = $value\n";
             }
        }
    }

输出(版本1)

VERIFY: k0 ka = 11              Correct, we had a lone ace and gave it 11.
VERIFY: k18 ka ka ka ka = 22    Correct, we had 18 in other cards and all A's to 1's.
VERIFY: k19 ka ka ka = 22       Ditto, 19 in cards.
VERIFY: k19 ka ka ka ka = 23    Ditto, 19 in cards.
...                             ...

当前输出(仅添加代码以打印错误):

-- nothing :-)