この記事の練習問題で使用する知識:
基礎文法、制御構造、(レッスン1~3)、メソッドの定義と呼出し、デフォルト引数とキーワード引数、クラスの定義と使用、イニシャライザ、アクセスメソッド、クラスの継承
Rubyのゲームコード一覧はこちら
<<前のページ | Ruby記事一覧 |
次のページ>> |
確認問題:モンスターとのバトルゲームを作ろう
この問題では簡単なターン制バトルゲームを作成します。
このプログラムではプレイヤーとモンスターが交互に攻撃を行い、どちらかのHPが0になるまで戦闘が続きます。
プレイヤーは攻撃するか防御するかを選べます。モンスターはランダムな攻撃成功率を持っており、攻撃が成功した場合、プレイヤーのHPが減少します。またモンスターの攻撃成功率は、成功または失敗によって変化します。
この問題の要件
以下の要件に従ったプログラムを作成すること。
Character
クラスを作成し、名前、HP、攻撃力を保持できるようにすること。- このクラスには攻撃力を動的に設定するメソッド
set_power
を追加すること。
- このクラスには攻撃力を動的に設定するメソッド
Player
クラスを作成し、Character
クラスを継承すること。- 名前の初期値は
"プレイヤー"
とする。
- 名前の初期値は
Monster
クラスを作成し、Character
クラスを継承すること。- 攻撃成功率(
attack_success_rate
)を持つプロパティを追加し、初期値を0.5
に設定する。 - 成功率を更新するメソッド
update_success_rate
を実装し、失敗時は成功率を+0.2
増加(最大1.0まで)させること。
- 攻撃成功率(
- ターン制の戦闘を実装すること。
- プレイヤーは攻撃か防御を選択できる。
- 防御を選択した場合、次のモンスターの攻撃成功率はリセットされる。
- モンスターの攻撃が成功した場合、プレイヤーのHPを減らす。
- いずれかのHPが0になった場合、勝者を表示して終了する。
ただし、以下のような実行結果となること。
----- ↓出力される結果の例↓ -----
ゲームを開始します。 次のモンスターの攻撃の成功率は 50% です。 攻撃しますか?防御しますか? (1: 攻撃, 2: 防御): 1 プレイヤーの攻撃: 25 ダメージ モンスターのHP: 75 モンスターの攻撃: 40 ダメージ プレイヤーのHP: 60 次のモンスターの攻撃の成功率は 50% です。 ... プレイヤーの勝利!
この問題を解くヒント
1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。
正解のコードは以下のような構成となっています。
1:Characterクラスの定義
□ name, attack_power, hpのアクセサメソッドを定義
□ initializeメソッドでnameとhpを初期化(hpはデフォルト値100)
□ set_powerメソッドでattack_powerを設定
2:Playerクラスの定義
□ Characterクラスを継承
□ initializeメソッドでデフォルトnameを”プレイヤー”に設定
3:Monsterクラスの定義
□ Characterクラスを継承
□ attack_success_rateのアクセサメソッドを定義
□ initializeメソッドでnameとsuccess_rateを初期化(success_rateはデフォルト値0.5)
□ update_success_rateメソッドで攻撃成功率を更新
4:ゲーム開始のメッセージを出力
5:Playerクラスのインスタンスplayerを生成
6:Monsterクラスのインスタンスmonsterを生成
7:playerとmonsterの攻撃力を設定
8:whileループ開始(player.hp > 0 && monster.hp > 0の条件下)
□ monsterの次の攻撃成功率を出力
□ プレイヤーに行動を選択させる(攻撃または防御)
□ if文でactionが1(攻撃)の場合の処理
□ □ monsterのhpをplayer.attack_power分減らす
□ □ 攻撃内容とmonsterの現在hpを出力
□ if文でactionが2(防御)の場合の処理
□ □ 防御を選択したメッセージを出力
□ else文(無効な選択肢の場合)
□ □ 再選択を促すメッセージを出力し、次のループへ
□ if文でmonster.hp <= 0ならループ終了
□ randとmonster.attack_success_rateを比較しモンスターの攻撃を判定
□ □ 攻撃が成功した場合
□ □ □ if文でactionが2(防御)ならダメージを受けないメッセージを出力
□ □ □ else文でplayerのhpをmonster.attack_power分減らす
□ □ □ 攻撃内容とplayerの現在hpを出力
□ □ □ update_success_rateメソッドで攻撃成功率を更新
□ □ 攻撃が失敗した場合
□ □ □ 攻撃失敗メッセージを出力
□ □ □ update_success_rateメソッドで攻撃成功率を更新
□ if文でactionが2(防御)ならmonster.attack_success_rateを0.5にリセット
9:whileループ終了
10:if文でplayer.hp > 0なら勝利メッセージを出力
11:else文で敗北メッセージを出力
以下のコードをコピーし、コメントに従ってコードを完成させてください。
# 共通のCharacterクラスを定義 class Character attr_accessor :name, :attack_power, :hp def initialize(name, hp = 100) @name = name @hp = hp end # メタプログラミングを使って動的に攻撃力を設定 =begin 【穴埋め問題1】 ここに攻撃力を設定するためのメソッド set_power を定義し、引数 attack を受け取りそれを @attack_power に代入するコードを書いてください。 =end end # Playerクラス =begin 【穴埋め問題2】 ここでCharacterクラスを継承したPlayerクラスを作成し、initializeメソッドを定義してください。nameのデフォルト値を"プレイヤー"に設定してください。 =end # Monsterクラス class Monster < Character attr_accessor :attack_success_rate def initialize(name = "モンスター", success_rate = 0.5) super(name) @attack_success_rate = success_rate end # 攻撃成功率を更新 =begin 【穴埋め問題3】 ここにモンスターの攻撃成功率を更新するためのメソッド update_success_rate を定義してください。 - 引数 success を受け取ります。 - success が true の場合、成功率を 0.5 に設定してください。 - 失敗した場合は、成功率を現在の成功率に 0.2 を加算した値(最大値 1.0)に設定してください。 =end end # ゲームを開始 puts "ゲームを開始します。" =begin 【穴埋め問題4】 ここでPlayerクラスのインスタンス player と Monsterクラスのインスタンス monster を生成してください。 =end # プレイヤーとモンスターの攻撃力を設定 =begin 【穴埋め問題5】 ここでplayerとmonsterのそれぞれに対して、set_powerメソッドを呼び出し攻撃力を設定してください。 - player の攻撃力は 25 - monster の攻撃力は 40 =end # ターン制の戦闘 while player.hp > 0 && monster.hp > 0 # モンスターの次の攻撃の成功率を表示 puts "次のモンスターの攻撃の成功率は #{(monster.attack_success_rate * 100).round}% です。" # プレイヤーのターン =begin 【穴埋め問題6】 ここでプレイヤーに攻撃(1)か防御(2)を選択させ、その結果に応じて以下を実行してください: - 攻撃(1)の場合は monster の HP を player.attack_power 分減少させる - 防御(2)の場合は「防御を選択しました」と表示する =end break if monster.hp <= 0 # モンスターのターン =begin 【穴埋め問題7】 ここでモンスターがランダムな成功率に基づいて攻撃を行い、プレイヤーのHPを減らすかを処理してください。 - 成功の場合、プレイヤーの HP を monster.attack_power 分減少させる(ただし、防御中はノーダメージ) - 成功または失敗に応じて、update_success_rate を適切に呼び出す =end end # 勝敗判定 =begin 【穴埋め問題8】 ここでプレイヤーとモンスターのHPを比較し、勝利メッセージまたは敗北メッセージを表示してください。 =end
モンスターとのバトルゲームの正解コードと解説
この問題の一つの正解例とそのコードの解説を以下に示します。
正解コードの例
例えば以下のようなプログラムが考えられます。
# 共通のCharacterクラスを定義 class Character attr_accessor :name, :attack_power, :hp def initialize(name, hp = 100) @name = name @hp = hp end # メタプログラミングを使って動的に攻撃力を設定 def set_power(attack) self.attack_power = attack end end # Playerクラス class Player < Character def initialize(name = "プレイヤー") super(name) end end # Monsterクラス class Monster < Character attr_accessor :attack_success_rate def initialize(name = "モンスター", success_rate = 0.5) super(name) @attack_success_rate = success_rate end # 攻撃成功率を更新 def update_success_rate(success) @attack_success_rate = success ? 0.5 : [@attack_success_rate + 0.2, 1.0].min 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
正解のコードの解説
今回解説するのは簡単なターン制バトルゲームのコードです。
このコードは「プレイヤー」と「モンスター」が交互に攻撃し、どちらかのHPが0になるまで戦闘を行う仕組みを実装しています。
それでは、各部分について詳しく解説します。
Characterクラスの定義
class Character attr_accessor :name, :attack_power, :hp def initialize(name, hp = 100) @name = name @hp = hp end def set_power(attack) self.attack_power = attack end end
attr_accessor
:name
、attack_power
、hp
という属性を定義し、それらに読み書き可能なメソッドを自動生成します。initialize
メソッド: オブジェクトを生成する際に呼び出される特別なメソッドです。name
とhp
を初期化します。hp
にはデフォルト値100が設定されています。set_power
メソッド: 攻撃力を設定するためのメソッドで、self.attack_power
を使って動的に値を設定します。
Playerクラスの定義
class Player < Character def initialize(name = "プレイヤー") super(name) end end
< Character
:Player
クラスはCharacter
クラスを継承しており、すべての機能を引き継ぎます。super
: 親クラス(Character
クラス)のinitialize
メソッドを呼び出します。デフォルトの名前を"プレイヤー"
としています。
Monsterクラスの定義
class Monster < Character attr_accessor :attack_success_rate def initialize(name = "モンスター", success_rate = 0.5) super(name) @attack_success_rate = success_rate end def update_success_rate(success) @attack_success_rate = success ? 0.5 : [@attack_success_rate + 0.2, 1.0].min end end
attr_accessor
: 攻撃成功率(attack_success_rate
)を追加。initialize
メソッド: モンスターの名前と攻撃成功率を初期化します。成功率はデフォルトで0.5
です。update_success_rate
メソッド: 攻撃が成功した場合は成功率をリセット(0.5
)、失敗した場合は最大値1.0
まで増加させます。
ゲームの開始
player = Player.new monster = Monster.new player.set_power(25) monster.set_power(40)
Player.new
とMonster.new
: プレイヤーとモンスターのインスタンスを作成します。set_power
: 攻撃力をそれぞれ設定します。
ターン制バトルの実装
while player.hp > 0 && monster.hp > 0 # モンスターの攻撃成功率を表示 puts "次のモンスターの攻撃の成功率は #{(monster.attack_success_rate * 100).round}% です。" # プレイヤーのターン action = gets.chomp.to_i if action == 1 damage_to_monster = player.attack_power monster.hp -= damage_to_monster elsif action == 2 # 防御時の処理 end break if monster.hp <= 0 # モンスターのターン if rand < monster.attack_success_rate # 成功時の処理 else # 失敗時の処理 end end
while
ループ: プレイヤーとモンスターのHPが両方とも正の値である間、戦闘を続けます。- プレイヤーの行動選択:
- 攻撃 (1): モンスターにダメージを与えます。
- 防御 (2): モンスターの攻撃成功率をリセットします。
- モンスターの攻撃:
rand < attack_success_rate
: 攻撃が成功するかランダムで判定します。- 攻撃が失敗した場合、成功率を増加させます。
勝敗の判定
if player.hp > 0 puts "#{player.name}の勝利!" else puts "#{monster.name}の勝利!" end
条件分岐: プレイヤーのHPが0より大きければ勝利、そうでなければモンスターの勝利とします。
まとめ
このコードは、Rubyのオブジェクト指向プログラミングを学ぶのに最適なコードです。
クラスの継承や動的プロパティの設定、そしてランダム処理を組み合わせたゲームロジックを実装しています。
このプログラムを通じて、プログラム構造の設計やクラス間の関係性を理解する第一歩を踏み出しましょう。
Rubyのゲームコード一覧はこちら
<<前のページ |
Ruby記事一覧 |
次のページ>> |
この記事への質問・コメント
この記事を作成するにあたりAIを活用しています。
問題ないことは確認していますが、もし間違いや表現の違和感などありましたら、ご指摘頂けると大変助かります。