1

私は PHP で非常に小さなブラックジャック ゲームに取り組んでいます。

私は現在カードを数える関数を書いていますが、エースは私のお尻を蹴っています。

私のカードはすべて次のような配列になっています。

$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 のエースも持っていましたが、明らかに問題が発生します。エースで 21 を超えないように、繰り返しループし続ける必要があると思いますが、それを実行するための最善の方法が完全にはわかりません。

皆さん、いくつかの意見をいただければ幸いです。 編集

私が考えることができる最善のことは、これを関数に追加することです

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

実際、これはうまくいくかもしれないと思います。テストに数分ください。

編集:

いいえ、うまくいきませんでした。4、エース、エース、6が出てこれで22になりました。

4

1 に答える 1

3

ブラックジャックについてはよくわかりませんが、これは私の試みです。

    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 4 AA で 12、6 4 A で 21 が必要です。したがって、残りのエースの数がカウントされます。それに応じてソースを変更しました。

説明

まず、エース以外のカードの価値を計算します。これらは定数なので、これで終わりです。そして、この合計が(暫定)$card_valuesです。

次に、いくつかのエースを持っている (または持っていない) 可能性があります。while($aces)エースがない場合は何もしないようにするのは理にかなっています。

問題は、これらのエースをどうするかということです。必要条件はここにあります: 合計は 21 に収まる必要があります。つまり、「私は 10 でエースを持っているので、21 に収まる」とは言えません。その後に別のエースがある可能性があるからです。 . したがって、残りのエースをすべて追加した場合の最悪のケースを計算する必要があります。もちろん、これはエースの数に 11 を掛けたものです。最悪の場合でも (つまり、$card_values + 11*$ace21 未満)、11 を追加できます。そうでない場合は、1 を追加する必要があります。

これは「貪欲な」アルゴリズムの一種です: 可能な限りすべての 1 を当てはめますが、21 に最も近いアプローチに到達するのに十分な 11 を残して、それを超えないようにします。

この実装には、 NumberOfItems * LowestValue >= HighestValue になるたびに発生する厄介なバグがあったことを覚えているようです (私は間違っているかもしれません)。しかし、この場合、NumberOfItems が 11/1 = 11 エース以上である必要があり、デッキにそれほど多くのエースがないので、問題ありません。そして確かに、考えられるケースは 5 つです - 「いいえ」から「4 つのエース」まで - 他のカードのすべての合計について簡単にテストできます。

    // 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 :-)
于 2013-02-07T00:15:28.447 に答える