takogaki
@takogaki

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

PHPでポーカーの役判定を作っています

解決したいこと

PHPでポーカーの役判定を作っているのですが、カード5枚の表示はできたのですが、カードの不正チェックと並べ替えと役判定がどうしてもわかりません。
宜しければ助けていただきたいです。

該当するソースコード

<?php
// 以下はポーカーの役を判定するプログラムです。
// cards配列に格納したカードの役を判定し、結果表示してください。
// cards配列には計5枚、それぞれ絵柄(suit)、数字(numeber)を格納する
// 絵柄はheart, spade, diamond, clubのみ
// 数字は1-13のみ

// 上記以外の絵柄や数字が存在した場合、または同一の絵柄、数字がcards配列に存在した場合、
// 役の判定前に「手札が不正です」と表示してください。
// 役判定は関数に記述し、関数を呼び出して結果表示すること
// プログラムが完成したらcards配列を差し替えてすべての役で検証を行い、提出時にテストケースを示すこと

// <役>
// ワンペア・・・同じ数字2枚(ペア)が1組
// ツーペア・・・同じ数字2枚(ペア)が2組
// スリーカード・・・同じ数字3枚
// ストレート・・・数字の連番5枚(13と1は繋がらない)
// フラッシュ・・・同じマークが5枚
// フルハウス・・・同じ数字3枚が1組+同じ数字2枚(ペア)が1組
// フォーカード・・・同じ数字4枚
// ストレートフラッシュ・・・数字の連番5枚+同じマークが5枚
// ロイヤルストレートフラッシュ・・・1, 10, 11, 12, 13で同じマーク
// ※下の方が強い

// 表示例1)
// 手札は
// heart2 heart5 heart3 heart4 culb1
// 役はストレートです

// 表示例2)
// 手札は
// heart1 spade2 diamond11 club13 heart9
// 役はなしです

// 表示例3)
// 手札は
// heart1 heart1 heart3 heart4 heart5
// 手札は不正です

自分で試したこと

<?php

// 手札
$suits = ['heart', 'spade', 'diamond', 'club'];
$numbers = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'];

// suitsのkeyをランダムに表示する
$randsuit1 = array_rand($suits);
$randsuit2 = array_rand($suits);
$randsuit3 = array_rand($suits);
$randsuit4 = array_rand($suits);
$randsuit5 = array_rand($suits);

// keyから値を取得し、それを変数に代入する
$the_suit1 = $suits[$randsuit1];
$the_suit2 = $suits[$randsuit2];
$the_suit3 = $suits[$randsuit3];
$the_suit4 = $suits[$randsuit4];
$the_suit5 = $suits[$randsuit5];

// $the_suits = [$the_suit1, $the_suit2, $the_suit3, $the_suit4, $the_suit5];

// numbersのkeyをランダムに表示する
$randnum1 = array_rand($numbers);
$randnum2 = array_rand($numbers);
$randnum3 = array_rand($numbers);
$randnum4 = array_rand($numbers);
$randnum5 = array_rand($numbers);

// keyから値を取得し、それを変数に代入する
$the_num1 = $numbers[$randnum1];
$the_num2 = $numbers[$randnum2];
$the_num3 = $numbers[$randnum3];
$the_num4 = $numbers[$randnum4];
$the_num5 = $numbers[$randnum5];

// $the_nums = [$the_num1, $the_num2, $the_num3, $the_num4, $the_num5];

// 取得したsuitとnumberを交互に表示する
$final_cards = [
['suit' => $the_suit1, 'num' => $the_num1],
['suit' => $the_suit2, 'num' => $the_num2],
['suit' => $the_suit3, 'num' => $the_num3],
['suit' => $the_suit4, 'num' => $the_num4],
['suit' => $the_suit5, 'num' => $the_num5],
];

//(ここから関数処理)
function judge($final_cards) {
// この関数内に処理を記述

// カードの不正チェック

// カードの並び替え

// 役判定

// 結果を返す

}
?>
<!DOCTYPE html>



ポーカー役判定



手札は


<?php foreach($final_cards as $final): ?>
<?php
$final_suit = $final['suit'];
$final_num = $final['num'];
?>
<?php echo $final_suit . ' ' . $final_num . ' ';?>
<?php endforeach ?>

役は<?=judge($final_cards) ?>です。




if文で役判定をしようとすると膨大な記述量、そしてエラーが出てしまう為他のやり方を探した結果、関数に辿り着いたのですがまだまだ勉強不足で上手くいきません。
ご教授願いたいです。
そもそもカードの表示方法から間違えている可能性もあるのでこちらに投稿させていただきます。
是非、よろしくお願い致します。

0

1Answer

なぜか知恵袋で同様の質問

が見つかりましたが与えられた課題か何かでしょうか.
知恵袋の回答者の言葉を引用すると

宿題を丸投げしたんじゃ全然勉強にならないです。

です.また,takogakiさんが感じている

if文で役判定をしようとすると膨大な記述量

という事実から考えるに,この膨大な記述量を難なくこなせるようになってほしいという願いが込められている課題だと思います.
記述量をなるべく少なくしてみたものを次に示しますので,読解して勉強してください.

警告までに,この記述では$final_cardsが宣言された時点において既にカードの不正チェックと並び替えが済んでいる上,cards配列が同じデータ構造をしていないことを伝えておきます(課題で与えられたデータ構造に変換できなければ眺めるだけ無駄です).

あくまで今回は役判定に焦点を絞って考えていただきたく,このような書き方になりました.頑張ってください.

役判定の例
<?php
function card_name($num) {
    return ['heart', 'spade', 'diamond', 'club'][$num % 4]
    . ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'][floor($num / 4)];
}
$final_cards = array_rand(range(0, 4 * 13 - 1), 5);
//$final_cards = [0, 36, 40, 44, 48]; // RoyalFlush
//$final_cards = [0, 4, 8, 12, 16];   // StraightFlush
//$final_cards = [0, 1, 2, 3, 4];     // Four Card
//$final_cards = [0, 1, 2, 4, 5];     // Full House
//$final_cards = [0, 4, 8, 44, 48];   // Flush
//$final_cards = [0, 4, 9, 12, 16];   // Straight
//$final_cards = [0, 1, 2, 4, 10];    // Three Card
//$final_cards = [0, 1, 4, 5, 30];    // Two Pair
//$final_cards = [0, 1, 4, 8, 12];    // One Pair

foreach ($final_cards as $n) {
    echo card_name($n) . ", ";
}

function judge($final_cards) {
    if (isRoyalFlush($final_cards))
        return "Royal Straight Flush";
    if (isStraightFlush($final_cards))
        return "Straight Flush";
    if (isFourCard($final_cards))
        return "Four Card";
    if (isFullHouse($final_cards))
        return "Full House";
    if (isFlush($final_cards))
        return "Flush";
    if (isStraight($final_cards))
        return "Straight";
    if (isThreeCard($final_cards))
        return "Three Card";
    if (isTwoPair($final_cards))
        return "Two Pair";
    if (isOnePair($final_cards))
        return "A Pair";
    
    return "No Role";
}

function isFlush($cards) {
    for ($i = 0; $i < 4; ++$i) {
        if ($cards[$i] % 4 != $cards[$i + 1] % 4) return false;
    }
    return true;
}

function isStraight($cards) {
    for ($i = 0; $i < 4; ++$i) {
        if (floor($cards[$i] / 4) != floor($cards[$i + 1] / 4) - 1) return false;
    }
    return true;
}

function isRoyalFlush($cards) {
    $correct = [0, 9, 10, 11, 12];
    for ($i = 0; $i < 5; ++$i) {
        if ($correct[$i] != floor($cards[$i] / 4)) return false;
    }
    return isFlush($cards);
}

function isStraightFlush($cards) {
    return isFlush($cards) && isStraight($cards);
}

function count_number($cards) {
    $ret = array_fill(0, 13, 0);
    foreach ($cards as $c) {
        $ret[floor($c / 4)]++;
    }
    return $ret;
}

function isFourCard($cards) {
    foreach (count_number($cards) as $cn) {
        if ($cn >= 4) return true;
    }
    return false;
}

function isFullHouse($cards) {
    $three = false;
    $two = false;
    foreach (count_number($cards) as $cn) {
        if ($cn >= 3) $three = true;
        elseif ($cn >= 2) $two = true;
    }
    return $three && $two;
}

function isThreeCard($cards) {
    foreach (count_number($cards) as $cn) {
        if ($cn >= 3) return true;
    }
    return false;
}

function isTwoPair($cards) {
    $two_cnt = 0;
    foreach (count_number($cards) as $cn) {
        if ($cn == 2) $two_cnt += 1;
    }
    return $two_cnt == 2;
}

function isOnePair($cards) {
    foreach  (count_number($cards) as $cn) {
        if ($cn == 2) return true;
    }
    return false;
}

echo judge($final_cards);
?>
1Like

Comments

  1. @takogaki

    Questioner


    @PondVillegeさん本当にどうもありがとうございます!
    そうなんです。
    Yahoo知恵袋の方と私は別人ですが、恐らく同じ悩みを抱えている方だと思います。

    教えていただいたプログラムを参考にさせていただき、ひとつひとつの意味をしっかりわかるように身につけていきたいとおもいます!

    本当にありがとうございました!
  2. ぜひ頑張ってください!
    解決しましたら,本質問をクローズにしていただけると幸いです.
  3. @takogaki

    Questioner

    // 手札
    function card_name($num){
    return['heart', 'spade', 'diamond', 'club'][$num % 4]
    . ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'][floor($num / 4)];
    }

    $final_cards = array_rand(range(0, 4 * 13 - 1), 5);
    //$final_cards = [0, 36, 40, 44, 48]; //RoyalFlush
    //$final_cards = [0, 4, 8, 12, 16]; //StraightFlush
    //$final_cards = [0, 1, 2, 3, 4]; //Four Card
    //$final_cards = [0, 1, 2, 4, 5]; //Full House
    //$final_cards = [0, 4, 8, 44, 48]; //Flush
    //$final_cards = [0, 4, 9, 12, 16]; //Storaight
    //$final_cards = [0, 1, 2, 4, 10]; //Three Card
    //$final_cards = [0, 1, 4, 5, 30]; //Two Pair
    //$final_cards = [0, 1, 4, 8, 12]; //One Pair


    //(ここから関数処理)
    function judge($final_cards) {
    // この関数内に処理を記述
    if (isRoyalFlush($final_cards))
    return "ロイヤルストレートフラッシュ";
    if (isStraightFlush($final_cards))
    return "ストレートフラッシュ";
    if (isFourCard($final_cards))
    return "フォーカード";
    if (isFullHouse($final_cards))
    return "フルハウス";
    if (isFlush($final_cards))
    return "フラッシュ";
    if (isStraight($final_cards))
    return "ストレート";
    if (isThreeCard($final_cards))
    return "スリーカード";
    if (isTwoPair($final_cards))
    return "ツーペア";
    if (isOnePair($final_cards))
    return "ワンペア";

    return "なし";
    }

    // カードの不正チェック

    // カードの並び替え

    // 役判定
    function isFlush ($cards){
    for ($i = 0; $i < 4; ++$i){
    if ($cards[$i] % 4 != $cards[$i + 1] % 4) return false;
    }
    return true;
    }

    function isStraight ($cards){
    for ($i = 0; $i < 4; ++$i){
    if (floor($cards[$i] / 4) != floor($cards[$i + 1] / 4) - 1) return false;
    }
    return true;
    }

    function isRoyalFlush ($cards){
    $correct = [0, 9, 10, 11, 12];
    for ($i = 0; $i < 5; ++$i){
    if ($correct[$i] != floor($cards[$i] / 4)) return false;
    }
    return isFlush($cards);
    }

    function isStraightFlush ($cards){
    return isFlush ($cards) && isStraight ($cards);
    }

    function count_number ($cards){
    $ret = array_fill(0, 13, 0);
    foreach ($cards as $c){
    $ret[floor($c / 4)] ++;
    }
    return $ret;
    }

    function isFourCard ($cards){
    foreach (count_number($cards) as $cn){
    if ($cn >= 4) return true;
    }
    return false;
    }

    function isFullHouse ($cards){
    $three = false;
    $two = false;
    foreach (count_number ($cards) as $cn){
    if ($cn >= 3) $three = true;
    else if ($cn >= 2) $two = true;
    }
    return $three && $two;
    }

    function isThreeCard ($cards){
    foreach (count_number($cards) as $cn){
    if ($cn >= 3) return true;
    }
    return false;
    }

    function isTwoPair ($cards){
    $two_cnt = 0;
    foreach (count_number($cards) as $cn){
    if ($cn == 2) $two_cnt += 1;
    }
    return $two_cnt == 2;
    }

    function isOnePair ($cards){
    foreach (count_number($cards) as $cn){
    if ($cn == 2) return true;
    }
    return false;
    }
    // 結果を返す
    ?>
    <!DOCTYPE html>
    <html lang="ja">
    <head>
    <meta charset="utf-8">
    <title>ポーカー役判定</title>
    </head>
    <body>
    <section>
    <p>手札は</p>
    <?php foreach ($final_cards as $n): ?>
    <?php echo card_name($n) . "\n" . ',' . "\n" ?>
    <?php ?>
    <?php endforeach ?>
    <p> 役は<?php echo judge($final_cards) ?>です。</p>
    </section>
    </body>
    </html>

    ありがとうございます!

    なんとかこのような形で作ることができました!(ほぼ写経)

    あとは”なぜこうなるのか”を一つ一つ解き明かしながらやっていこうと思います!

    本当にありがとうございました!

Your answer might help someone💌