Kotlinの初心者向け問題4-☆2:石取りゲームを作ろう
この問題を解くために必要な知識:
【レベル1~3の知識】
コメントの書き方、変数と定数、基本データ型、算術演算と論理演算、入力と出力、import文、配列、分岐処理(if、if~else、when)、繰り返し処理(for、while、do~while)、Null安全、スマートキャスト、関数の定義と呼び出し、関数の戻り値、関数のオーバーロード、ラベルとジャンプ、例外処理、クラスの定義と使用、インスタンス、コンストラクタ、プロパティ、クラスの継承、クラスの拡張、コレクションの基礎、リストコレクション(MutableList、ArrayList)、セットコレクション(HashSet、MutableSet、TreeSet)、マップコレクション(HashMap、MutableMap、TreeMap)
【レベル4の知識】
メンバ関数、ゲッターとセッター、カプセル化、クラスメンバ、抽象クラス、インターフェース、データクラス
<<前の問題 | 問題集Top |
次の問題>> |
Kotlin練習問題4-☆2:石取りゲームを作ろう
この課題では、2人のプレイヤーが交互に石を取り合う「石取りゲーム」を作成します。
各プレイヤーは1ターンで1~3個の石を取ることができます。最後の石を取ったプレイヤーが負けとなります。
この問題の要件
以下の要件に従ってプログラムを作成してください。
- 抽象クラス
Player
を定義することname
という名前のプロパティ(String
型)を持つこと。takeStones
という抽象関数を持つこと。この関数は、プレイヤーが石を取る処理を定義します。
Player
クラスを継承するHumanPlayer
クラスを定義することtakeStones
関数をオーバーライドし、プレイヤーに1~3個の石を取るように指示すること。
Player
クラスを継承するAIPlayer
クラスを定義することtakeStones
関数をオーバーライドし、ランダムに1~3個の石を取ること。
Game
クラスを定義し、ゲームのロジックを実装することtotalStones
という名前のプロパティを持ち、ゲーム開始時の石の数を格納すること。startGame
という名前のメンバ関数を定義し、ゲームの進行を制御すること。
main
関数でゲームを実行することGame
オブジェクトを作成し、石の数を設定すること(例えば20個)。HumanPlayer
とAIPlayer
のオブジェクトを作成し、ゲームを開始すること。
ただし、以下のような実行結果となること。
----- ↓出力される結果の例↓ -----
残りの石の数: 20 あなた さん、何個の石を取りますか? (1~3個): 2 残りの石の数: 18 コンピュータ は 3 個の石を取りました 残りの石の数: 15 あなた さん、何個の石を取りますか? (1~3個): 3 残りの石の数: 12 コンピュータ は 1 個の石を取りました 残りの石の数: 11 あなた さん、何個の石を取りますか? (1~3個): 2 残りの石の数: 9 コンピュータ は 2 個の石を取りました 残りの石の数: 7 あなた さん、何個の石を取りますか? (1~3個): 3 残りの石の数: 4 コンピュータ は 1 個の石を取りました 残りの石の数: 3 あなた さん、何個の石を取りますか? (1~3個): 3 あなた が最後の石を取りました! あなた の負けです!
----- ↑出力される結果の例↑ -----
この問題を解くヒント
1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。
正解のコードは上から順に以下のような構成となっています。
1.Random
クラスのインポート
2.抽象クラスPlayer
の定義
2-1. name
プロパティの宣言
2-2. 抽象関数takeStones
の定義
3.HumanPlayer
クラスの定義
3-1. Player
クラスを継承
3-2. コンストラクタでname
を受け取る
3-3. takeStones
関数のオーバーライド
4.AIPlayer
クラスの定義
4-1. Player
クラスを継承
4-2. コンストラクタでname
を受け取る
4-3. takeStones
関数のオーバーライド
5.Game
クラスの定義
5-1. totalStones
プロパティの宣言
5-2. ゲームの進行を制御するstartGame
関数の定義
5-2-1. remainingStones
変数の初期化
5-2-2. ゲーム進行中のループ処理
5-2-2-1. 現在のプレイヤーが石を取る処理
5-2-2-2. プレイヤー交代の処理
6.main
関数の定義
6-1. Game
オブジェクトの作成
6-2. HumanPlayer
とAIPlayer
オブジェクトの作成
6-3. ゲーム開始のためにstartGame
関数を呼び出す
以下のコードをコピーし、コメントに従ってコードを完成させて下さい。
import kotlin.random.Random // 抽象クラス Player を定義 abstract class Player(val name: String) { // プレイヤーが石を取るための抽象関数 abstract fun takeStones(totalStones: Int): Int } // 人間プレイヤーを表すクラス class HumanPlayer(name: String) : Player(name) { // 人間プレイヤーが石を取る処理を実装 override fun takeStones(totalStones: Int): Int { println("$name さん、何個の石を取りますか? (1~3個): ") /* 【穴埋め問題1】 ここにユーザーの入力を受け取り、変数 stones に格納するコードを書いてください。 1~3の範囲に制限するための処理も含めてください。 */ } } // AIプレイヤーを表すクラス class AIPlayer(name: String) : Player(name) { // AIプレイヤーがランダムに石を取る処理を実装 override fun takeStones(totalStones: Int): Int { /* 【穴埋め問題2】 ここにAIが1~3個のランダムな数の石を取るコードを書いてください。 */ } } // ゲームのロジックを実装するクラス class Game(val totalStones: Int) { private var remainingStones = totalStones // ゲームを開始するメンバ関数 fun startGame(player1: Player, player2: Player) { var currentPlayer = player1 while (remainingStones > 0) { println("残りの石の数: $remainingStones") /* 【穴埋め問題3】 ここに現在のプレイヤーが石を取る処理と、 その結果、残りの石を減らすコードを書いてください。 最後の石を取ったプレイヤーを判定し、負けと表示する処理も含めてください。 */ // プレイヤー交代 currentPlayer = if (currentPlayer == player1) player2 else player1 } } } fun main() { // 石の数を設定してゲームを開始 val game = Game(20) // 人間プレイヤーとAIプレイヤーを作成 val human = HumanPlayer("あなた") val ai = AIPlayer("コンピュータ") // ゲーム開始 game.startGame(human, ai) }
このヒントを見てもまだ回答を導き出すのが難しいと感じる場合は、先に正解のコードと解説を見て内容を理解するようにしましょう。
解答例
この問題の一つの正解例とそのコードの解説を以下に示します。
正解コードの例
例えば以下のようなプログラムが考えられます。
********************
import kotlin.random.Random // 抽象クラス Player を定義 abstract class Player(val name: String) { // プレイヤーが石を取るための抽象関数 abstract fun takeStones(totalStones: Int): Int } // 人間プレイヤーを表すクラス class HumanPlayer(name: String) : Player(name) { // 人間プレイヤーが石を取る処理を実装 override fun takeStones(totalStones: Int): Int { println("$name さん、何個の石を取りますか? (1~3個): ") val stones = readLine()?.toIntOrNull() ?: 1 return stones.coerceIn(1, 3) // 1~3の範囲に制限 } } // AIプレイヤーを表すクラス class AIPlayer(name: String) : Player(name) { // AIプレイヤーがランダムに石を取る処理を実装 override fun takeStones(totalStones: Int): Int { val stones = Random.nextInt(1, 4) // 1~3のランダムな数 println("$name は $stones 個の石を取りました") return stones } } // ゲームのロジックを実装するクラス class Game(val totalStones: Int) { private var remainingStones = totalStones // ゲームを開始するメンバ関数 fun startGame(player1: Player, player2: Player) { var currentPlayer = player1 while (remainingStones > 0) { println("残りの石の数: $remainingStones") val stonesTaken = currentPlayer.takeStones(remainingStones) remainingStones -= stonesTaken if (remainingStones <= 0) { println("${currentPlayer.name} が最後の石を取りました!") println("${currentPlayer.name} の負けです!") break } // プレイヤー交代 currentPlayer = if (currentPlayer == player1) player2 else player1 } } } fun main() { // 石の数を設定してゲームを開始 val game = Game(20) // 人間プレイヤーとAIプレイヤーを作成 val human = HumanPlayer("あなた") val ai = AIPlayer("コンピュータ") // ゲーム開始 game.startGame(human, ai) }
********************
正解コードの解説
このコードでは、プレイヤーとコンピュータが交互に石を取る「石取りゲーム」を実装しています。
ゲームは、プレイヤーとAI(コンピュータ)が交互に1~3個の石を取るシンプルなルールです。
ここでは、抽象クラスを使ってプレイヤーの共通の機能を実装し、それを継承して具体的なプレイヤーとAIの動作を定義しています。
import kotlin.random.Random
Kotlin標準ライブラリのRandom
クラスをインポートしています。これにより、プログラムでランダムな数値を生成することができます。
抽象クラス Player
の定義
abstract class Player(val name: String)
抽象クラスは、共通の機能を定義するためのクラスです。このクラス自体はインスタンス化されませんが、他のクラスがこれを継承して具体的な機能を実装します。
Player
クラスは、name
という名前のプロパティを持ち、各プレイヤーの名前を保持します。
また、takeStones
という抽象メソッドを定義しており、具体的なプレイヤークラスでこのメソッドを実装する必要があります。
takeStones
関数
abstract fun takeStones(totalStones: Int): Int
この関数は、プレイヤーがどれだけの石を取るかを決定するための抽象メソッドです。HumanPlayer
やAIPlayer
クラスで具体的に実装されます。
HumanPlayer
クラス
class HumanPlayer(name: String) : Player(name)
Player
クラスを継承するクラスです。プレイヤーが石を取る際の動作を実装しています。ユーザーに対して1~3の範囲で石を取る数を入力させ、その数を返します。
AIPlayer
クラス
class AIPlayer(name: String) : Player(name)
同様に、Player
クラスを継承するクラスです。AIがランダムに1~3個の石を取る動作を実装しています。
Random.nextInt(1, 4)
を使ってランダムな数値を生成し、その数を返します。
Game
クラス
class Game(val totalStones: Int)
このクラスはゲームのロジック全体を管理します。totalStones
はゲーム開始時の石の総数です。startGame
関数を使ってゲームを進行させます。
startGame
関数
この関数は、ゲームを開始し、プレイヤーが交互に石を取る動作を制御します。石が0になるまでゲームを続け、最後に石を取ったプレイヤーが負けとなります。
main
関数
main
関数はプログラムのエントリーポイントです。ここでは、ゲームの初期化やプレイヤーの作成、ゲームの開始が行われます。
まとめ
このコードでは、Kotlinの抽象クラスと継承の基本的な使い方を学ぶことができます。
Player
クラスを抽象クラスとして定義し、それを継承して具体的なHumanPlayer
やAIPlayer
を実装することで、共通の機能を効率的に管理できる点が理解できるでしょう。
<<前の問題 |
問題集Top |
次の問題>> |
この問題への質問・コメント
この問題を作成するにあたりAIを活用しています。
問題ないことは確認していますが、もし間違いや表現の違和感などありましたら、ご指摘頂けると大変助かります。