PHP:ポーカーの役判定アルゴリズム

PHP ポーカー でググっても既に学習済みの人じゃないと分からないような難しいコードしか出てこなかったので、このメモが同じ段階で躓いている初心者の人の為になれば幸いです。

準備

まずはロイヤルストレートフラッシュの手持ちからスタート。

ここのマークと数字を書き換えても、ちゃんと役が判定出来るアルゴリズムを作る。

$cards = [

["suite" => "club" , "number" => 4]  // 1枚目

["suite" => "club" , "number" => 3] // 2枚目

["suite" => "club" , "number" => 2] // 3枚目

["suite" => "club" , "number" => 5] // 4枚目

["suite" => "club" , "number" => 1] // 5枚目

]

 

このままでは扱いずらいので、数字とマークを分けておき数字はソートしておく(ストレート等を判定する為)

$hand_num = array_column($cards,"number");

$hand_suit = array_column($cards,"number");

sort($hand_num);

出力結果→

Array (

[0] => 1

[1] => 2

[2] => 3

[3] => 4

[4] => 5 ) です。

 

下準備が出来たので、ここから役を判定するアルゴリズムを考えていきます。

フラッシュ

条件:手札5枚のマークが全て同じマーク

1枚目と2枚目が同じマークかつ・・・4枚目と5枚目が同じマークなら。

  if ($hand_suit[0] == $hand_suit[1] &&
        $hand_suit[1] == $hand_suit[2] &&
        $hand_suit[2] == $hand_suit[3] &&
        $hand_suit[3] == $hand_suit[4] ) {
        $bool_flush = true;
    }

ストレート

条件:1~13の数字内で連番5回続く

もっとスマートに判定する方法があるだろうけど、真っ先に思いついたのが

1~5 2~6 3~7・・・というように全試行していく方法。

if ($str15 ||$str26 ||$str37 ||$str48 ||$str59 ||$str610||$str711||$str812||$str913||$str113) {
        $bool_straight = true;
    }

ストレートフラッシュとロイヤルストレートフラッシュ

条件:ストレートとフラッシュ両方を満たした場合かつ、1.10.11.12.13の連番だった場合

この2つに関してはストレートとフラッシュを組み合わせるだけ。

 

// ストレートフラッシュ

  if ($bool_flush && $bool_straight) {
        $bool_str_flush = true;
    }

// ロイヤルストレートフラッシュ
    if ($bool_str_flush == true && $str113) {  // $str113 = 1.10.11.12.13の連番 
        $bool_royal = true;  
    }

 

フォーカードとスリーカード

条件:同じ数字が3枚、4枚ある場合

例えば手持ちの数字が [5.5.5.5.9]の場合、

  • 1枚目と2枚目のカードが同じ
  • 2枚目と3枚目のカードが同じ
  • 3枚目と4枚目のカードが同じ

この条件を満たせばフォーカードになる。

しかし、[1.5.5.5.5]の場合だとフォーカードなのに判定することが出来なくなるのでボツ。

カードの前後を比較することで判定するのを辞めて、

手札の中の数字とその数字が何枚あるか?を集計して判定する。

 for ($i=1; $i <= 13; $i++) {   
        $count_num[$i] = 0; // 配列の初期化 

    }
    for ($i=0; $i <= 4; $i++) { 
        $count_num[$hand_num[$i]]++; 
    }

出力結果→

1が1枚、5が4枚とカウント出来ているので、下記のコードで判定が可能になる。

(補足:ストレートも最適化可能)

 

for ($i=1; $i <= 13; $i++) { 
        $count_num[$hand_num[$i]]++;

if ($count_num[$i] == 4) {
            $bool_four = true;

if ($count_num[$i] == 3) {
            $bool_three = true;
        }

}

フルハウスとツーペアとワンペア

フルハウス = スリーカード+ワンペア

ツーペア = ワンペアが2つ

なのでワンペアのカウントが出来れば、さっき用意したスリーカードの判定を組み合わせてフルハウスが判定可能になり、ツーペアとワンペアも判定可能になる。

if ($count_num[$i] == 2) {
            $bool_one_pair++;  // ワンペアがあれば+1カウント
        }

if ($bool_three == true && $bool_one_pair == 1) {
            return "フルハウスです";
        }

if ($bool_one_pair == 2) {
            return "ツーペアです";
        }

if ($bool_one_pair == 1) {
        }

 

チェック

ちゃんと判定出来ていました

全ての役判定結果