Rubyの初心者向け問題4-☆3:モンスターとの戦闘ゲームを作ろう
この問題を解くために必要な知識:
【レベル1~3の知識】
コメントの書き方、変数と定数、基本データ型、四則演算と演算子、入力と出力、文字列操作、分岐処理(if、if~else、elsif、case)、繰り返し処理(for、while、until、each)、範囲(Range)、例外処理(begin-rescue-end)、配列(Array)、ハッシュ(Hash)、コレクション操作(配列、ハッシュの操作)、Enumerableモジュール、メソッドの定義と呼び出し、メソッドの戻り値、クラスの定義と使用、コンストラクタ、クラスの継承、モジュールの定義と使用、ミックスイン
【レベル4の知識】
アクセスメソッド(ゲッター、セッター)、カプセル化、クラスメソッドとインスタンスメソッド、共通メソッド、ブロックとイテレータ、プロック(Proc)、ラムダ(Lambda)、ファイル操作(読み書き)、正規表現、メタプログラミングの基礎
<<前の問題 | 問題集Top |
次の問題>> |
Ruby練習問題4-☆3:モンスターとの戦闘ゲームを作ろう
シンプルな戦闘ゲームを作成しましょう。
このゲームではプレイヤーとモンスターはそれぞれターンごとに攻撃を行い、相手のHPを0にした方が勝利です。
プレイヤーとモンスターの攻撃力はメタプログラミングを使って動的に設定します。
この問題の要件
以下の要件に従ったプログラムを作成すること。
- PlayerクラスとMonsterクラスを作成します。
- 各クラスには
name
、attack_power
のアクセサメソッドを定義します。 - メタプログラミングを使って、プレイヤーとモンスターの攻撃力を動的に設定するメソッドを定義します。
- プレイヤーの攻撃力は25とし、モンスターの攻撃力は40とします。
- ゲームはターン制で進行し、プレイヤーとモンスターは交互に攻撃します。
- モンスターの攻撃の成功率は50%ですが、攻撃に失敗した場合は次の攻撃の成功率が20%上がります。攻撃に成功した場合は次の攻撃の成功率は50%に戻ります。プレイヤーが防御を選んだ場合、その次のモンスターの攻撃の成功率は50%になります。
- プレイヤーは毎回攻撃するか防御するかを選択できます。防御を選んだ場合、モンスターから受けるダメージが0になります。
- 攻撃の結果は攻撃力の値が相手のHPから減算されます。HPが0以下になった方が負けです。
- プレイヤーとモンスターの初期HPはそれぞれ100とします。
ただし、以下のような実行結果となること。
----- ↓出力される結果の例↓ -----
ゲームを開始します。 次のモンスターの攻撃の成功率は 50% です。 攻撃しますか?防御しますか? (1: 攻撃, 2: 防御): 1 プレイヤーの攻撃: 25 ダメージ モンスターのHP: 75 モンスターの攻撃: 40 ダメージ プレイヤーのHP: 60 次のモンスターの攻撃の成功率は 50% です。 ... プレイヤーの勝利!
----- ↑出力される結果の例↑ -----
この問題を解くヒント
1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。
正解のコードは以下のような構成となっています。
1.Playerクラスの定義
1-1. attr_accessor で name, attack_power, hp を定義
1-2. initialize メソッドで初期化(デフォルトの名前は”プレイヤー”, HPは100)
2.Monsterクラスの定義
2-1. attr_accessor で name, attack_power, hp, attack_success_rate を定義
2-2. initialize メソッドで初期化(デフォルトの名前は”モンスター”, HPは100, 攻撃成功率は0.5)
2-3. update_success_rate メソッドで攻撃成功率を更新するメソッドを定義
3.メタプログラミングを使ったメソッド定義
3-1. set_attack_power メソッドを定義し、プレイヤーとモンスターの攻撃力を動的に設定
4.ゲームの開始
4-1. プレイヤーとモンスターのインスタンスを作成
4-2. set_attack_power メソッドを使用して、プレイヤーとモンスターの攻撃力を設定
4-3. ターン制の戦闘を開始
4-3-1. プレイヤーとモンスターのHPが0以上である限り戦闘を続行
4-3-1-1. モンスターの次の攻撃の成功率を表示
4-3-1-2. プレイヤーのターンで攻撃か防御かを選択
4-3-1-2-1. 攻撃を選んだ場合、モンスターにダメージを与える
4-3-1-2-2. 防御を選んだ場合、防御メッセージを表示
4-3-1-2-3. 無効な選択の場合、再度選択を促す
4-3-1-3. モンスターのHPが0以下の場合、戦闘を終了
4-3-1-4. モンスターのターンで攻撃の成功をランダムに判定
4-3-1-4-1. 攻撃が成功した場合、プレイヤーにダメージを与え、成功率をリセット
4-3-1-4-2. 防御を選んだ場合、ダメージを受けない
4-3-1-4-3. 攻撃が失敗した場合、攻撃成功率を増加
4-3-1-5. プレイヤーが防御を選んだ場合、モンスターの攻撃成功率をリセット
5.勝敗判定
5-1. プレイヤーのHPが0より大きい場合、プレイヤーの勝利を表示
5-2. モンスターのHPが0より大きい場合、モンスターの勝利を表示
以下のコードをコピーし、コメントに従ってコードを完成させてください。
# Playerクラスを定義 class Player attr_accessor :name, :attack_power, :hp def initialize(name = "プレイヤー") @name = name @hp = 100 end end # Monsterクラスを定義 class Monster attr_accessor :name, :attack_power, :hp, :attack_success_rate def initialize(name = "モンスター") @name = name @hp = 100 @attack_success_rate = 0.5 # 初期攻撃成功率 end # 攻撃成功率を更新 def update_success_rate(success) if success @attack_success_rate = 0.5 else @attack_success_rate += 0.2 end end end # メタプログラミングを使って動的に攻撃力を設定 def set_attack_power(object, attack_power) object.instance_eval do ***ここにメソッドを動的に定義して攻撃力を設定するコードを書いてください*** end end # ゲームを開始 puts "ゲームを開始します。" player = Player.new monster = Monster.new # プレイヤーとモンスターの攻撃力を設定 ***ここにプレイヤーの攻撃力を設定するコードを書いてください*** ***ここにモンスターの攻撃力を設定するコードを書いてください*** # ターン制の戦闘 while player.hp > 0 && monster.hp > 0 # モンスターの次の攻撃の成功率を表示 puts "次のモンスターの攻撃の成功率は #{(monster.attack_success_rate * 100).round}% です。" # プレイヤーのターン puts "攻撃しますか?防御しますか? (1: 攻撃, 2: 防御): " action = gets.chomp.to_i if action == 1 ***ここにプレイヤーが攻撃するコードを書いてください*** elsif action == 2 puts "#{player.name}は防御を選択しました。" else puts "無効な選択です。再度選択してください。" next end break if monster.hp <= 0 # モンスターのターン if rand < monster.attack_success_rate damage_to_player = monster.attack_power if action == 2 puts "#{player.name}は防御に成功し、ダメージを受けませんでした。" else ***ここにモンスターが攻撃するコードを書いてください*** end monster.update_success_rate(true) else puts "#{monster.name}の攻撃は失敗しました。" monster.update_success_rate(false) end # プレイヤーが防御を選択した場合、モンスターの攻撃成功率をリセット monster.attack_success_rate = 0.5 if action == 2 end # 勝敗判定 if player.hp > 0 puts "#{player.name}の勝利!" else puts "#{monster.name}の勝利!" end
この問題の解答例
例えば以下のようなプログラムが考えられます。
********************
# Playerクラスを定義 class Player attr_accessor :name, :attack_power, :hp def initialize(name = "プレイヤー") @name = name @hp = 100 end # メタプログラミングを使って動的に攻撃力を設定 def set_power(attack) self.attack_power = attack end end # Monsterクラスを定義 class Monster attr_accessor :name, :attack_power, :hp, :attack_success_rate def initialize(name = "モンスター") @name = name @hp = 100 @attack_success_rate = 0.5 # 初期攻撃成功率 end # メタプログラミングを使って動的に攻撃力を設定 def set_power(attack) self.attack_power = attack end # 攻撃成功率を更新 def update_success_rate(success) if success @attack_success_rate = 0.5 else @attack_success_rate += 0.2 end end end # ゲームを開始 puts "ゲームを開始します。" player = Player.new monster = Monster.new # プレイヤーとモンスターの攻撃力を設定 player.set_power(25) monster.set_power(40) # ターン制の戦闘 while player.hp > 0 && monster.hp > 0 # モンスターの次の攻撃の成功率を表示 puts "次のモンスターの攻撃の成功率は #{(monster.attack_success_rate * 100).round}% です。" # プレイヤーのターン puts "攻撃しますか?防御しますか? (1: 攻撃, 2: 防御): " action = gets.chomp.to_i if action == 1 damage_to_monster = player.attack_power monster.hp -= damage_to_monster puts "#{player.name}の攻撃: #{damage_to_monster} ダメージ" puts "#{monster.name}のHP: #{monster.hp}" elsif action == 2 puts "#{player.name}は防御を選択しました。" else puts "無効な選択です。再度選択してください。" next end break if monster.hp <= 0 # モンスターのターン if rand < monster.attack_success_rate damage_to_player = monster.attack_power if action == 2 puts "#{player.name}は防御に成功し、ダメージを受けませんでした。" else player.hp -= damage_to_player puts "#{monster.name}の攻撃: #{damage_to_player} ダメージ" puts "#{player.name}のHP: #{player.hp}" end monster.update_success_rate(true) else puts "#{monster.name}の攻撃は失敗しました。" monster.update_success_rate(false) end # プレイヤーが防御を選択した場合、モンスターの攻撃成功率をリセット monster.attack_success_rate = 0.5 if action == 2 end # 勝敗判定 if player.hp > 0 puts "#{player.name}の勝利!" else puts "#{monster.name}の勝利!" end
********************
正解のコードの解説
このRubyコードでは、プレイヤーとモンスターが戦うターン制のバトルゲームを実装しています。
メタプログラミングを使って動的に攻撃力を設定する方法や、攻撃成功率の管理を行いながらゲームが進行する仕組みを解説します。
PlayerクラスとMonsterクラスの定義
class Player attr_accessor :name, :attack_power, :hp def initialize(name = "プレイヤー") @name = name @hp = 100 end def set_power(attack) self.attack_power = attack end end
Player
クラスはプレイヤーキャラクターを定義します。名前、攻撃力、HP(体力)を持ちます。
initialize
: プレイヤーを初期化します。@name
にはデフォルトで「プレイヤー」が設定され、@hp
は100です。attr_accessor
:name
(名前)、attack_power
(攻撃力)、hp
(体力)にアクセスできるようにします。set_power
: このメソッドはプレイヤーの攻撃力を動的に設定するために使います。メタプログラミングを活用して、後から攻撃力を自由に変更できるようにしています。
class Monster attr_accessor :name, :attack_power, :hp, :attack_success_rate def initialize(name = "モンスター") @name = name @hp = 100 @attack_success_rate = 0.5 end def set_power(attack) self.attack_power = attack end def update_success_rate(success) if success @attack_success_rate = 0.5 else @attack_success_rate += 0.2 end end end
Monster
クラスはモンスターキャラクターを定義します。Player
クラスと似た構造ですが、モンスターには追加で@attack_success_rate
(攻撃成功率)があります。
モンスターの攻撃成功率は0.5(50%)からスタートし、攻撃が失敗するたびに増加します。
ゲーム開始の設定
puts "ゲームを開始します。" player = Player.new monster = Monster.new player.set_power(25) monster.set_power(40)
ここではゲームの開始を告げ、プレイヤーとモンスターのインスタンスを作成します。
player.set_power(25)
: プレイヤーの攻撃力を25に設定しています。monster.set_power(40)
: モンスターの攻撃力は40に設定されています。
プレイヤーとモンスターの戦闘ロジック
while player.hp > 0 && monster.hp > 0
このループでは、プレイヤーとモンスターのHPがどちらも0より大きい間、戦闘が続行されます。以下の順番でプレイヤーとモンスターのターンが進行します。
プレイヤーのターン
puts "攻撃しますか?防御しますか? (1: 攻撃, 2: 防御): " action = gets.chomp.to_i
プレイヤーは「攻撃」または「防御」を選択します。入力が1なら攻撃、2なら防御が行われます。無効な選択をした場合、再度入力を求められます。
if action == 1 damage_to_monster = player.attack_power monster.hp -= damage_to_monster puts "#{player.name}の攻撃: #{damage_to_monster} ダメージ" puts "#{monster.name}のHP: #{monster.hp}" elsif action == 2 puts "#{player.name}は防御を選択しました。" end
- 攻撃の場合: プレイヤーの攻撃力(
player.attack_power
)に応じてモンスターにダメージを与え、その分モンスターのHPを減らします。 - 防御の場合: プレイヤーは防御を選択します。この後、モンスターの攻撃からダメージを守る役割を果たします。
モンスターのターン
if rand < monster.attack_success_rate
モンスターの攻撃が成功するかどうかは、rand
でランダムな値を生成し、monster.attack_success_rate
(攻撃成功率)と比較することで決まります。
例えば、成功率が50%(0.5)なら、rand
が0.5未満であれば攻撃が成功します。
if action == 2 puts "#{player.name}は防御に成功し、ダメージを受けませんでした。" else player.hp -= damage_to_player puts "#{monster.name}の攻撃: #{damage_to_player} ダメージ" puts "#{player.name}のHP: #{player.hp}" end
- 防御成功: プレイヤーが防御を選択している場合、モンスターの攻撃は失敗し、ダメージを受けません。
- 攻撃成功: 防御をしていない場合は、モンスターが攻撃を成功させ、プレイヤーのHPにダメージが加えられます。
monster.update_success_rate(true)
モンスターの攻撃が成功した場合、attack_success_rate
(攻撃成功率)はリセットされ、次回の攻撃も50%の確率で成功します。失敗した場合、成功率が0.2増加します。
勝敗の判定
if player.hp > 0 puts "#{player.name}の勝利!" else puts "#{monster.name}の勝利!" end
戦闘終了後、プレイヤーかモンスターのどちらかのHPが0以下になった時点で、勝者が決まります。
プレイヤーが勝てばその旨が表示され、逆の場合はモンスターの勝利が表示されます。
まとめ
このコードを通じて、Rubyでのクラス定義、メタプログラミングによる動的なメソッド操作、条件分岐、ランダムな処理など、基本的なプログラミング技術を学ぶことができます。
ゲームを通して、コードがどのように動作しているか理解を深めることができます。
<<前の問題 |
問題集Top |
次の問題>> |
この問題への質問・コメント
この問題を作成するにあたりAIを活用しています。
問題ないことは確認していますが、もし間違いや表現の違和感などありましたら、ご指摘頂けると大変助かります。