Kotlinの初心者向け問題2-☆2:モンスターとのバトルゲームを作ろう
この問題を解くために必要な知識:
【レベル1の知識】
コメントの書き方、変数と定数、基本データ型、算術演算と論理演算、入力と出力、import文、配列、分岐処理(if、if~else、when)、繰り返し処理(for、while、do~while)、Null安全、スマートキャスト
【レベル2の知識】
関数の定義と呼び出し、関数の戻り値、関数のオーバーロード、ラベルとジャンプ、例外処理、クラスの定義と使用、インスタンス、コンストラクタ、プロパティ、クラスの継承、クラスの拡張
<<前の問題 | 問題集Top |
次の問題>> |
Kotlin練習問題2-☆2:モンスターとのバトルゲームを作ろう
プレイヤーとモンスターが戦うシンプルなバトルゲームを作成しましょう。
プレイヤーとモンスターはそれぞれ攻撃や防御のアクションを行い、HP(ヒットポイント)がゼロになるまで戦います。
この問題の要件
以下の要件に従ってプログラムを作成してください。
- プレイヤークラスとモンスタークラスを作成し、それぞれに名前(name)、HP(hp)、攻撃力(attackPower)のプロパティを持たせること。
- 勇者の攻撃力は20、スライムの攻撃力は40とします。
- スライムの攻撃は60%の確率で成功し、40%の確率でミスします。スライムの攻撃がミスした場合、次のスライム攻撃の成功率に20%加え、成功した場合は60%にリセットします。
- 勇者は攻撃するか防御するかを選択でき、防御を選択した場合、スライムの攻撃を無効化し、スライムの攻撃成功率を60%にリセットします。
- 各ターンの結果をコンソールに出力すること。
- 勇者が攻撃するか防御するかを選択する前に、勇者のHPとスライムのHPとスライムの攻撃の成功率を表示すること。
- 最後に勝者を表示すること。
ただし、以下のような実行結果となること。
----- ↓出力される結果の例↓ -----
勇者のHP: 100, スライムのHP: 100, スライムの攻撃成功率: 60.0% 攻撃するか防御するかを選んでください (1: 攻撃, 2: 防御): 1 勇者の攻撃! スライムに20のダメージ! スライムの攻撃! 攻撃がミス! 勇者のHP: 100, スライムのHP: 80, スライムの攻撃成功率: 80.0% 攻撃するか防御するかを選んでください (1: 攻撃, 2: 防御): 2 勇者は防御を選択した! スライムの攻撃! 攻撃が成功! 勇者の攻撃を防御した! スライムの攻撃成功率は60.0%にリセットされました。 勇者のHP: 100, スライムのHP: 80, スライムの攻撃成功率: 60.0% ... スライムを倒した!勇者の勝利!
----- ↑出力される結果の例↑ -----
この問題を解くヒント
1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。
正解のコードは上から順に以下のような構成となっています。
1.Kotlin標準ライブラリからRandomクラスをインポート
2.Playerクラスの定義
2-1. Playerクラスのプロパティの定義
2-1-1. name(プレイヤーの名前)
2-1-2. hp(プレイヤーのHP)
2-1-3. attackPower(プレイヤーの攻撃力)
2-2. Playerクラスのattackメソッドの定義
2-2-1. プレイヤーの攻撃メッセージを表示
2-2-2. モンスターのHPを減少
2-2-3. ダメージメッセージを表示
3.Monsterクラスの定義
3-1. Monsterクラスのプロパティの定義
3-1-1. name(モンスターの名前)
3-1-2. hp(モンスターのHP)
3-1-3. attackPower(モンスターの攻撃力)
3-1-4. attackSuccessRate(モンスターの攻撃成功率、初期値0.6)
3-2. Monsterクラスのattackメソッドの定義
3-2-1. モンスターの攻撃メッセージを表示
3-2-2. 乱数生成と攻撃成功判定
3-2-3. 攻撃が成功した場合、プレイヤーのHPを減少させる
3-2-4. 攻撃が失敗した場合、次回の攻撃成功率を20%増加
4.main関数の定義
4-1. PlayerとMonsterオブジェクトの作成
4-2. バトルループの開始
4-2-1. プレイヤーとモンスターのステータスを表示
4-2-2. ユーザー入力の取得(攻撃か防御かを選択)
4-2-3. プレイヤーが攻撃を選択した場合、モンスターを攻撃
4-2-4. モンスターが倒された場合のメッセージ表示
4-2-5. モンスターが攻撃を開始
4-2-6. プレイヤーが防御を選択した場合、防御メッセージとモンスターの攻撃成功率をリセット
4-2-7. プレイヤーが倒された場合のメッセージ表示
以下のコードをコピーし、コメントに従ってコードを完成させて下さい。
import kotlin.random.Random // プレイヤークラスを定義 class Player(val name: String, var hp: Int, val attackPower: Int) { // プレイヤーの攻撃関数 fun attack(opponent: Monster) { println("${name}の攻撃!") // プレイヤーが攻撃を開始したことを表示 /* 【穴埋め問題1】 ここに相手のモンスターのHPをプレイヤーの攻撃力分減らすコードを書いてください。 */ println("${opponent.name}に${attackPower}のダメージ!") // 相手に与えたダメージを表示 } } // モンスタークラスを定義 class Monster(val name: String, var hp: Int, val attackPower: Int) { var attackSuccessRate = 0.6 // 初期の攻撃成功率は60% // モンスターの攻撃関数 fun attack(opponent: Player) { println("${name}の攻撃!") // モンスターが攻撃を開始したことを表示 /* 【穴埋め問題2】 ここに乱数を生成し、モンスターの攻撃成功率に基づいて攻撃を成功させるかどうかを判断するコードを書いてください。 */ /* 【穴埋め問題3】 ここに相手のプレイヤーのHPをモンスターの攻撃力分減らすコードを書いてください。攻撃が成功した場合のみ行います。 */ println("${opponent.name}に${attackPower}のダメージ!") // 相手に与えたダメージを表示 } } // メイン関数 fun main() { // プレイヤーとモンスターのインスタンスを作成 /* 【穴埋め問題4】 プレイヤーとモンスターのインスタンスを作成するコードを書いてください。 */ // バトルループ while (player.hp > 0 && monster.hp > 0) { // 現在のステータスを表示 println("${player.name}のHP: ${player.hp}, ${monster.name}のHP: ${monster.hp}, ${monster.name}の攻撃成功率: ${monster.attackSuccessRate * 100}%") println("攻撃するか防御するかを選んでください (1: 攻撃, 2: 防御): ") val action = readLine()?.toIntOrNull() ?: 1 // ユーザーの入力を取得 if (action == 1) { player.attack(monster) // ユーザーが攻撃を選択した場合 } else if (action == 2) { println("${player.name}は防御を選択した!") // ユーザーが防御を選択した場合 } if (monster.hp <= 0) { println("${monster.name}を倒した!${player.name}の勝利!") // モンスターのHPが0以下の場合 break } if (action != 2) { monster.attack(player) // ユーザーが防御を選択していない場合、モンスターが攻撃 } else { println("${player.name}は攻撃を防御した!") // ユーザーが防御を選択した場合、モンスターの攻撃を無効化 monster.attackSuccessRate = 0.6 // スライムの攻撃成功率をリセット } if (player.hp <= 0) { println("${player.name}は倒された…${monster.name}の勝利!") // プレイヤーのHPが0以下の場合 break } } }
このヒントを見てもまだ回答を導き出すのが難しいと感じる場合は、先に正解のコードと解説を見て内容を理解するようにしましょう。
解答例
この問題の一つの正解例とそのコードの解説を以下に示します。
正解コードの例
例えば以下のようなプログラムが考えられます。
********************
import kotlin.random.Random // プレイヤークラスを定義 class Player(val name: String, var hp: Int, val attackPower: Int) { // プレイヤーの攻撃関数 fun attack(opponent: Monster) { println("${name}の攻撃!") // プレイヤーが攻撃を開始したことを表示 opponent.hp -= attackPower // 相手のHPをプレイヤーの攻撃力分減らす println("${opponent.name}に${attackPower}のダメージ!") // 相手に与えたダメージを表示 } } // モンスタークラスを定義 class Monster(val name: String, var hp: Int, val attackPower: Int) { var attackSuccessRate = 0.6 // 初期の攻撃成功率は60% // モンスターの攻撃関数 fun attack(opponent: Player) { println("${name}の攻撃!") // モンスターが攻撃を開始したことを表示 if (Random.nextDouble() <= attackSuccessRate) { // 乱数が成功率以下なら攻撃成功 println("攻撃が成功!") opponent.hp -= attackPower // 相手のHPをモンスターの攻撃力分減らす println("${opponent.name}に${attackPower}のダメージ!") // 相手に与えたダメージを表示 attackSuccessRate = 0.6 // 成功率をリセット } else { // 乱数が成功率以上なら攻撃ミス println("攻撃がミス!") attackSuccessRate += 0.2 // 次回の攻撃成功率を20%増加 } } } // メイン関数 fun main() { // プレイヤーとモンスターのインスタンスを作成 val player = Player("勇者", 100, 20) val monster = Monster("スライム", 100, 40) // バトルループ while (player.hp > 0 && monster.hp > 0) { // 現在のステータスを表示 println("${player.name}のHP: ${player.hp}, ${monster.name}のHP: ${monster.hp}, ${monster.name}の攻撃成功率: ${monster.attackSuccessRate * 100}%") println("攻撃するか防御するかを選んでください (1: 攻撃, 2: 防御): ") val action = readLine()?.toIntOrNull() ?: 1 // ユーザーの入力を取得 if (action == 1) { player.attack(monster) // ユーザーが攻撃を選択した場合 } else if (action == 2) { println("${player.name}は防御を選択した!") // ユーザーが防御を選択した場合 } if (monster.hp <= 0) { println("${monster.name}を倒した!${player.name}の勝利!") // モンスターのHPが0以下の場合 break } if (action != 2) { monster.attack(player) // ユーザーが防御を選択していない場合、モンスターが攻撃 } else { println("${player.name}は攻撃を防御した!") // ユーザーが防御を選択した場合、モンスターの攻撃を無効化 monster.attackSuccessRate = 0.6 // スライムの攻撃成功率をリセット } if (player.hp <= 0) { println("${player.name}は倒された…${monster.name}の勝利!") // プレイヤーのHPが0以下の場合 break } } }
********************
コードの解説
この解説では、Kotlinで作成した「プレイヤーとモンスターのバトルゲーム」のコードを初心者向けに説明します。このコードの各部分がどのように動作し、Kotlinの基本的な文法や構造がどのように使われているかを理解することができます。
ランダム関数のインポート
import kotlin.random.Random
最初に、Kotlin標準ライブラリからRandom
クラスをインポートします。これにより、プログラム内でランダムな数値を生成できるようになります。ランダムな数値は、モンスターの攻撃成功率を判定するために使用されます。
Playerクラスの定義
class Player(val name: String, var hp: Int, val attackPower: Int) {
Player
クラスは、プレイヤーの情報を保持し、攻撃する機能を持ちます。このクラスには、プレイヤーの名前 (name
)、HP (hp
)、攻撃力 (attackPower
) が含まれています。val
は値を変更できないプロパティ、var
は変更可能なプロパティを示します。
Playerクラスのattackメソッド
fun attack(opponent: Monster) { println("${name}の攻撃!") opponent.hp -= attackPower println("${opponent.name}に${attackPower}のダメージ!") }
attack
メソッドは、プレイヤーがモンスターを攻撃する機能を提供します。opponent
パラメータには、攻撃対象のモンスターが渡されます。攻撃が行われると、モンスターのHPがプレイヤーの攻撃力だけ減少し、攻撃の結果が表示されます。
Monsterクラスの定義
class Monster(val name: String, var hp: Int, val attackPower: Int) { var attackSuccessRate = 0.6
Monster
クラスは、モンスターの情報を保持し、攻撃する機能を持ちます。プレイヤーと同様に、モンスターの名前、HP、攻撃力が含まれています。また、モンスターの攻撃成功率 (attackSuccessRate
) も保持されます。
Monsterクラスのattackメソッド
fun attack(opponent: Player) { println("${name}の攻撃!") if (Random.nextDouble() <= attackSuccessRate) { opponent.hp -= attackPower attackSuccessRate = 0.6 } else { attackSuccessRate += 0.2 } println("${opponent.name}に${attackPower}のダメージ!") }
attack
メソッドは、モンスターがプレイヤーを攻撃する機能を提供します。このメソッドでは、ランダムな数値を生成し、モンスターの攻撃が成功するかどうかを判定します。
攻撃が成功すると、プレイヤーのHPが減少し、攻撃成功率がリセットされます。失敗した場合、次回の攻撃成功率が20%増加します。
メイン関数の定義とバトルの開始
fun main() { val player = Player("勇者", 100, 20) val monster = Monster("スライム", 100, 40)
main
関数はプログラムのエントリーポイントです。ここでプレイヤーとモンスターのインスタンスが作成され、バトルが開始されます。プレイヤーとモンスターの初期状態が設定され、バトルループが開始されます。
バトルループの実行
while (player.hp > 0 && monster.hp > 0) {
このwhile
ループは、プレイヤーかモンスターのHPが0になるまで繰り返されます。各ループでは、プレイヤーが攻撃するか防御するかを選択し、モンスターが攻撃を行います。
プレイヤーの行動選択
val action = readLine()?.toIntOrNull() ?: 1 if (action == 1) { player.attack(monster) } else if (action == 2) { println("${player.name}は防御を選択した!") }
プレイヤーは、攻撃 (1) または防御 (2) を選択できます。入力された値に応じて、プレイヤーの行動が決まります。攻撃を選択すると、プレイヤーがモンスターを攻撃し、防御を選択すると、次のモンスターの攻撃が防がれます。
モンスターの攻撃
if (action != 2) { monster.attack(player) } else { println("${player.name}は攻撃を防御した!") monster.attackSuccessRate = 0.6 }
プレイヤーが防御を選択していない場合、モンスターがプレイヤーを攻撃します。防御を選択した場合、モンスターの攻撃成功率がリセットされ、次回の攻撃に影響します。
バトルの終了
if (monster.hp <= 0) { println("${monster.name}を倒した!${player.name}の勝利!") break } if (player.hp <= 0) { println("${player.name}は倒された…${monster.name}の勝利!") break }
バトルが終了すると、勝者が決定され、バトルループが終了します。プレイヤーかモンスターのHPが0になると、どちらが勝利したかが表示されます。
<<前の問題 |
問題集Top |
次の問題>> |
この問題への質問・コメント
この問題を作成するにあたりAIを活用しています。
問題ないことは確認していますが、もし間違いや表現の違和感などありましたら、ご指摘頂けると大変助かります。