【Kotlin】レッスン5-☆1:モンスター捕獲ゲームを作ろう|抽象クラスとランダム処理で学ぶ継承の基本

一つ前のページではデータクラスについて学習しました。
今回は モンスター捕獲ゲーム を作成していきましょう。
Lesson1:基礎文法編
Lesson2:制御構造編
Lesson3:関数編
Lesson4:コレクション編
Lesson5:オブジェクト指向編
・Lesson5-1:クラスの基本を理解しよう
・Lesson5-2:プライマリコンストラクタを理解しよう
・Lesson5-3:セカンダリコンストラクタを理解しよう
・Lesson5-4:ふたつのコンストラクタを使いこなそう
・Lesson5-5:アクセス修飾子とカプセル化を理解しよう
・Lesson5-6:クラスメンバとインスタンスメンバを理解しよう
・Lesson5-7:クラスの継承を理解しよう
・Lesson5-8:メソッドのオーバーライドを理解しよう
・Lesson5-9:クラスを拡張しよう
・Lesson5-10:抽象クラスを理解しよう
・Lesson5-11:インターフェースを理解しよう
・Lesson5-12:データクラスを理解しよう
・確認問題5-☆1:モンスター捕獲ゲームを作ろう ◁今回はココ
・確認問題5-☆2:マルバツゲームを作ろう
・確認問題5-☆3:石取りゲームを作ろう
Kotlinのゲームコード一覧はこちら
Kotlinでモンスター捕獲ゲームを実装しよう|抽象クラスとサイコロロジックを学ぶ

複数のモンスターを捕まえるゲームを作成しましょう。
このゲームではモンスターがサイコロを振り、その結果を見てプレイヤーはサイコロを振るかどうかを決めることができます。
プレイヤーのサイコロの目がモンスターのサイコロの目より大きければ捕獲成功。小さければ失敗でゲーム終了です。
この問題の要件
以下の要件に従ってコードを完成させてください。
- 抽象クラス
Character
を定義name
という名前のプロパティを持ちます(String
型)。- サイコロを振る
rollDice
という関数を持ちます。この関数は 1 から 6 までのランダムな整数を返します。
Character
クラスを継承するMonster
クラスを定義- コンストラクタでモンスターの名前を受け取ります。
Character
クラスを継承するPlayer
クラスを定義- コンストラクタでプレイヤーの名前を受け取ります。
main
関数でゲームを実行Player
オブジェクトを作成し、名前は「勇者」とします。Monster
オブジェクトを 3 つ作成し、それぞれ「ゴブリン」、「スライム」、「ドラゴン」という名前をつけます。- これらのモンスターを
ArrayList
に格納します。 - プレイヤーが各モンスターを捕まえようとするループを実行します。ループの中で、プレイヤーはサイコロを振るかどうかを決めることができます。
- プレイヤーのサイコロの目がモンスターのサイコロの目より大きければ捕まえることができます。失敗するとゲームオーバーとなり、ループが終了します。
ただし、以下のような実行結果となること。
ゴブリンを捕まえようとしています... ゴブリンのサイコロ: 4 サイコロを振りますか? (yes/no): yes プレイヤーのサイコロ: 6 ゴブリンを捕まえました! スライムを捕まえようとしています... スライムのサイコロ: 5 サイコロを振りますか? (yes/no): yes プレイヤーのサイコロ: 3 スライムを捕まえられませんでした... ゲームオーバー!
この問題を解くヒント
1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。
- ヒント1【コードの構成を見る】
-
正解のコードは上から順に以下のような構成となっています。
1:kotlin.random.Randomモジュールのインポート
2:抽象クラスCharacterの定義
□ プライマリコンストラクタでnameプロパティを初期化
□ rollDice関数の定義
□ □ Random.nextIntを用いて1から6までのランダムな整数を返す
3:Monsterクラスの定義
□ Characterクラスを継承
4:Playerクラスの定義
□ Characterクラスを継承
5:main関数の定義
□ Playerオブジェクトplayerの生成
□ Monsterオブジェクトmonster1、monster2、monster3の生成
□ ArrayListにモンスターを格納
□ forループでmonstersリストを反復処理
□ □ モンスターの名前を出力
□ □ モンスターのrollDice関数を呼び出して結果をmonsterRollに格納
□ □ monsterRollを出力
□ □ 「サイコロを振りますか?」と出力
□ □ ユーザー入力を受け取り、response変数に格納
□ □ if文でresponseが”yes”と一致するか判定(大文字小文字を無視)
□ □ □ プレイヤーのrollDice関数を呼び出して結果をplayerRollに格納
□ □ □ playerRollを出力
□ □ □ if文でplayerRollがmonsterRollより大きいか判定
□ □ □ □ 成功メッセージを出力
□ □ □ □ ゲーム続行
□ □ □ else文
□ □ □ □ 失敗メッセージを出力
□ □ □ □ ゲームオーバーメッセージを出力
□ □ □ □ breakでループ終了
□ □ else文
□ □ □ モンスター捕獲を諦めた旨を出力
- ヒント2【穴埋め問題にする】
-
以下のコードをコピーし、コメントに従ってコードを完成させて下さい。
import kotlin.random.Random // 抽象クラス Character を定義 abstract class Character(val name: String) { // サイコロを振る関数 fun rollDice(): Int { /* 【穴埋め問題1】 ここにサイコロを振るためのランダムな数を生成するコードを書いてください。 */ } } // Character クラスを継承する Monster クラスを定義 class Monster(name: String) : Character(name) // Character クラスを継承する Player クラスを定義 class Player(name: String) : Character(name) fun main() { // プレイヤーを作成 val player = Player("勇者") // モンスターを作成 val monster1 = Monster("ゴブリン") val monster2 = Monster("スライム") val monster3 = Monster("ドラゴン") // モンスターを格納するArrayListを作成 val monsters = arrayListOf(monster1, monster2, monster3) // プレイヤーがモンスターを捕まえようとするループ for (monster in monsters) { println("${monster.name}を捕まえようとしています...") val monsterRoll = monster.rollDice() println("${monster.name}のサイコロ: $monsterRoll") print("サイコロを振りますか? (yes/no): ") val response = readLine()?.trim() ?: "" if (response.equals("yes", ignoreCase = true)) { /* 【穴埋め問題2】 ここにプレイヤーがサイコロを振るためのコードを書いてください。 */ } else { println("${monster.name}を捕まえるのを諦めました。") } } }
このヒントを見てもまだ回答を導き出すのが難しいと感じる場合は、先に正解のコードと解説を見て内容を理解するようにしましょう。
練習問題の解答と解説
この問題の正解コードとその解説は以下の通りです。
クリックして開いて確認してください。
- 正解コード
-
import kotlin.random.Random // 抽象クラス Character を定義 abstract class Character(val name: String) { // サイコロを振る関数 fun rollDice(): Int { return Random.nextInt(6) + 1 // 1から6までのランダムな数を返す } } // Character クラスを継承する Monster クラスを定義 class Monster(name: String) : Character(name) // Character クラスを継承する Player クラスを定義 class Player(name: String) : Character(name) fun main() { // プレイヤーを作成 val player = Player("勇者") // モンスターを作成 val monster1 = Monster("ゴブリン") val monster2 = Monster("スライム") val monster3 = Monster("ドラゴン") // モンスターを格納するArrayListを作成 val monsters = arrayListOf(monster1, monster2, monster3) // プレイヤーがモンスターを捕まえようとするループ for (monster in monsters) { println("${monster.name}を捕まえようとしています...") val monsterRoll = monster.rollDice() println("${monster.name}のサイコロ: $monsterRoll") print("サイコロを振りますか? (yes/no): ") val response = readLine()?.trim() ?: "" if (response.equals("yes", ignoreCase = true)) { val playerRoll = player.rollDice() println("プレイヤーのサイコロ: $playerRoll") if (playerRoll > monsterRoll) { println("${monster.name}を捕まえました!") } else { println("${monster.name}を捕まえられませんでした...") println("ゲームオーバー!") break } } else { println("${monster.name}を捕まえるのを諦めました。") } } }
- 正解コードの解説
-
コードをブロックごとに分割して解説します。
抽象クラス Character の定義
abstract class Character(val name: String) { fun rollDice(): Int { return Random.nextInt(6) + 1 } }
- abstract class Character: これは抽象クラスで、具体的なインスタンスを作成できません。他のクラスが継承して使うことを目的としています。
- val name: String: キャラクターの名前を表すプロパティです。
- fun rollDice(): Int: サイコロを振る関数です。
Random.nextInt(6)
によって、1~6 のランダムな値を生成します。
Monster クラスと Player クラスの定義
class Monster(name: String) : Character(name) class Player(name: String) : Character(name)
- class Monster:
Character
クラスを継承しています。モンスター専用の追加機能はありません。 - class Player: プレイヤーのクラスも
Character
を継承し、基本的に同じ構造です。
main関数とゲームのセットアップ
fun main() { val player = Player("勇者") val monster1 = Monster("ゴブリン") val monster2 = Monster("スライム") val monster3 = Monster("ドラゴン") val monsters = arrayListOf(monster1, monster2, monster3)
- fun main(): Kotlinプログラムのエントリーポイントです。
- val player = Player(“勇者”): プレイヤーのインスタンスを作成します。
- val monsters = arrayListOf(…): モンスターをリストに格納し、順番に操作できるようにします。
モンスターとの対戦ループ
for (monster in monsters) { println("${monster.name}を捕まえようとしています...") val monsterRoll = monster.rollDice() println("${monster.name}のサイコロ: $monsterRoll")
- for (monster in monsters): リスト内のモンスターを1体ずつ順番に処理します。
- monster.rollDice(): モンスターがサイコロを振ります。
プレイヤーの選択と対戦結果の処理
print("サイコロを振りますか? (yes/no): ") val response = readLine()?.trim() ?: "" if (response.equals("yes", ignoreCase = true)) { val playerRoll = player.rollDice() println("プレイヤーのサイコロ: $playerRoll") if (playerRoll > monsterRoll) { println("${monster.name}を捕まえました!") } else { println("${monster.name}を捕まえられませんでした...") println("ゲームオーバー!") break } } else { println("${monster.name}を捕まえるのを諦めました。") } }
- readLine(): コンソールからユーザーの入力を取得します。
- response.equals(“yes”, ignoreCase = true): ユーザーが「yes」を入力したかを確認します。
- player.rollDice(): プレイヤーがサイコロを振ります。
- if (playerRoll > monsterRoll): プレイヤーのサイコロの値がモンスターより大きい場合、捕まえることに成功します。それ以外はゲームオーバーになります。
まとめ
このコードではKotlinの基本的なクラス構造やリスト操作、サイコロを使ったゲームロジックを学べます。
特に継承とループの使い方、そしてユーザー入力の処理が中心となっています。
これを応用して、さらに複雑なゲームやアプリを作成できるスキルを磨いていきましょう!
Kotlinのゲームコード一覧はこちら