MENU

【PHP】Lesson4-☆1:ナインゲームで配列とループを総復習しよう

tggaa478@yahoo.co.jp

レッスン4で学習した内容を応用して、簡単なゲームを作成しましょう。

Lesson1:基礎文法編
Lesson2:制御構造編
Lesson3:関数編
Lesson4:データ構造編

 ・Lesson4-1:配列の基本を理解しよう
 ・Lesson4-2:キーが文字列の配列を理解しよう
 ・Lesson4-3:配列の要素を追加/削除しよう
 ・Lesson4-4:配列を調査しよう
 ・Lesson4-5:配列を操作しよう
 ・Lesson4-6:配列を並び替えよう
 ・Lesson4-7:配列の多次元化を理解しよう
 ・確認問題4-1:ナインゲームを作ろう ◁今回はココ
 ・確認問題4-2:宝探しゲームを作ろう
 ・確認問題4-3:マルバツゲームを作ろう
Lesson5:クラス

PHPで作るゲームコード一覧はこちら

<<前のページ

学習記事一覧

次のページ>>

演習問題|PHPでナインゲームを作って配列とロジックを実践しよう

ナインゲームという対戦型ゲームを作成しましょう。

このゲームでは、プレイヤーとコンピュータが各自1から9までの牌を持ち、順番に牌を出して得点を競います。

プレイヤーは牌を選択し、コンピュータはランダムに牌を選択します。

各ラウンドで選んだ牌の数値が大きい方がその数値分の得点を獲得し、最終的に得点の高い方が勝利です。

この演習の要件

以下の要件に従ってコードを完成させてください。

  1. 初期設定
    • プレイヤーとコンピュータの牌はそれぞれ1から9までの整数とする。
    • 得点は初期値0点で開始する。
  2. ゲームの進行
    • 9回のラウンドを行う。
    • 各ラウンドでプレイヤーは手持ちの牌から1つを選択すること。
    • コンピュータはランダムに牌を選択すること。
  3. 得点計算
    • プレイヤーとコンピュータが選んだ牌を比較し、数値の大きい方がその牌の数値分の得点を得る。
    • 同じ値の場合は引き分けとし、得点は発生しない。
  4. 使用済み牌の処理
    • 選択した牌は「使用済み」とし、無効化する(-1で表示)。
  5. 最終結果表示
    • 全ラウンド終了後、プレイヤーとコンピュータの得点を表示し、勝敗を決定すること。

ただし、以下のような実行結果となること。

ナインゲームを開始します!

【第1回戦】
プレイヤーの得点 : 0点
コンピュータの得点: 0点
☆プレイヤーの持ち牌⇒【1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9】
コンピュータの持ち牌⇒【1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9】
持ち牌の中から出す牌を選択してください > 9
プレイヤーの打牌:9 > 4:コンピュータの打牌
プレイヤーは9点獲得

【第2回戦】
プレイヤーの得点 : 9点
コンピュータの得点: 0点
☆プレイヤーの持ち牌⇒【1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,-】
コンピュータの持ち牌⇒【1 ,2 ,3 ,- ,5 ,6 ,7 ,8 ,9】
持ち牌の中から出す牌を選択してください > 5
プレイヤーの打牌:5 < 7:コンピュータの打牌
コンピュータは7点獲得

...(省略)...

ゲーム終了!
プレイヤーの得点 : 45点
コンピュータの得点: 40点
プレイヤーの勝利です!

解き方のヒント

1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。

Q
ヒント【穴埋め問題にする】

以下のコードをコピーし、コメントに従ってコードを完成させて下さい。

<?php
function displayTiles($title, $tiles) {
    echo $title . "⇒【" . implode(" ,", array_map(fn($t) => $t === -1 ? '-' : $t, $tiles)) . "】" . PHP_EOL;
}

function displayScores($playerScore, $computerScore) {
    echo "プレイヤーの得点 : {$playerScore}点" . PHP_EOL;
    echo "コンピュータの得点: {$computerScore}点" . PHP_EOL;
}

function getPlayerChoice($tiles) {
    while (true) {
        echo "持ち牌の中から出す牌を選択してください > ";
        $choice = trim(fgets(STDIN));
        if (in_array($choice, $tiles)) {
            return (int)$choice;
        }
        echo "無効な選択です。再度選択してください。" . PHP_EOL;
    }
}

function getComputerChoice($tiles) {
    return $tiles[array_rand($tiles)];
}

echo "ナインゲームを開始します!" . PHP_EOL;

// 初期設定
/*【穴埋め問題1】
ここでプレイヤーとコンピュータの持ち牌、および得点の初期設定を行うコードを書いてください。
*/

// ラウンド処理
for ($round = 1; $round <= 9; $round++) {
    echo PHP_EOL . "【第{$round}回戦】" . PHP_EOL;

    // 得点と牌の表示
    displayScores($playerScore, $computerScore);
    displayTiles('☆プレイヤーの持ち牌', $playerTiles);
    displayTiles('コンピュータの持ち牌', $computerTiles);

    // 牌の選択
    /*【穴埋め問題2】
    プレイヤーとコンピュータの牌を選択する処理をここに記述してください。
    */

    // 結果表示
    echo "プレイヤーの打牌:{$playerChoice}";
    if ($playerChoice > $computerChoice) {
        echo " > {$computerChoice}:コンピュータの打牌" . PHP_EOL;
        $playerScore += $playerChoice;
        echo "プレイヤーは{$playerChoice}点獲得" . PHP_EOL;
    } elseif ($playerChoice < $computerChoice) {
        echo " < {$computerChoice}:コンピュータの打牌" . PHP_EOL;
        $computerScore += $computerChoice;
        echo "コンピュータは{$computerChoice}点獲得" . PHP_EOL;
    } else {
        echo " = {$computerChoice}:コンピュータの打牌" . PHP_EOL;
        echo "引き分けです。得点はなし" . PHP_EOL;
    }

    // 使用した牌を無効化
    /*【穴埋め問題3】
    使用済みの牌を無効化するコードをここに記述してください。
    */
}

// 最終結果
echo PHP_EOL . "ゲーム終了!" . PHP_EOL;
displayScores($playerScore, $computerScore);

if ($playerScore > $computerScore) {
    echo "プレイヤーの勝利です!" . PHP_EOL;
} elseif ($playerScore < $computerScore) {
    echo "コンピュータの勝利です!" . PHP_EOL;
} else {
    echo "引き分けです!" . PHP_EOL;
}

このヒントを見てもまだ回答を導き出すのが難しいと感じる場合は、先に正解のコードと解説を見て内容を理解するようにしましょう。

演習問題の答え合わせ

この問題の正解コードとその解説は以下の通りです。

クリックして開いて確認してください。

Q
正解コード
<?php
function displayTiles($title, $tiles) {
    echo $title . "⇒【" . implode(" ,", array_map(fn($t) => $t === -1 ? '-' : $t, $tiles)) . "】" . PHP_EOL;
}

function displayScores($playerScore, $computerScore) {
    echo "プレイヤーの得点 : {$playerScore}点" . PHP_EOL;
    echo "コンピュータの得点: {$computerScore}点" . PHP_EOL;
}

function getPlayerChoice($tiles) {
    while (true) {
        echo "持ち牌の中から出す牌を選択してください > ";
        $choice = trim(fgets(STDIN));
        if (in_array($choice, $tiles)) {
            return (int)$choice;
        }
        echo "無効な選択です。再度選択してください。" . PHP_EOL;
    }
}

function getComputerChoice($tiles) {
    return $tiles[array_rand($tiles)];
}

echo "ナインゲームを開始します!" . PHP_EOL;

// 初期設定
$playerTiles = range(1, 9);
$computerTiles = range(1, 9);
$playerScore = 0;
$computerScore = 0;

for ($round = 1; $round <= 9; $round++) {
    echo PHP_EOL . "【第{$round}回戦】" . PHP_EOL;

    // 得点と牌の表示
    displayScores($playerScore, $computerScore);
    displayTiles('☆プレイヤーの持ち牌', $playerTiles);
    displayTiles('コンピュータの持ち牌', $computerTiles);

    // 牌の選択
    $playerChoice = getPlayerChoice(array_diff($playerTiles, [-1]));
    $computerChoice = getComputerChoice(array_diff($computerTiles, [-1]));

    // 結果表示
    echo "プレイヤーの打牌:{$playerChoice}";
    if ($playerChoice > $computerChoice) {
        echo " > {$computerChoice}:コンピュータの打牌" . PHP_EOL;
        $playerScore += $playerChoice;
        echo "プレイヤーは{$playerChoice}点獲得" . PHP_EOL;
    } elseif ($playerChoice < $computerChoice) {
        echo " < {$computerChoice}:コンピュータの打牌" . PHP_EOL;
        $computerScore += $computerChoice;
        echo "コンピュータは{$computerChoice}点獲得" . PHP_EOL;
    } else {
        echo " = {$computerChoice}:コンピュータの打牌" . PHP_EOL;
        echo "引き分けです。得点はなし" . PHP_EOL;
    }

    // 使用した牌を無効化
    $playerTiles[array_search($playerChoice, $playerTiles)] = -1;
    $computerTiles[array_search($computerChoice, $computerTiles)] = -1;
}

// 最終結果
echo PHP_EOL . "ゲーム終了!" . PHP_EOL;
displayScores($playerScore, $computerScore);

if ($playerScore > $computerScore) {
    echo "プレイヤーの勝利です!" . PHP_EOL;
} elseif ($playerScore < $computerScore) {
    echo "コンピュータの勝利です!" . PHP_EOL;
} else {
    echo "引き分けです!" . PHP_EOL;
}
Q
正解コードの解説

コードをブロックごとに分割して解説します。

初期設定と関数の定義

function displayTiles($title, $tiles) {
    echo $title . "⇒【" . implode(" ,", array_map(fn($t) => $t === -1 ? '-' : $t, $tiles)) . "】" . PHP_EOL;
}

この関数は、プレイヤーやコンピュータの持ち牌を表示する役割を持ちます。

  • implode()関数: 配列の要素を文字列に変換して連結します。
  • array_map()関数: 配列内の各要素に処理を施します。
  • 三項演算子 (? :): 条件式で「-1」の場合は「-」を表示し、それ以外はその数値を表示します。
function displayScores($playerScore, $computerScore) {
    echo "プレイヤーの得点 : {$playerScore}点" . PHP_EOL;
    echo "コンピュータの得点: {$computerScore}点" . PHP_EOL;
}

この関数はプレイヤーとコンピュータの得点を表示します。

  • 文字列内で変数を埋め込む: {$変数名} と記述することで変数の値を文字列内に挿入できます。
  • PHP_EOL: プラットフォームに依存しない改行コードを出力します。

プレイヤーとコンピュータの選択処理

function getPlayerChoice($tiles) {
    while (true) {
        echo "持ち牌の中から出す牌を選択してください > ";
        $choice = trim(fgets(STDIN));
        if (in_array($choice, $tiles)) {
            return (int)$choice;
        }
        echo "無効な選択です。再度選択してください。" . PHP_EOL;
    }
}

この関数は、プレイヤーが牌を選択する処理を担当します。

  • fgets(STDIN): 標準入力から1行分のデータを取得します。
  • trim(): 入力された文字列の前後の空白や改行を取り除きます。
  • in_array(): 配列内に指定した値が存在するかをチェックします。
  • 無限ループ (while(true)): 条件が常に真のため、正しい入力が行われるまで繰り返します。
function getComputerChoice($tiles) {
    return $tiles[array_rand($tiles)];
}

コンピュータはランダムに牌を選択します。

  • array_rand(): 配列からランダムにキーを取得します。

メイン処理の開始

$playerTiles = range(1, 9);
$computerTiles = range(1, 9);
$playerScore = 0;
$computerScore = 0;
  • range(1, 9): 1から9までの整数を含む配列を生成します。
  • 初期得点は0点に設定します。

ラウンドごとの処理

for ($round = 1; $round <= 9; $round++) {
    echo PHP_EOL . "【第{$round}回戦】" . PHP_EOL;
  • forループ: 1から9までループを繰り返し、9回戦行うように設定します。
  • 各ラウンドの開始時にラウンド数を表示します。

牌の選択と得点処理

$playerChoice = getPlayerChoice(array_diff($playerTiles, [-1]));
$computerChoice = getComputerChoice(array_diff($computerTiles, [-1]));

array_diff(): 配列の要素から「-1」を除外します。これにより未使用の牌だけが選択可能になります。

if ($playerChoice > $computerChoice) {
    echo " > {$computerChoice}:コンピュータの打牌" . PHP_EOL;
    $playerScore += $playerChoice;
    echo "プレイヤーは{$playerChoice}点獲得" . PHP_EOL;
} elseif ($playerChoice < $computerChoice) {
    echo " < {$computerChoice}:コンピュータの打牌" . PHP_EOL;
    $computerScore += $computerChoice;
    echo "コンピュータは{$computerChoice}点獲得" . PHP_EOL;
} else {
    echo " = {$computerChoice}:コンピュータの打牌" . PHP_EOL;
    echo "引き分けです。得点はなし" . PHP_EOL;
}
  • 条件分岐 (if-elseif-else) によって、得点を計算します。
  • +=: 得点を加算します。

使用済み牌の処理

$playerTiles[array_search($playerChoice, $playerTiles)] = -1;
$computerTiles[array_search($computerChoice, $computerTiles)] = -1;
  • array_search(): 指定した値のインデックスを検索します。
  • 使用済みの牌は「-1」に置き換えて無効化します。

最終結果の表示

if ($playerScore > $computerScore) {
    echo "プレイヤーの勝利です!" . PHP_EOL;
} elseif ($playerScore < $computerScore) {
    echo "コンピュータの勝利です!" . PHP_EOL;
} else {
    echo "引き分けです!" . PHP_EOL;
}

最終的な得点を比較し、勝敗または引き分けを判定します。

まとめ

このコードでは、PHPの配列操作、条件分岐、ユーザー入力処理、ループ処理などを組み合わせてゲームを実現しました。

このコードはゲーム要素を通じてPHPの基本文法を学べる良い練習問題です。

ぜひこのコードをアレンジして、さらに理解を深めてください!

もっと分かりやすい学習サイトにするために

この記事を読んで「ここが分かりにくかった」「ここが難しかった」等の意見を募集しています。

世界一わかりやすいPHP学習サイトにするため、ぜひ 問い合わせフォーム からご意見下さい。

<<前のページ

学習記事一覧

次のページ>>

記事URLをコピーしました