LoginSignup
nana777__
@nana777__

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

【PHP】ポーカーの役判定(ジョーカーあり)について

解決したいこと

【PHP】ポーカーの約判定について

PHPの勉強を始め、ポーカーの役判定の課題に直面しているのですが
ジョーカーありで役判定をすると全て判定結果がスリーカードになってしまいます。

当方、かなり知識も薄いためどこが原因かわからず手詰まり状態です。

ヒントだけでもいいので助けていただけますと嬉しいです。
よろしくお願いいたします。

発生している問題・エラー

判定結果が全てスリーカードになってしまう

または、問題・エラーが起きている画像をここにドラッグアンドドロップ

該当するソースコード

<?php

// 手札
//ワンペア
$cards = [
    ['suit'=>'heart', 'number'=>12],
    ['suit'=>'joker', 'number'=>0],
    ['suit'=>'spade', 'number'=>1],
    ['suit'=>'diamond', 'number'=>2],
    ['suit'=>'club', 'number'=>13],
];
// //ツーペア
// $cards = [
//     ['suit'=>'heart', 'number'=>12],
//     ['suit'=>'spade', 'number'=>10],
//     ['suit'=>'joker', 'number'=>0],
//     ['suit'=>'spade', 'number'=>1],
//     ['suit'=>'club', 'number'=>1],
// ];
// //スリーカード
// $cards = [
//     ['suit'=>'heart', 'number'=>7],
//     ['suit'=>'spade', 'number'=>1],
//     ['suit'=>'diamond', 'number'=>13],
//     ['suit'=>'spade', 'number'=>7],
//     ['suit'=>'joker', 'number'=>0],
// ];
// //ストレート
// $cards = [
//     ['suit'=>'heart', 'number'=>3],
//     ['suit'=>'spade', 'number'=>6],
//     ['suit'=>'joker', 'number'=>0],
//     ['suit'=>'spade', 'number'=>4],
//     ['suit'=>'club', 'number'=>7],
// ];
// //フラッシュ
// $cards = [
//     ['suit'=>'heart', 'number'=>2],
//     ['suit'=>'heart', 'number'=>1],
//     ['suit'=>'joker', 'number'=>13],
//     ['suit'=>'heart', 'number'=>9],
//     ['suit'=>'heart', 'number'=>4],
// ];
// //フルハウス
// $cards = [
//     ['suit'=>'joker', 'number'=>0],
//     ['suit'=>'spade', 'number'=>4],
//     ['suit'=>'diamond', 'number'=>4],
//     ['suit'=>'spade', 'number'=>7],
//     ['suit'=>'club', 'number'=>7],
// ];
// //フォーカード
// $cards = [
//     ['suit'=>'heart', 'number'=>8],
//     ['suit'=>'spade', 'number'=>1],
//     ['suit'=>'joker', 'number'=>0],
//     ['suit'=>'spade', 'number'=>8],
//     ['suit'=>'club', 'number'=>8],
// ];
//ストレートフラッシュ
// $cards = [
//     ['suit'=>'heart', 'number'=>7],
//     ['suit'=>'heart', 'number'=>11],
//     ['suit'=>'heart', 'number'=>8],
//     ['suit'=>'heart', 'number'=>10],
//     ['suit'=>'joker', 'number'=>0],
// ];
// ロイヤルストレートフラッシュ
// $cards = [
//     ['suit'=>'heart', 'number'=>12],
//     ['suit'=>'heart', 'number'=>1],
//     ['suit'=>'heart', 'number'=>13],
//     ['suit'=>'joker', 'number'=>0],
//     ['suit'=>'heart', 'number'=>10],
// ];
// 不正手札
// $cards = [
//     ['suit'=>'heart', 'number'=>12],
//     ['suit'=>'heart', 'number'=>12],
//     ['suit'=>'heart', 'number'=>13],
//     ['suit'=>'heart', 'number'=>11],
//     ['suit'=>'joker', 'number'=>0],
// ];

function is_valid_hand($cards) {
    // カードの不正チェック
    $existing_cards = array(); // すでに存在するカードの組み合わせを格納する配列

    foreach ($cards as $card) {
        // 数字が0から13の範囲外の場合は不正
        if ($card['number'] < 0 || $card['number'] > 13) {
            return false;
        }
        
        // 絵柄が有効なものではない場合は不正
        if ($card['suit'] !== 'heart' && $card['suit'] !== 'spade' && $card['suit'] !== 'diamond' && $card['suit'] !== 'club' && $card['suit'] !== 'joker') {
            return false;
        }

        // 同じ絵柄と数字の組み合わせがすでに存在する場合は不正
        $card_key = $card['suit'] . $card['number'];
        if (in_array($card_key, $existing_cards)) {
            return false;
        } else {
            // 組み合わせを配列に追加
            $existing_cards[] = $card_key;
        }
    }
    
    return true; // 全ての条件を満たす場合は正常

}

function compare_cards($cards){
    global $suits_order;
    foreach($cards as $key => $value)
    {
        $sort_keys[$key] = $value['number'];
    }
    
    array_multisort($sort_keys, SORT_ASC, $cards);
    return $cards;

}

function is_royal_straight_flush($cards) {
    // ロイヤルストレートフラッシュの数字の配列
    $royal_flush_numbers = [1, 10, 11, 12, 13];

    $suits = array_column($cards, 'suit');
    $numbers = array_column($cards, 'number');

    // ジョーカーを含むロイヤルストレートフラッシュの条件
    $has_joker = in_array('joker', $suits) && count(array_intersect($royal_flush_numbers, $numbers)) === 4;

    return ($numbers === $royal_flush_numbers) && (count(array_unique($suits)) === 1) || $has_joker;
}
function is_straight_flush($cards) {
    $suits = array_column($cards, 'suit');
    $numbers = array_column($cards, 'number');

    // ジョーカーを除外した数字の配列
    $numbers_without_joker = array_filter($numbers, function($number) {
        return $number !== 0;
    });

    // ジョーカーが含まれている場合、最小の数字としてジョーカーの数字を扱う
    if (in_array(0, $numbers)) {
        $numbers_without_joker[] = max($numbers_without_joker) + 1; // 最小の数字よりも1大きい数字を追加する
    }

    // 数字を昇順にソート
    sort($numbers_without_joker);

    // 数字が連続しているかどうかを確認
    $is_straight = true;
    for ($i = 0; $i < count($numbers_without_joker) - 1; $i++) {
        if ($numbers_without_joker[$i + 1] - $numbers_without_joker[$i] !== 1) {
            $is_straight = false;
            break;
        }
    }

    // 同じスートかつ、連続した数字の場合はストレートフラッシュ
    return $is_straight && (count(array_unique($suits)) === 1);
}
function is_four_of_a_kind($cards) {
    $numbers = array_column($cards, 'number');
    $count_values = array_count_values($numbers);

    // Check if there are four cards of the same number
    if (in_array(4, $count_values, true)) {
        return true;
    }

    // Check if there are three cards of the same number and a joker
    if (in_array(3, $count_values, true) && in_array(0, $numbers, true)) {
        return true;
    }

    // Check if there are two cards of the same number and two jokers
    if (in_array(2, $count_values, true) && in_array(0, $numbers, true) && count($numbers) === 3) {
        return true;
    }

    return false;
}

function is_full_house($cards) {
    $numbers = array_column($cards, 'number');
    $count_values = array_count_values($numbers);

    // Check if there are three cards of the same number and two cards of another number
    if (in_array(3, $count_values, true) && in_array(2, $count_values, true)) {
        return true;
    }

    // Check if there are two cards of the same number and a joker, and three cards of another number
    if (in_array(2, $count_values, true) && in_array(0, $numbers, true) && count($numbers) === 3) {
        return true;
    }

    // Check if there is a joker, and four cards of the same number
    if (in_array(0, $numbers, true) && in_array(4, $count_values, true)) {
        return true;
    }

    return false;
}

function is_flush($cards) {
    $suits = array_column($cards, 'suit');
    
    // If there's only one unique suit, it's a flush
    if (count(array_unique($suits)) === 1) {
        return true;
    }

    // If there's a joker, consider it as any suit
    if (in_array('joker', $suits, true)) {
        // Remove the joker from the suits array
        $suits = array_diff($suits, ['joker']);
        // If after removing the joker, there's only one unique suit left, it's a flush
        if (count(array_unique($suits)) === 1) {
            return true;
        }
    }

    return false;
}
function is_straight($cards) {
    $numbers = array_column($cards, 'number');
    sort($numbers);

    // If there are no duplicates and the difference between the highest and lowest card is 4, it's a straight
    if (count(array_unique($numbers)) === 5 && ($numbers[4] - $numbers[0]) === 4) {
        return true;
    }

    // If there's a joker, consider it as any number and check if it completes a straight
    if (in_array(0, $numbers, true)) {
        // Remove the joker from the numbers array
        $numbers = array_diff($numbers, [0]);
        sort($numbers);

        // Check if the remaining cards form a straight
        if (($numbers[3] - $numbers[0]) <= 3 && count(array_unique($numbers)) <= 4) {
            return true;
        }
    }

    return false;
}

function is_three_of_a_kind($cards) {
    $numbers = array_column($cards, 'number');
    $count_values = array_count_values($numbers);

    // ジョーカーの数を数える
    $joker_count = isset($count_values[0]) ? $count_values[0] : 0;

    // ジョーカーを除外して、3枚揃っている数字が3回以上出現しているかどうかを確認
    return isset($count_values[3 - $joker_count]) || $joker_count >= 3;
}


    function is_two_pair($cards) {
        $numbers = array_column($cards, 'number');
        $joker_count = 0;
        
        // ジョーカーの数を数える
        foreach ($cards as $card) {
            if ($card['number'] === 0) {
                $joker_count++;
            }
        }
        
        // ジョーカーを除外してカードの数字をカウント
        $count_values = array_count_values(array_filter($numbers, function ($num) { return $num !== 0; }));
        
        // ペアの数をカウント
        $pairs = 0;
        foreach ($count_values as $value) {
            if ($value === 2) {
                $pairs++;
            }
        }
        
        // ジョーカーを利用してツーペアが成立するかどうかを判定
        return ($pairs + $joker_count) === 2;
    }
    
    function is_one_pair($cards) {
        $numbers = array_column($cards, 'number');
        $joker_count = 0;
        foreach ($cards as $card) {
            if ($card['number'] === 0) { // ジョーカーの場合
                $joker_count++;
            }
        }
        $count_values = array_count_values(array_filter($numbers, function ($num) { return $num !== 0; })); // ジョーカーを除外してカウント
        return in_array(2 - $joker_count, $count_values, true); // ペアがあるかどうかを確認
    }
    
    
function judge($cards) {
    //エラーチェック
    $status = is_valid_hand($cards);
    // カードの並び替え
    $sort_data = compare_cards($cards);


        // 手札が正常かどうかをチェック
        if (!is_valid_hand($cards)) {
            return "手札は不正です。";
        }
    
        // カードを数字でソート
        $sorted_cards = compare_cards($cards);
    
        // 役の判定を行う
        if (is_royal_straight_flush($sorted_cards)) {
            return "役はロイヤルストレートフラッシュです。";
        } elseif (is_straight_flush($sorted_cards)) {
            return "役はストレートフラッシュです。";
        } elseif (is_four_of_a_kind($sorted_cards)) {
            return "役はフォーカードです。";
        } elseif (is_full_house($sorted_cards)) {
            return "役はフルハウスです。";
        } elseif (is_flush($sorted_cards)) {
            return "役はフラッシュです。";
        } elseif (is_straight($sorted_cards)) {
            return "役はストレートです。";
        } elseif (is_three_of_a_kind($sorted_cards)) {
            return "役はスリーカードです。";
        } elseif (is_two_pair($sorted_cards)) {
            return "役はツーペアです。";
        } elseif (is_one_pair($sorted_cards)) {
            return "役はワンペアです。";
        } else {
            return "役はなしです。";
        }
    }
    

// 関数「judge」を呼び出して結果を表示する
echo "手札は" . "\n";
foreach ($cards as $card) {
    echo $card['suit'] . $card['number'] . ' ';
}
echo "\n" . judge($cards) .  "\n";
?>

0

2Answer

判定結果が全てスリーカードになってしまう

これが正しいとすると、2つの問題があります。

  1. スリーカード判定を行うまでの他の判定に誤りがある(より上位の役になるべきものが正しく判定されていない)
  2. スリーカード判定に誤りがある(スリーカード以下の役がスリーカードになる)

流石に全ての検証をこちらでやって原因調査するのは厳しいので、具体的なケースを明示された方が良いと思います。

まずは個々の判定処理について網羅的に確認しましょう。
考えられる手札の組み合わせと、それに対してそれぞれの判定処理がどのような結果を返すかを整理してリスト化します。
そのリストに沿って確認すれば、どこにどのような問題があるのかが明確になると思います。

0

array_count_values()は、key: keyの数 の配列を返すんですよね?

となるとis_three_of_a_kind()のreturn文は、

isset($count_values[3 - $joker_count])
  • ジョーカーが0枚の時は、手持ちに 3のカード があったらtrue
  • ジョーカーが1枚の時は、手持ちに 2のカード があったらtrue
  • ジョーカーが2枚の時は、手持ちに 1のカード があったらtrue
  • ジョーカーが3枚の時は、手持ちに 0のカード があったらtrue

という判定文になっちゃってますね。

ですので、意図せぬスリーカード判定になっちゃってるのではないかと思います。

0

Your answer might help someone💌