【Kotlin】確認問題4-☆1:ナインゲームを作ろう

記事内に商品プロモーションを含む場合があります

この記事の練習問題で使用する知識:
基礎文法(レッスン1)比較演算子と論理演算子if文による分岐処理when文による分岐処理for文による繰り返し処理while文による繰り返し処理関数の定義と呼出し関数の戻り値Mapコレクション操作

Kotlinのゲームコード一覧はこちら

<<前のページ Kotlin記事一覧 次のページ>>

確認問題:ナインゲームを作ろう

ナインゲームを作成しましょう。

ナインゲームはプレイヤーとコンピュータが対戦するシンプルなゲームです。

この問題の要件

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

  • プレイヤーとコンピュータは1から9までの9枚の牌を持っています。
  • プレイヤーとコンピュータはそれぞれのターンで牌を一枚選びます。
  • 牌の数字を比較し、大きい数字を出した方にその数字と同じ数の得点が入ります。
  • 一度出した牌は再び使用することはできません。全ての牌が使われるまでゲームは続きます。
  • 最終的に得点が多い方が勝者となります。
  • プレイヤーの牌はユーザーが入力し、コンピュータの牌はランダムに選ばれます。
  • ゲームの進行に合わせて、各ターンの状況と結果を表示してください。

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

----- ↓出力される結果の例↓ -----

ナインゲームを開始します!
プレイヤーの持ち牌 ⇒「1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9」
コンピュータの持ち牌⇒「1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9」

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

プレイヤーの持ち牌 ⇒「1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,-」
コンピュータの持ち牌⇒「1 ,2 ,3 ,4 ,- ,6 ,7 ,8 ,9」
...

この問題を解くヒント

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

ヒント1【コードの構成を見る】

正解のコードは上から順に以下のような構成となっています。

1:main関数の定義とゲーム開始メッセージの出力
  □ playerTilesinitializeTiles関数で初期化
  □ computerTilesinitializeTiles関数で初期化
  □ playerScoreを0で初期化
  □ computerScoreを0で初期化
  □ forループで1から9まで繰り返し処理
  □ □ ラウンド情報を出力
  □ □ displayScores関数でプレイヤーとコンピュータのスコアを表示
  □ □ displayTiles関数でプレイヤーの持ち牌を表示
  □ □ displayTiles関数でコンピュータの持ち牌を表示
  □ □ getPlayerTile関数でプレイヤーの打牌を取得
  □ □ getComputerTile関数でコンピュータの打牌を取得
  □ □ 勝敗判定のためにjudgeRound関数を呼び出し、結果をroundResultに代入
  □ □ 結果に基づきwhen構文でスコア加算または引き分けを表示
  □ □ ラウンドの詳細結果を出力
  □ displayFinalResult関数で最終スコアとゲーム結果を表示
2:initializeTiles関数の定義
  □ 空のMutableMapを生成
  □ forループで1から9のキーにtrueを設定
  □ 生成したマップを返す
3:displayScores関数の定義
  □ プレイヤーとコンピュータのスコアを出力
4:displayTiles関数の定義
  □ tilesマップの各キーと値をループ処理
  □ 未使用牌は番号を表示し、使用済み牌は「-」を表示
5:getPlayerTile関数の定義
  □ whileループでプレイヤーからの入力を繰り返し取得
  □ if文で選択した牌が未使用か判定
  □ □ 未使用なら牌を使用済みに設定し返す
  □ □ 使用済みならエラーメッセージを出力し再入力を促す
6:getComputerTile関数の定義
  □ 未使用牌をランダムに選択
  □ 選択した牌を使用済みに設定し返す
7:judgeRound関数の定義
  □ when構文で打牌の大小を比較し勝敗を返す
8:displayFinalResult関数の定義
  □ ゲーム終了メッセージを出力
  □ プレイヤーとコンピュータの最終スコアを出力
  □ スコアに基づき最終結果を判定し出力

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

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

import kotlin.random.Random

fun main() {
    println("ナインゲームを開始します!")

    // プレイヤーとコンピュータの持ち牌を初期化
    val playerTiles = initializeTiles()
    val computerTiles = initializeTiles()

    // スコア初期化
    var playerScore = 0
    var computerScore = 0

    // 9回戦を行う
    for (round in 1..9) {
        println("\n【第${round}回戦】")
        displayScores(playerScore, computerScore)

        // プレイヤーとコンピュータの持ち牌を表示
        displayTiles("プレイヤー", playerTiles)
        displayTiles("コンピュータ", computerTiles)

        // プレイヤーとコンピュータの打牌
        val playerTile = getPlayerTile(playerTiles)
        val computerTile = getComputerTile(computerTiles)

        // 勝敗判定
        val roundResult = judgeRound(playerTile, computerTile)
        println("プレイヤーの打牌:$playerTile > $computerTile:コンピュータの打牌")

        when (roundResult) {
            "player" -> {
                println("プレイヤーは${playerTile}点獲得")
                playerScore += playerTile
            }
            "computer" -> {
                println("コンピュータは${computerTile}点獲得")
                computerScore += computerTile
            }
            else -> println("引き分けです")
        }
    }

    // ゲーム終了後の結果表示
    displayFinalResult(playerScore, computerScore)
}

/* 【穴埋め問題1】
ここにinitializeTiles関数を作成し、1から9までのキーをtrueに設定したMutableMapを返すコードを書いてください。
*/

/* 【穴埋め問題2】
ここにdisplayScores関数を作成し、プレイヤーとコンピュータのスコアをそれぞれ出力するコードを書いてください。
*/

/* 【穴埋め問題3】
ここにdisplayTiles関数を作成し、指定された持ち牌の内容を表示するコードを書いてください。
*/

/* 【穴埋め問題4】
ここにgetPlayerTile関数を作成し、プレイヤーから未使用の打牌を選択させるコードを書いてください。
*/

/* 【穴埋め問題5】
ここにgetComputerTile関数を作成し、コンピュータの未使用の打牌をランダムに選択するコードを書いてください。
*/

/* 【穴埋め問題6】
ここにjudgeRound関数を作成し、プレイヤーとコンピュータの打牌を比較して勝敗を判定するコードを書いてください。
*/

/* 【穴埋め問題7】
ここにdisplayFinalResult関数を作成し、最終スコアとゲームの結果を出力するコードを書いてください。
*/

この問題の穴埋めコードは以上です。

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

ナインゲームの正解コードと解説

この問題の一つの正解例とそのコードの解説を以下に示します。

正解コードの例

例えば以下のようなプログラムが考えられます。

import kotlin.random.Random

fun main() {
    println("ナインゲームを開始します!")

    // プレイヤーとコンピュータの持ち牌を初期化
    val playerTiles = initializeTiles()
    val computerTiles = initializeTiles()

    // スコア初期化
    var playerScore = 0
    var computerScore = 0

    // 9回戦を行う
    for (round in 1..9) {
        println("\n【第${round}回戦】")
        displayScores(playerScore, computerScore)

        // プレイヤーとコンピュータの持ち牌を表示
        displayTiles("プレイヤー", playerTiles)
        displayTiles("コンピュータ", computerTiles)

        // プレイヤーとコンピュータの打牌
        val playerTile = getPlayerTile(playerTiles)
        val computerTile = getComputerTile(computerTiles)

        // 勝敗判定
        val roundResult = judgeRound(playerTile, computerTile)
        println("プレイヤーの打牌:$playerTile > $computerTile:コンピュータの打牌")

        when (roundResult) {
            "player" -> {
                println("プレイヤーは${playerTile}点獲得")
                playerScore += playerTile
            }
            "computer" -> {
                println("コンピュータは${computerTile}点獲得")
                computerScore += computerTile
            }
            else -> println("引き分けです")
        }
    }

    // ゲーム終了後の結果表示
    displayFinalResult(playerScore, computerScore)
}

// 関数:持ち牌を初期化
fun initializeTiles(): MutableMap<Int, Boolean> {
    return mutableMapOf<Int, Boolean>().apply {
        for (i in 1..9) {
            this[i] = true
        }
    }
}

// 関数:得点を表示
fun displayScores(playerScore: Int, computerScore: Int) {
    println("プレイヤーの得点 : ${playerScore}点")
    println("コンピュータの得点: ${computerScore}点")
}

// 関数:持ち牌を表示
fun displayTiles(playerType: String, tiles: Map<Int, Boolean>) {
    print("$playerType の持ち牌⇒「")
    tiles.forEach { (key, value) -> if (value) print("$key ,") else print("- ,") }
    println("」")
}

// 関数:プレイヤーの打牌を取得
fun getPlayerTile(tiles: MutableMap<Int, Boolean>): Int {
    var playerTile: Int
    while (true) {
        print("持ち牌の中から出す牌を選択してください > ")
        playerTile = readLine()!!.toInt()
        if (tiles[playerTile] == true) {
            tiles[playerTile] = false // 使用済みに設定
            return playerTile
        } else {
            println("その牌は既に使われています。別の牌を選んでください。")
        }
    }
}

// 関数:コンピュータの打牌を取得
fun getComputerTile(tiles: MutableMap<Int, Boolean>): Int {
    val computerTile = tiles.filter { it.value }.keys.random()
    tiles[computerTile] = false
    return computerTile
}

// 関数:勝敗判定
fun judgeRound(playerTile: Int, computerTile: Int): String {
    return when {
        playerTile > computerTile -> "player"
        computerTile > playerTile -> "computer"
        else -> "draw"
    }
}

// 関数:最終結果を表示
fun displayFinalResult(playerScore: Int, computerScore: Int) {
    println("\nゲーム終了!")
    println("最終得点:")
    println("プレイヤーの得点 : ${playerScore}点")
    println("コンピュータの得点: ${computerScore}点")

    when {
        playerScore > computerScore -> println("プレイヤーの勝利です!")
        computerScore > playerScore -> println("コンピュータの勝利です!")
        else -> println("引き分けです!")
    }
}

正解コードの解説

このコードはプレイヤーとコンピュータが9回の対戦を行うシンプルなゲームです。

各プレイヤーは牌を選び、より大きな数字を選んだプレイヤーが得点を獲得します。

コードをブロックごとに分割し、初心者向けに解説します。

ランダム関数のインポート

import kotlin.random.Random

import kotlin.random.Random: Kotlin標準ライブラリのRandomクラスを使用して、コンピュータがランダムな牌を選ぶ機能を実現しています。

メイン関数の開始

fun main() {
    println("ナインゲームを開始します!")
  • fun main(): Kotlinプログラムのエントリーポイント。プログラムはこの関数から実行されます。
  • println: コンソールにメッセージを表示します。この場合、ゲームの開始を知らせています。

持ち牌の初期化

val playerTiles = mutableMapOf<Int, Boolean>()
val computerTiles = mutableMapOf<Int, Boolean>()
for (i in 1..9) {
    playerTiles[i] = true
    computerTiles[i] = true
}
  • mutableMapOf: 可変のマップを作成します。ここでは各プレイヤーの牌(キー)とその使用状態(値)を管理しています。
  • for (i in 1..9): 1から9までの連続した数字をループで処理し、全ての牌を初期化しています。

スコアの初期化

var playerScore = 0
var computerScore = 0
  • var: 変更可能な変数を宣言します。
  • プレイヤーとコンピュータの得点を0に初期化します。

ゲームのラウンドを処理

for (round in 1..9) {
    println("\n【第${round}回戦】")
    println("プレイヤーの得点 : ${playerScore}点")
    println("コンピュータの得点: ${computerScore}点")
}
  • for (round in 1..9): 9回のラウンドを繰り返します。
  • println: 現在のラウンド数やスコアを表示します。
  • ${}: 文字列テンプレートを使い、変数の値を埋め込んでいます。

持ち牌の表示

playerTiles.forEach { (key, value) -> if (value) print("$key ,") else print("- ,") }
  • forEach: マップ内の全ての要素に対して繰り返し処理を行います。
  • if (value): 牌が使用可能かをチェックします。使用可能ならその番号を表示し、使用済みなら-を表示します。

プレイヤーの打牌を入力

var playerTile: Int
while (true) {
    print("持ち牌の中から出す牌を選択してください > ")
    playerTile = readLine()!!.toInt()
    if (playerTiles[playerTile] == true) {
        playerTiles[playerTile] = false
        break
    } else {
        println("その牌は既に使われています。別の牌を選んでください。")
    }
}
  • readLine(): ユーザー入力を取得します。
  • !!.toInt(): 入力された文字列を整数に変換します。!!はnull値がないことを保証します。
  • while (true): 条件が満たされるまで繰り返し実行します。
  • if (playerTiles[playerTile] == true): 入力された牌が使用可能かを確認します。

コンピュータの打牌を決定

val computerTile = computerTiles.filter { it.value }.keys.random()
computerTiles[computerTile] = false
  • filter: 条件を満たす要素を抽出します。ここでは使用可能な牌だけを選択しています。
  • keys.random(): 使用可能な牌の中からランダムに1つを選択します。

ラウンド結果の判定と得点更新

if (playerTile > computerTile) {
    println("プレイヤーは${playerTile}点獲得")
    playerScore += playerTile
} else if (computerTile > playerTile) {
    println("コンピュータは${computerTile}点獲得")
    computerScore += computerTile
} else {
    println("引き分けです")
}
  • if: 条件に応じた処理を実行します。
  • +=: 変数に得点を加算します。

最終結果の表示

if (playerScore > computerScore) {
    println("プレイヤーの勝利です!")
} else if (computerScore > playerScore) {
    println("コンピュータの勝利です!")
} else {
    println("引き分けです!")
}

if-else: プレイヤーとコンピュータのスコアを比較して勝敗を判定します。

まとめ

このコードでは、Kotlinの基本文法(変数、ループ、条件分岐、マップ操作、標準入力/出力)を活用してゲームを構築する方法を学びました。

特にマップやループの使い方に注目してください。

プログラムの流れを理解することで、自分でカスタマイズしたゲームを作る力がつきます。

Kotlinのゲームコード一覧はこちら

<<前のページ Kotlin記事一覧 次のページ>>

この記事への質問・コメント

この記事を作成するにあたりAIを活用しています。

問題ないことは確認していますが、もし間違いや表現の違和感などありましたら、ご指摘頂けると大変助かります。






    Kotlinテキスト&問題集へ戻る
    トップページへ戻る