【Kotlin】確認問題3-☆3:モンスターとのバトルゲームを作ろう

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

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

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

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

確認問題:モンスターとのバトルゲームを作ろう

勇者とモンスターが戦うバトルゲームを作成してください。このゲームでは、以下のルールに従います:

  • プレイヤー(勇者)は攻撃または防御の選択が可能です。
  • モンスターはランダムな成功率で攻撃を試みます。
  • 勇者の攻撃が成功すると、モンスターのHPが減少します。
  • 勇者が防御を選択し、モンスターの攻撃が失敗した場合、モンスターの攻撃成功率が増加します。
  • HPが0以下になった方が敗北となり、ゲームは終了します。

この問題の要件

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

  1. 変数定義:
    • 勇者のHP (playerHp) を100で初期化すること。
    • 勇者の攻撃力 (playerAttackPower) を20で設定すること。
    • モンスターのHP (monsterHp) を100で初期化すること。
    • モンスターの攻撃力 (monsterAttackPower) を40で設定すること。
    • モンスターの攻撃成功率 (monsterAttackSuccessRate) を60で初期化すること。
  2. ゲーム進行:
    • ゲーム開始時にタイトルを表示すること。
    • 勇者とモンスターのHPおよびモンスターの攻撃成功率を毎ターン表示すること。
    • プレイヤーが攻撃を選択した場合、モンスターのHPが減少すること。
    • プレイヤーが防御を選択した場合、モンスターの攻撃が失敗すれば、攻撃成功率を20%増加させること。
    • 勇者またはモンスターのHPが0以下になった場合、勝敗メッセージを表示してゲームを終了すること。
  3. ランダム性:
    • モンスターの攻撃が成功するかはランダムな確率に基づき判定すること。
  4. ユーザー入力:
    • 勇者の行動は1(攻撃)または2(防御)を入力して選択できるようにすること。

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

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

=== モンスターとのバトルゲーム ===
勇者のHP: 100, ドラゴンのHP: 100, ドラゴンの攻撃成功率: 60%
攻撃するか防御するかを選んでください (1: 攻撃, 2: 防御):
1
勇者はドラゴンに20のダメージを与えた!
ドラゴンのHP: 80, 勇者のHP: 100, ドラゴンの攻撃成功率: 60%
ドラゴンの攻撃!
ドラゴンは勇者に40のダメージを与えた!
勇者のHP: 60, ドラゴンのHP: 80, ドラゴンの攻撃成功率: 60%
攻撃するか防御するかを選んでください (1: 攻撃, 2: 防御):
2
勇者は防御を選択した!
ドラゴンの攻撃!
ドラゴンの攻撃がミス!攻撃成功率が80%に上昇!
勇者のHP: 60, ドラゴンのHP: 80, ドラゴンの攻撃成功率: 80%
攻撃するか防御するかを選んでください (1: 攻撃, 2: 防御):
1
勇者はドラゴンに20のダメージを与えた!
ドラゴンのHP: 60, 勇者のHP: 60, ドラゴンの攻撃成功率: 80%
ドラゴンの攻撃!
ドラゴンは勇者に40のダメージを与えた!
勇者のHP: 20, ドラゴンのHP: 60, ドラゴンの攻撃成功率: 60%
攻撃するか防御するかを選んでください (1: 攻撃, 2: 防御):
1
勇者はドラゴンに20のダメージを与えた!
ドラゴンのHP: 40, 勇者のHP: 20, ドラゴンの攻撃成功率: 60%
ドラゴンの攻撃!
ドラゴンは勇者に40のダメージを与えた!
勇者は倒された…ドラゴンの勝利!

この問題を解くヒント

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

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

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

1:main関数の定義
  □ 変数playerHpに100を代入
  □ 変数playerAttackPowerに20を代入
  □ 変数monsterHpに100を代入
  □ 変数monsterAttackPowerに40を代入
  □ 変数monsterAttackSuccessRateに60を代入
  □ 「=== モンスターとのバトルゲーム ===」と出力
  □ while文でplayerHpとmonsterHpが0より大きい間ループを実行
  □ □ displayStatus関数を呼び出し、現在のステータスを表示
  □ □ getPlayerAction関数を呼び出し、プレイヤーの行動を取得
  □ □ if文でプレイヤーの行動が1(攻撃)であるかを判定
  □ □ □ attack関数を呼び出し、monsterHpを更新
  □ □ else if文でプレイヤーの行動が2(防御)であるかを判定
  □ □ □ 「勇者は防御を選択した!」と出力
  □ □ □ performMonsterAttack関数を呼び出し、攻撃の結果を取得
  □ □ □ if文でモンスターの攻撃がミスであるかを判定
  □ □ □ □ monsterAttackSuccessRateを20増加
  □ □ □ □ 「ドラゴンの攻撃がミス!攻撃成功率が{monsterAttackSuccessRate}%に上昇!」と出力
  □ □ □ □ continueでループをスキップ
  □ □ if文でmonsterHpが0以下であるかを判定
  □ □ □ 「ドラゴンは倒された!勇者の勝利!」と出力
  □ □ □ breakでループを終了
  □ □ 「ドラゴンの攻撃!」と出力
  □ □ performMonsterAttack関数を呼び出し、攻撃の結果を取得
  □ □ if文でモンスターの攻撃がヒットであるかを判定
  □ □ □ attack関数を呼び出し、playerHpを更新
  □ □ □ monsterAttackSuccessRateを60にリセット
  □ □ else文でモンスターの攻撃がミスである場合の処理
  □ □ □ monsterAttackSuccessRateを20増加
  □ □ □ 「ドラゴンの攻撃がミス!攻撃成功率が{monsterAttackSuccessRate}%に上昇!」と出力
  □ □ if文でplayerHpが0以下であるかを判定
  □ □ □ 「勇者は倒された…ドラゴンの勝利!」と出力
2:displayStatus関数の定義
  □ 「勇者のHP: {playerHp}, ドラゴンのHP: {monsterHp}, ドラゴンの攻撃成功率: {monsterAttackSuccessRate}%」と出力
3:getPlayerAction関数の定義
  □ 「攻撃するか防御するかを選んでください (1: 攻撃, 2: 防御):」と出力
  □ ユーザー入力を取得し、数値に変換して返す(入力が不正な場合再帰的に呼び出し)
4:attack関数の定義
  □ 攻撃対象のHPから攻撃力を減算して新しいHPを計算
  □ 「{attacker}は{target}に{attackPower}のダメージを与えた!」と出力
  □ 新しいHPを返す
5:performMonsterAttack関数の定義
  □ ランダムな数値を生成し、成功率以下なら”hit”を返し、それ以外は”miss”を返す

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

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

import kotlin.random.Random

fun main() {
    /* 【穴埋め問題1】
    ここに変数playerHp, playerAttackPower, monsterHp, monsterAttackPower, monsterAttackSuccessRateを初期化するコードを書いてください。
    */

    println("=== モンスターとのバトルゲーム ===")

    while (/* 【穴埋め問題2】ここにループ条件を書いてください */) {
        displayStatus(/* 【穴埋め問題3】ここに関数の引数を渡すコードを書いてください */)
        val playerAction = getPlayerAction()
        if (playerAction == 1) {
            /* 【穴埋め問題4】
            ここに攻撃を行い、monsterHpを更新するコードを書いてください。
            */
        } else if (playerAction == 2) {
            println("勇者は防御を選択した!")
            val monsterAction = performMonsterAttack(monsterAttackSuccessRate)
            if (monsterAction == "miss") {
                /* 【穴埋め問題5】
                ここに攻撃ミス時の処理を書くコードを書いてください。
                */
            }
        }

        if (/* 【穴埋め問題6】ここにモンスターのHPが0以下か判定するコードを書いてください */) {
            println("ドラゴンは倒された!勇者の勝利!")
            break
        }

        println("ドラゴンの攻撃!")
        val attackResult = performMonsterAttack(monsterAttackSuccessRate)
        if (attackResult == "hit") {
            /* 【穴埋め問題7】
            ここに攻撃がヒットした時の処理を書くコードを書いてください。
            */
        } else {
            /* 【穴埋め問題8】
            ここに攻撃ミス時の処理を書くコードを書いてください。
            */
        }

        if (/* 【穴埋め問題9】ここにプレイヤーのHPが0以下か判定するコードを書いてください */) {
            println("勇者は倒された…ドラゴンの勝利!")
        }
    }
}

fun displayStatus(playerHp: Int, monsterHp: Int, monsterAttackSuccessRate: Int) {
    println("勇者のHP: $playerHp, ドラゴンのHP: $monsterHp, ドラゴンの攻撃成功率: $monsterAttackSuccessRate%")
}

fun getPlayerAction(): Int {
    println("攻撃するか防御するかを選んでください (1: 攻撃, 2: 防御):")
    return readLine()?.toIntOrNull() ?: getPlayerAction() // 再帰的に再入力を促す
}

fun attack(targetHp: Int, attackPower: Int, attacker: String, target: String): Int {
    val newHp = targetHp - attackPower
    println("$attackerは$targetに$attackPowerのダメージを与えた!")
    return newHp
}

fun performMonsterAttack(successRate: Int): String {
    val chance = Random.nextInt(100) + 1
    return if (chance <= successRate) "hit" else "miss"
}

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

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

練習問題の解答と解説

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

正解コードの例

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

import kotlin.random.Random

fun main() {
    var playerHp = 100
    val playerAttackPower = 20
    var monsterHp = 100
    val monsterAttackPower = 40
    var monsterAttackSuccessRate = 60

    println("=== モンスターとのバトルゲーム ===")

    while (playerHp > 0 && monsterHp > 0) {
        displayStatus(playerHp, monsterHp, monsterAttackSuccessRate)
        val playerAction = getPlayerAction()
        if (playerAction == 1) {
            monsterHp = attack(monsterHp, playerAttackPower, "勇者", "ドラゴン")
        } else if (playerAction == 2) {
            println("勇者は防御を選択した!")
            val monsterAction = performMonsterAttack(monsterAttackSuccessRate)
            if (monsterAction == "miss") {
                monsterAttackSuccessRate += 20
                println("ドラゴンの攻撃がミス!攻撃成功率が${monsterAttackSuccessRate}%に上昇!")
                continue
            }
        }

        if (monsterHp <= 0) {
            println("ドラゴンは倒された!勇者の勝利!")
            break
        }

        println("ドラゴンの攻撃!")
        val attackResult = performMonsterAttack(monsterAttackSuccessRate)
        if (attackResult == "hit") {
            playerHp = attack(playerHp, monsterAttackPower, "ドラゴン", "勇者")
            monsterAttackSuccessRate = 60
        } else {
            monsterAttackSuccessRate += 20
            println("ドラゴンの攻撃がミス!攻撃成功率が${monsterAttackSuccessRate}%に上昇!")
        }

        if (playerHp <= 0) {
            println("勇者は倒された…ドラゴンの勝利!")
        }
    }
}

fun displayStatus(playerHp: Int, monsterHp: Int, monsterAttackSuccessRate: Int) {
    println("勇者のHP: $playerHp, ドラゴンのHP: $monsterHp, ドラゴンの攻撃成功率: $monsterAttackSuccessRate%")
}

fun getPlayerAction(): Int {
    println("攻撃するか防御するかを選んでください (1: 攻撃, 2: 防御):")
    return readLine()?.toIntOrNull() ?: getPlayerAction() // 再帰的に再入力を促す
}

fun attack(targetHp: Int, attackPower: Int, attacker: String, target: String): Int {
    val newHp = targetHp - attackPower
    println("$attacker は $target に $attackPower のダメージを与えた!")
    return newHp
}

fun performMonsterAttack(successRate: Int): String {
    val chance = Random.nextInt(100) + 1
    return if (chance <= successRate) "hit" else "miss"
}

正解コードの解説

今回のKotlinコードでは勇者とモンスターが戦うバトルゲームを実装しています。

このコードをブロックごとに分け、文法と動作について初心者向けに説明します。

変数の宣言と初期化

var playerHp = 100
val playerAttackPower = 20
var monsterHp = 100
val monsterAttackPower = 40
var monsterAttackSuccessRate = 60
  • playerHp: 勇者の体力(変化するため var)。
  • playerAttackPower: 勇者の攻撃力(一定値のため val)。
  • monsterHp: モンスターの体力(変化するため var)。
  • monsterAttackPower: モンスターの攻撃力(一定値のため val)。
  • monsterAttackSuccessRate: モンスターの攻撃成功率。

メイン関数とゲームループ

fun main() {
    println("=== モンスターとのバトルゲーム ===")
    while (playerHp > 0 && monsterHp > 0) {
        displayStatus(playerHp, monsterHp, monsterAttackSuccessRate)
        val playerAction = getPlayerAction()
        ...
    }
}
  • fun main():Kotlinプログラムのエントリーポイント。
  • while ループ:勇者またはモンスターのHPが0になるまでゲームを続けます。

状態表示の関数

fun displayStatus(playerHp: Int, monsterHp: Int, monsterAttackSuccessRate: Int) {
    println("勇者のHP: $playerHp, ドラゴンのHP: $monsterHp, ドラゴンの攻撃成功率: $monsterAttackSuccessRate%")
}
  • 引数:関数に渡される値(例: playerHp, monsterHp, monsterAttackSuccessRate)。
  • println:コンソールに情報を表示するための関数。

プレイヤーの行動取得

fun getPlayerAction(): Int {
    println("攻撃するか防御するかを選んでください (1: 攻撃, 2: 防御):")
    return readLine()?.toIntOrNull() ?: getPlayerAction()
}
  • readLine():ユーザーから入力を取得。
  • toIntOrNull():入力を整数に変換し、失敗した場合は null を返す。
  • 再帰呼び出し:無効な入力がされた場合、再び関数を呼び出して再入力を促します。

攻撃の処理

fun attack(targetHp: Int, attackPower: Int, attacker: String, target: String): Int {
    val newHp = targetHp - attackPower
    println("$attackerは$targetに$attackPowerのダメージを与えた!")
    return newHp
}
  • targetHp - attackPower:相手の体力から攻撃力を引き、残り体力を計算。
  • テンプレート文字列:"${変数}" を使って文字列に値を埋め込む。

モンスターの攻撃処理

fun performMonsterAttack(successRate: Int): String {
    val chance = Random.nextInt(100) + 1
    return if (chance <= successRate) "hit" else "miss"
}
  • Random.nextInt(100) + 1:1から100のランダムな整数を生成。
  • if:条件に応じて “hit” または “miss” を返す。

ゲーム終了と勝敗判定

if (playerHp <= 0) {
    println("勇者は倒された…ドラゴンの勝利!")
} else if (monsterHp <= 0) {
    println("ドラゴンは倒された!勇者の勝利!")
}

if-else:条件分岐により勝敗を判定。

まとめ

このコードではランダムな攻撃成功率やユーザー入力を活用して、シンプルなバトルゲームを実現しました。

Kotlinの基本文法(関数、条件分岐、ループ、テンプレート文字列、再帰)を学びながら、ゲームロジックを構築する楽しさを体験できます。

ぜひこのプログラムを参考に自分なりのゲームロジックを作ってみましょう!習得した知識を実際に応用することで、より深く理解できます。

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

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

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

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

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






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