【Python】レッスン5-☆2:モンスターとのバトルゲームを作ろう

記事内に商品プロモーションを含む場合があります

この記事の練習問題で使用する知識:
1.基礎文法、2.制御構造、3.関数とスコープ、4.データ構造、5.オブジェクト指向

Pythonのゲームコード一覧はこちら

<<前のページ Python記事一覧
次のページ>>

練習問題5-☆1:モンスターとのバトルゲームを作ろう

シンプルなターン制バトルゲームを作成しましょう。

このゲームでは「勇者」と「ドラゴン」というキャラクターが互いに攻撃や防御を行います。

勇者が攻撃を選択した場合、ドラゴンのHPが減少し、防御を選択した場合、ドラゴンの次の攻撃を防ぐことができます。

ドラゴンは一定の確率で攻撃を成功させることができ、攻撃が失敗するたびに次の攻撃の成功率が上がります。

勇者のHPが0になった場合はゲームオーバー、ドラゴンのHPが0になった場合はプレイヤーの勝利です。

問題の詳細条件

以下の要件に従ってコードを完成させてください。

  1. クラスの定義:
    • キャラクター情報を保持する Character クラスを定義する。
    • Character クラスは、名前 (name)、HP (hp)、攻撃力 (attack_power) を属性として持ち、キャラクターが生存しているかどうかを判定する is_alive メソッドを持つ。
  2. ゲームの初期設定:
    • 勇者として name="勇者", hp=100, attack_power=20 のキャラクターを定義する。
    • ドラゴンとして name="ドラゴン", hp=100, attack_power=40 のキャラクターを定義する。
    • ドラゴンの攻撃成功率を示す変数 monster_attack_chance を初期値60で設定する。
  3. ゲームのメインループ:
    • 勇者とドラゴンが生存している間、以下の処理を繰り返す。
    • 勇者のHP、ドラゴンのHP、およびドラゴンの攻撃成功率を表示する。
    • 勇者が「攻撃」を選択した場合、ドラゴンのHPから勇者の攻撃力分を減算する。
    • 勇者が「防御」を選択した場合、次のドラゴンの攻撃を防ぐための defend フラグを設定する。
  4. ドラゴンのターン:
    • ドラゴンが生存している場合、ランダムな値に基づいて攻撃が成功するか判定する。
    • 勇者が「防御」を選択している場合、攻撃は失敗し、次のターンの攻撃成功率を60にリセットする。
    • 勇者が防御していない場合、攻撃が成功すると勇者のHPからドラゴンの攻撃力分を減算する。
    • ドラゴンの攻撃が失敗するたびに、攻撃成功率を20ずつ増加させる。
  5. 勝敗の判定:
    • メインループを抜けた後、勇者が生存していれば「勇者の勝利」、ドラゴンが生存していれば「ドラゴンの勝利」と表示する。

ただし、以下のような実行結果となるコードを書くこと。

*****↓↓正解コードの実行結果の例↓↓*****

勇者のHP: 100, ドラゴンのHP: 100, ドラゴンの攻撃成功率: 60%
攻撃するか防御するかを選んでください (1: 攻撃, 2: 防御): 1
勇者の攻撃!
ドラゴンに20のダメージ!

ドラゴンのHP: 80, ドラゴンの攻撃!
攻撃が成功!
勇者に40のダメージ!

勇者のHP: 60, ドラゴンのHP: 80, ドラゴンの攻撃成功率: 60%
攻撃するか防御するかを選んでください (1: 攻撃, 2: 防御): 2
勇者は防御を選択した!
ドラゴンの攻撃!
攻撃がミス!防御が成功しました!

【ヒント】難しいと感じる人だけ見よう

1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。

ヒント1【コードの構成を見る】

正解のコードは上から順に以下のような構成となっています。
(※下記の□はコード内のインデントを表しています)

1:Randomモジュールのインポート
2:Characterクラスの定義
  □ __init__メソッドの定義
  □ □ インスタンス変数nameにnameを代入
  □ □ インスタンス変数hpにhpを代入
  □ □ インスタンス変数attack_powerにattack_powerを代入
  □ is_aliveメソッドの定義
  □ □ 戻り値としてhpが0より大きいかを返す
3:playerにCharacterインスタンス(”勇者”, 100, 20)を代入
4:monsterにCharacterインスタンス(”ドラゴン”, 100, 40)を代入
5:monster_attack_chanceに60を代入

6:while文によるループ開始
  □ playerとmonsterの両方がis_aliveメソッドで生存しているか判定
  □ f文字列を使い、勇者のHP、ドラゴンのHP、ドラゴンの攻撃成功率を出力
  □ input関数を使い、ユーザーに「攻撃するか防御するかを選んでください」と入力を求め、actionに代入
  □ if文にてactionが”1″か判定
  □ □ 真の場合、「勇者の攻撃!」と出力
  □ □ monster.hpからplayer.attack_powerを減算
  □ □ f文字列を使い、ドラゴンに与えたダメージを出力
  □ elif文にてactionが”2″か判定
  □ □ 真の場合、「勇者は防御を選択した!」と出力
  □ □ defendをTrueに設定
  □ else文
  □ □ 「無効な入力です。もう一度入力してください。」と出力
  □ □ continueにより次のループへ戻る

7:if文でmonsterがis_aliveメソッドで生存しているか判定
  □ attack_rollに1から100のランダムな整数を代入
  □ if文にてattack_rollがmonster_attack_chance以下か判定
  □ □ 真の場合かつlocals()内にdefendがあり、defendがTrueか判定
  □ □ □ 「ドラゴンの攻撃!」と出力
  □ □ □ 「攻撃がミス!防御が成功しました!」と出力
  □ □ □ defendを削除
  □ □ □ monster_attack_chanceを60にリセット
  □ □ else文
  □ □ □ 「ドラゴンの攻撃!」と出力
  □ □ □ 「攻撃が成功!」と出力
  □ □ □ player.hpからmonster.attack_powerを減算
  □ □ □ f文字列を使い、勇者に与えたダメージを出力
  □ □ □ monster_attack_chanceを60にリセット
  □ else文
  □ □ 「ドラゴンの攻撃!」と出力
  □ □ 「攻撃がミス!」と出力
  □ □ monster_attack_chanceに20を加算

8:if文にてplayerがis_aliveメソッドで生存しているか判定
  □ 真の場合、「ドラゴンを倒した!勇者の勝利!」と出力
  □ 偽の場合、「勇者は倒された…ドラゴンの勝利!」と出力

ヒント2【穴埋め問題にする】

以下のコードをコピーし、コメントに従ってコードを完成させて下さい。

import random

# プレイヤーとモンスターのクラス定義
class Character:
    """【穴埋め問題1】
    ここにクラスの初期化メソッドを定義し、name、hp、attack_powerを属性として設定するコードを書いてください。
    """

    def is_alive(self):
        """【穴埋め問題2】
        ここにキャラクターが生存しているかどうかを判定するコードを書いてください。
        """

# ゲームの初期設定
"""【穴埋め問題3】
ここで「勇者」と「ドラゴン」という名前のキャラクターを作成し、それぞれに初期HPと攻撃力を設定するコードを書いてください。
また、monster_attack_chanceという変数を初期値60で設定してください。
"""

# ゲームのメインループ
while player.is_alive() and monster.is_alive():
    # 現在のステータスを表示
    print(f"\n勇者のHP: {player.hp}, ドラゴンのHP: {monster.hp}, ドラゴンの攻撃成功率: {monster_attack_chance}%")
    action = input("攻撃するか防御するかを選んでください (1: 攻撃, 2: 防御): ")

    # プレイヤーのターン
    if action == "1":
        """【穴埋め問題4】
        ここに勇者の攻撃を実行し、ドラゴンのHPを減らすコードを書いてください。
        """
    elif action == "2":
        """【穴埋め問題5】
        ここに勇者が防御を選択した際のフラグを設定するコードを書いてください。
        """
    else:
        print("無効な入力です。もう一度入力してください。")
        continue

    # モンスターのターン
    if monster.is_alive():
        attack_roll = random.randint(1, 100)
        if attack_roll <= monster_attack_chance:
            if 'defend' in locals() and defend:
                """【穴埋め問題6】
                ここにドラゴンの攻撃を防ぐコードを書いてください。
                成功した際には攻撃成功率をリセットするコードも追加してください。
                """
            else:
                """【穴埋め問題7】
                ここにドラゴンの攻撃が成功した場合のコードを書いてください。
                勇者のHPからドラゴンの攻撃力を減算し、攻撃成功率をリセットするコードも追加してください。
                """
        else:
            print("ドラゴンの攻撃!")
            print("攻撃がミス!")
            monster_attack_chance += 20  # 攻撃成功率を上昇

# 勝敗の判定
if player.is_alive():
    print("\nドラゴンを倒した!勇者の勝利!")
else:
    print("\n勇者は倒された…ドラゴンの勝利!")

この問題の穴埋めコードは以上です。

このヒントを見てもまだ回答を導き出すのが難しいと感じる場合は、先に正解のコードと解説を見て内容を理解するようにしましょう。

問題の答え合わせと解説

この問題の一つの正解例とそのコードの解説を以下に示します。

一つの正解例

例えば以下のようなプログラムが考えられます。

import random

# プレイヤーとモンスターのクラス定義
class Character:
    def __init__(self, name, hp, attack_power):
        self.name = name
        self.hp = hp
        self.attack_power = attack_power

    def is_alive(self):
        return self.hp > 0

# ゲームの初期設定
player = Character("勇者", 100, 20)
monster = Character("ドラゴン", 100, 40)
monster_attack_chance = 60  # 初期の攻撃成功率

# ゲームのメインループ
while player.is_alive() and monster.is_alive():
    # 現在のステータスを表示
    print(f"\n勇者のHP: {player.hp}, ドラゴンのHP: {monster.hp}, ドラゴンの攻撃成功率: {monster_attack_chance}%")
    action = input("攻撃するか防御するかを選んでください (1: 攻撃, 2: 防御): ")

    # プレイヤーのターン
    if action == "1":
        print("勇者の攻撃!")
        monster.hp -= player.attack_power
        print(f"ドラゴンに{player.attack_power}のダメージ!")
    elif action == "2":
        print("勇者は防御を選択した!")
        defend = True
    else:
        print("無効な入力です。もう一度入力してください。")
        continue

    # モンスターのターン
    if monster.is_alive():
        attack_roll = random.randint(1, 100)
        if attack_roll <= monster_attack_chance:
            if 'defend' in locals() and defend:
                print("ドラゴンの攻撃!")
                print("攻撃がミス!防御が成功しました!")
                del defend
                monster_attack_chance = 60  # 攻撃成功率をリセット
            else:
                print("ドラゴンの攻撃!")
                print("攻撃が成功!")
                player.hp -= monster.attack_power
                print(f"勇者に{monster.attack_power}のダメージ!")
                monster_attack_chance = 60  # 攻撃成功率をリセット
        else:
            print("ドラゴンの攻撃!")
            print("攻撃がミス!")
            monster_attack_chance += 20  # 攻撃成功率を上昇

# 勝敗の判定
if player.is_alive():
    print("\nドラゴンを倒した!勇者の勝利!")
else:
    print("\n勇者は倒された…ドラゴンの勝利!")

正解例の詳細解説

このコードはPythonで作成されたシンプルなターン制バトルゲームです。

勇者とドラゴンが交互に攻撃や防御を行い、どちらかのHPが0になるまで戦います。

各部分に使われている文法を解説します。

ランダムモジュールのインポート

import random

まず最初にPythonのrandomモジュールをインポートします。

このモジュールを使うことで、ゲームの中でランダムな数値を生成し、モンスターの攻撃成功率をランダムに決定できます。

クラスの定義と初期化

class Character:
    def __init__(self, name, hp, attack_power):
        self.name = name
        self.hp = hp
        self.attack_power = attack_power

    def is_alive(self):
        return self.hp > 0

Characterというクラスを定義しています。

このクラスにはキャラクターの名前 (name)、HP (体力、hp)、攻撃力 (attack_power) の属性を設定し、is_aliveメソッドでキャラクターが生きているかどうかを判定します。

  • __init__ メソッドはコンストラクタと呼ばれ、クラスからオブジェクトを作成したときに呼ばれます。
  • is_alive メソッドでは、self.hp > 0の条件を使ってHPが0より大きいかを確認し、生存しているかどうかを返します。

初期設定

player = Character("勇者", 100, 20)
monster = Character("ドラゴン", 100, 40)
monster_attack_chance = 60  # 初期の攻撃成功率

playermonsterというキャラクターを作成し、それぞれ「勇者」と「ドラゴン」という名前、HP、攻撃力を設定します。

またmonster_attack_chanceはドラゴンの攻撃が成功する確率で、初期値として60を設定しています。

ゲームのメインループ

while player.is_alive() and monster.is_alive():
    # 現在のステータスを表示
    print(f"\n勇者のHP: {player.hp}, ドラゴンのHP: {monster.hp}, ドラゴンの攻撃成功率: {monster_attack_chance}%")
    action = input("攻撃するか防御するかを選んでください (1: 攻撃, 2: 防御): ")

whileループはplayermonsterが両方とも生きている (is_alive) 間繰り返されます。

各ターンで、勇者のHP、ドラゴンのHP、そしてドラゴンの攻撃成功率が表示され、ユーザーに「攻撃」か「防御」を選択させます。

プレイヤーのターン

if action == "1":
    print("勇者の攻撃!")
    monster.hp -= player.attack_power
    print(f"ドラゴンに{player.attack_power}のダメージ!")
elif action == "2":
    print("勇者は防御を選択した!")
    defend = True
else:
    print("無効な入力です。もう一度入力してください。")
    continue
  • 「攻撃」を選択すると、ドラゴンのHPから勇者の攻撃力 (attack_power) 分のダメージが引かれます。
  • 「防御」を選択すると、defend というフラグを True に設定し、次のドラゴンの攻撃を防げるようにします。
  • 無効な入力があった場合には「無効な入力です」と表示され、ターンが再実行されます。

モンスターのターン

if monster.is_alive():
    attack_roll = random.randint(1, 100)
    if attack_roll <= monster_attack_chance:
        if 'defend' in locals() and defend:
            print("ドラゴンの攻撃!")
            print("攻撃がミス!防御が成功しました!")
            del defend
            monster_attack_chance = 60
        else:
            print("ドラゴンの攻撃!")
            print("攻撃が成功!")
            player.hp -= monster.attack_power
            print(f"勇者に{monster.attack_power}のダメージ!")
            monster_attack_chance = 60
    else:
        print("ドラゴンの攻撃!")
        print("攻撃がミス!")
        monster_attack_chance += 20

ドラゴンが生存している間、ランダムな数値 (attack_roll) に基づいて攻撃が成功するか判定します。

  • defendフラグが立っているときには、防御が成功して攻撃はミスになり、defendフラグが解除されます。
  • 攻撃が成功した場合には、勇者のHPがドラゴンの攻撃力分減少します。
  • もし攻撃が失敗した場合、次の攻撃成功率が20%増加します。

勝敗の判定

if player.is_alive():
    print("\nドラゴンを倒した!勇者の勝利!")
else:
    print("\n勇者は倒された…ドラゴンの勝利!")

whileループを抜けた後、どちらかのHPが0になったことを確認し、勇者が勝利したかドラゴンが勝利したかを表示します。

まとめ

このコードではPythonのクラスの使い方やif文による条件分岐、whileループの基本、そしてrandomモジュールの使用方法を学ぶことができます。

自分でコードを変更して、キャラクターの能力やゲームルールをカスタマイズしてみましょう。

例えば今回作成したCharacterクラスを利用して、強さの違う別のモンスターを追加して連続で戦えるようにするなどがおすすめです。

ゲームの流れを理解しながら進めることで、プログラミングのスキルが身についていきます。

Pythonのゲームコード一覧はこちら

<<前のページ Python記事一覧
次のページ>>

質問用コンタクトフォーム

この記事はAIを用いて書いた記事です。

人間の目による確認も行っていますが、もし間違い等ありましたらご指摘頂けると大変助かります。






    Python記事一覧へ戻る
    トップページへ戻る