【Kotlin】レッスン3-☆3:バトルゲームを作ろう|条件分岐と乱数の応用で対戦ロジックを学ぶ

一つ前のページでは丁半賭博ゲームを作成しました。
今回は モンスターとのバトルゲーム を作成していきましょう。
Lesson1:基礎文法編
Lesson2:制御構造編
Lesson3:関数編
・Lesson3-1:関数の基本を理解しよう
・Lesson3-2:デフォルト引数とキーワード引数を理解しよう
・Lesson3-3:関数の戻り値を理解しよう
・Lesson3-4:真偽値を返す関数を理解しよう
・Lesson3-5:関数のオーバーロードを理解しよう
・Lesson3-6:ジェネリクスの基礎を理解しよう
・確認問題3-☆1:ブラックジャックゲームを作ろう
・確認問題3-☆2:丁半賭博ゲームを作ろう
・確認問題3-☆3:モンスターとのバトルゲームを作ろう ◁今回はココ
Lesson4:コレクション編
Lesson5:オブジェクト指向編
Kotlinのゲームコード一覧はこちら
確認問題:Kotlinで勇者とモンスターの対戦ゲームを実装しよう

勇者とモンスターが戦うバトルゲームを作成してください。このゲームでは、以下のルールに従います:
- HPが0以下になった方が敗北となり、ゲームは終了します。
- プレイヤー(勇者)は攻撃または防御の選択が可能です。
- モンスターはランダムな成功率で攻撃を試みます。
- 勇者の攻撃が成功すると、モンスターのHPが減少します。
- 勇者が防御を選択し、モンスターの攻撃が失敗した場合、モンスターの攻撃成功率が増加します。
この問題の要件
以下の要件に従ってコードを完成させてください。
- 変数定義:
- 勇者のHP (
playerHp
) を100で初期化すること。 - 勇者の攻撃力 (
playerAttackPower
) を20で設定すること。 - モンスターのHP (
monsterHp
) を100で初期化すること。 - モンスターの攻撃力 (
monsterAttackPower
) を40で設定すること。 - モンスターの攻撃成功率 (
monsterAttackSuccessRate
) を60で初期化すること。
- 勇者のHP (
- ゲーム進行:
- ゲーム開始時にタイトルを表示すること。
- 勇者とモンスターのHPおよびモンスターの攻撃成功率を毎ターン表示すること。
- プレイヤーが攻撃を選択した場合、モンスターのHPが減少すること。
- プレイヤーが防御を選択した場合、モンスターの攻撃が失敗すれば、攻撃成功率を20%増加させること。
- 勇者またはモンスターのHPが0以下になった場合、勝敗メッセージを表示してゲームを終了すること。
- ランダム性:
- モンスターの攻撃が成功するかはランダムな確率に基づき判定すること。
- ユーザー入力:
- 勇者の行動は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" }
- 正解コードの解説
-
コードをブロックごとに分割して解説します。
変数の宣言と初期化
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のゲームコード一覧はこちら