【Kotlin】確認問題3-☆1:ブラックジャックゲームを作ろう

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

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

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

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

確認問題:ブラックジャックゲームを作ろう





ブラックジャックは、プレイヤーとディーラーが対戦するカードゲームです。この問題では、Kotlinを使って簡単なブラックジャックゲームを作成します。

プレイヤーは2枚のカードを引き、その合計値をもとにゲームを進めます。

合計値が21に近い方が勝者となりまが、21を超えると「バースト」となり、負けとなります。

今回は1から11までの数字のみを扱います。

この問題の要件

以下の要件に従ってプログラムを作成してください。

  1. ゲームの流れ:
    • プレイヤーとディーラーの双方が2枚のカードを引きます。
    • カードの合計が21を超えない限り、プレイヤーは「ヒット」(もう一枚引く)か「スタンド」(引かない)を選択できます。
    • プレイヤーがスタンドを選ぶと、ディーラーは17以上になるまでカードを引きます。
    • どちらかの合計が21を超えた場合、バーストして敗北となります。
    • プレイヤーとディーラーの手が決まった後、合計値が21に近い方が勝利します。
  2. カードの値:
    • カードの値はランダムに1から11の整数で決定します。
  3. 勝敗の判定:
    • 合計値が21を超えた場合はバーストして負け。
    • 合計値が21に最も近い方が勝者となります。

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

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

ブラックジャックゲームを開始します!
プレイヤーの引いたカード: 7
現在の合計: 7
ヒットしますか?(yes/no): yes
プレイヤーの引いたカード: 10
現在の合計: 17
ヒットしますか?(yes/no): no
ディーラーの引いたカード: 9
ディーラーの合計: 9
ディーラーの引いたカード: 8
ディーラーの合計: 17
プレイヤーの合計: 17
ディーラーの合計: 17
引き分けです。

この問題を解くヒント

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

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

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

1:kotlin.random.Randomをインポート
2:関数drawCardを定義
  □ Random.nextIntを使用して1から11までのランダムな整数を返す
3:関数playerTurnを定義
  □ 変数totalを初期化(0)
  □ whileループを開始
  □ □ 関数drawCardを呼び出し、戻り値を変数cardに代入
  □ □ 変数totalにcardを加算
  □ □ 「プレイヤーの引いたカード: $card」を出力
  □ □ 「現在の合計: $total」を出力
  □ □ if文でtotalが21を超えているか判定
  □ □ □ 真の場合、「バースト!プレイヤーの負けです。」と出力
  □ □ □ breakでループを終了
  □ □ 「ヒットしますか?(yes/no)」と出力
  □ □ ユーザー入力を変数choiceに代入
  □ □ if文でchoiceが”no”であるか判定
  □ □ □ 真の場合、breakでループを終了
  □ totalを返す
4:関数dealerTurnを定義
  □ 変数totalを初期化(0)
  □ whileループを開始(条件:total < 17)
  □ □ 関数drawCardを呼び出し、戻り値を変数cardに代入
  □ □ 変数totalにcardを加算
  □ □ 「ディーラーの引いたカード: $card」を出力
  □ □ 「ディーラーの合計: $total」を出力
  □ □ if文でtotalが21を超えているか判定
  □ □ □ 真の場合、「ディーラーがバーストしました。プレイヤーの勝ちです。」と出力
  □ □ □ breakでループを終了
  □ totalを返す
5:メイン関数を定義
  □ 「ブラックジャックゲームを開始します!」と出力
  □ 関数playerTurnを呼び出し、戻り値を変数playerTotalに代入
  □ if文でplayerTotalが21以下か判定
  □ □ 真の場合、関数dealerTurnを呼び出し、戻り値を変数dealerTotalに代入
  □ □ 「プレイヤーの合計: $playerTotal」を出力
  □ □ 「ディーラーの合計: $dealerTotal」を出力
  □ □ when式で勝敗を判定
  □ □ □ ディーラーの合計が21を超える、またはプレイヤーの合計が大きい場合、「プレイヤーの勝ちです!」と出力
  □ □ □ プレイヤーの合計がディーラーの合計より小さい場合、「ディーラーの勝ちです。」と出力
  □ □ □ それ以外の場合、「引き分けです。」と出力

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

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

import kotlin.random.Random

// カードをランダムに生成する関数
fun drawCard(): Int {
    /* 【穴埋め問題1】
    ここに1から11のランダムな整数を返すコードを書いてください。
    */
}

// プレイヤーのターンを処理する関数
fun playerTurn(): Int {
    /* 【穴埋め問題2】
    ここにプレイヤーのカード合計を保持するための変数totalを宣言し、0に初期化するコードを書いてください。
    */

    while (true) {
        /* 【穴埋め問題3】
        ここに新しいカードを引いて合計値に加算するコードを書いてください。
        */

        println("プレイヤーの引いたカード: $card")
        println("現在の合計: $total")

        if (total > 21) {
            println("バースト!プレイヤーの負けです。")
            break
        }

        print("ヒットしますか?(yes/no): ")
        val choice = readLine()

        if (choice == "no") {
            break
        }
    }
    return total
}

// ディーラーのターンを処理する関数
fun dealerTurn(): Int {
    /* 【穴埋め問題4】
    ここにディーラーのカード合計を保持するための変数totalを宣言し、0に初期化するコードを書いてください。
    */

    while (total < 17) {
        /* 【穴埋め問題5】
        ここに新しいカードを引いて合計値に加算するコードを書いてください。
        */

        println("ディーラーの引いたカード: $card")
        println("ディーラーの合計: $total")

        if (total > 21) {
            println("ディーラーがバーストしました。プレイヤーの勝ちです。")
            break
        }
    }
    return total
}

// メイン関数: ゲームの流れを制御する
fun main() {
    println("ブラックジャックゲームを開始します!")

    val playerTotal = playerTurn()
    if (playerTotal <= 21) {
        val dealerTotal = dealerTurn()
        println("プレイヤーの合計: $playerTotal")
        println("ディーラーの合計: $dealerTotal")

        when {
            dealerTotal > 21 || playerTotal > dealerTotal -> println("プレイヤーの勝ちです!")
            playerTotal < dealerTotal -> println("ディーラーの勝ちです。")
            else -> println("引き分けです。")
        }
    }
}

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

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

ゲームの正解コードと解説

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

正解コードの例

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

import kotlin.random.Random

// カードをランダムに生成する関数
// 1から11の範囲でランダムな整数を返します
fun drawCard(): Int {
    return Random.nextInt(1, 12) // 1から11のランダムな数を返す
}

// プレイヤーのターンを処理する関数
// プレイヤーがカードを引くかどうかを選択し、合計値を計算します
fun playerTurn(): Int {
    var total = 0 // プレイヤーのカードの合計を保持する変数

    while (true) { // ユーザーが「スタンド」を選ぶまでループ
        val card = drawCard() // 新しいカードを引く
        total += card // 引いたカードの値を合計に加える
        println("プレイヤーの引いたカード: $card") // 引いたカードの値を表示
        println("現在の合計: $total") // 現在の合計値を表示

        // 合計が21を超えた場合はバースト(負け)とする
        if (total > 21) {
            println("バースト!プレイヤーの負けです。")
            break // バーストしたらループを終了
        }

        // プレイヤーに次の行動を尋ねる
        print("ヒットしますか?(yes/no): ")
        val choice = readLine() // ユーザーの入力を受け取る

        // 「no」を選んだ場合、カードを引くのをやめる
        if (choice == "no") {
            break // ループを終了し、プレイヤーのターンを終了
        }
    }
    return total // プレイヤーの最終的な合計値を返す
}

// ディーラーのターンを処理する関数
// ディーラーは合計が17以上になるまでカードを引き続けます
fun dealerTurn(): Int {
    var total = 0 // ディーラーのカードの合計を保持する変数

    // ディーラーの合計が17未満である限りカードを引き続ける
    while (total < 17) {
        val card = drawCard() // 新しいカードを引く
        total += card // 引いたカードの値を合計に加える
        println("ディーラーの引いたカード: $card") // 引いたカードの値を表示
        println("ディーラーの合計: $total") // ディーラーの現在の合計値を表示

        // 合計が21を超えた場合はバースト(負け)とする
        if (total > 21) {
            println("ディーラーがバーストしました。プレイヤーの勝ちです。")
            break // バーストしたらループを終了
        }
    }
    return total // ディーラーの最終的な合計値を返す
}

// メイン関数: ゲームの流れを制御する
fun main() {
    println("ブラックジャックゲームを開始します!") // ゲームの開始メッセージを表示

    val playerTotal = playerTurn() // プレイヤーのターンを実行し、合計値を取得
    if (playerTotal <= 21) { // プレイヤーがバーストしていない場合にディーラーのターンを実行
        val dealerTotal = dealerTurn() // ディーラーのターンを実行し、合計値を取得
        println("プレイヤーの合計: $playerTotal") // プレイヤーの最終合計値を表示
        println("ディーラーの合計: $dealerTotal") // ディーラーの最終合計値を表示

        // 勝敗の判定
        when {
            dealerTotal > 21 || playerTotal > dealerTotal -> println("プレイヤーの勝ちです!") // ディーラーがバーストするか、プレイヤーの合計が勝っている場合
            playerTotal < dealerTotal -> println("ディーラーの勝ちです。") // プレイヤーの合計が負けている場合
            else -> println("引き分けです。") // 両者の合計が同じ場合
        }
    }
}

正解コードの解説

このコードはブラックジャックゲームの簡易バージョンを実装しています。

以下でコードの各ブロックを説明し、初心者の方が理解できるように解説します。

カードをランダムに生成する関数

fun drawCard(): Int {
    return Random.nextInt(1, 12)
}
  • Random.nextInt(1, 12): Kotlinのランダム生成機能を使って1から11の整数を返します。
  • fun drawCard(): drawCardという名前の関数を定義しています。この関数の戻り値は整数型(Int)です。

プレイヤーのターンを処理する関数

fun playerTurn(): Int {
    var total = 0

    while (true) {
        val card = drawCard()
        total += card
        println("プレイヤーの引いたカード: $card")
        println("現在の合計: $total")

        if (total > 21) {
            println("バースト!プレイヤーの負けです。")
            break
        }

        print("ヒットしますか?(yes/no): ")
        val choice = readLine()

        if (choice == "no") {
            break
        }
    }
    return total
}

目的: プレイヤーがカードを引きながら合計値を計算する処理を担当します。

  • var total = 0: プレイヤーのカードの合計値を保持する変数。
  • while (true): 条件がtrueの間繰り返し処理を実行します。breakでループを終了できます。
  • drawCard(): ランダムなカードを引く関数を呼び出しています。
  • println: 引いたカードや合計を出力するために使用します。
  • if (total > 21): 合計値が21を超えたら負け(バースト)と判断します。
  • readLine(): プレイヤーに入力を求める機能。入力がnoならループを終了します。

ディーラーのターンを処理する関数

fun dealerTurn(): Int {
    var total = 0

    while (total < 17) {
        val card = drawCard()
        total += card
        println("ディーラーの引いたカード: $card")
        println("ディーラーの合計: $total")

        if (total > 21) {
            println("ディーラーがバーストしました。プレイヤーの勝ちです。")
            break
        }
    }
    return total
}

目的: ディーラーが17以上の合計になるまでカードを引き続ける処理を担当します。

  • while (total < 17): 合計が17未満の間、ディーラーはカードを引きます。
  • break: 合計が21を超える(バーストする)とループを終了します。

メイン関数

fun main() {
    println("ブラックジャックゲームを開始します!")

    val playerTotal = playerTurn()
    if (playerTotal <= 21) {
        val dealerTotal = dealerTurn()
        println("プレイヤーの合計: $playerTotal")
        println("ディーラーの合計: $dealerTotal")

        when {
            dealerTotal > 21 || playerTotal > dealerTotal -> println("プレイヤーの勝ちです!")
            playerTotal < dealerTotal -> println("ディーラーの勝ちです。")
            else -> println("引き分けです。")
        }
    }
}

目的: ゲーム全体の流れを制御し、プレイヤーとディーラーの勝敗を判定します。

  • val playerTotal = playerTurn(): プレイヤーの合計値を取得。
  • if (playerTotal <= 21): プレイヤーがバーストしていなければディーラーのターンへ進みます。
  • when: 条件に応じた勝敗の判定を行います。

まとめ

このプログラムはブラックジャックの基本的なルールを元にゲームの流れをシンプルに実現しています。

プログラミング初心者はこのコードを元に、ブラックジャック以外のルールを試したり、より複雑な条件を加えてゲームを拡張してみてください!

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

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

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

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

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






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