🚀 ニフティ’s Notion

演習II

概要

演習Ⅱではオブジェクト指向のクラス・継承・コンポジションを使って簡単なCLIのコマンドバトルを作成します。

ソースコード
import random


class Charactor:
    def __init__(self, name, hp, atk):
        self.name = name
        self.hp = hp
        self.atk = atk

    def act_attack(self):
        print(f"{self.name}の攻撃")
        damage = self.atk
        return damage

    def cal_damage(self, damage):
        self.hp -= damage
        if damage > 0:
            print(f"{self.name}{damage}のダメージ")
        elif damage < 0:
            print(f"{self.name}{-1*damage}回復した")
        elif damage == 0:
            pass
        if self.hp <= 0:
            self.hp = 0
            print(f"{self.name}はたおれた")


enemy =
player1 =
player2 =
party = [player1, player2]

# ▲ 演習ではここより上部にコードを記述していきます
# ----------------------------------------------------------------------------

enemy.start_serif()
Game = True
while Game:
    print("------------------------------------------------")
    print(enemy.name, " hp:", enemy.hp)
    print("------------------------------------------------")
    print("\n")
    print("------------------------------------------------")
    for n in range(len(party)):
        print("■", party[n].name, " HP:", party[n].hp, " ATK:", party[n].atk)
    print("------------------------------------------------")

    # プレイヤーの行動
    for m in range(len(party)):
        if party[m].hp > 0:
            party[m].command()
            print("------------------------------------------------")
            input_command = input()
            if input_command == '1':
                target = enemy
                target.cal_damage(party[m].act_attack())
            elif input_command == '2':
                target = party[m]
                target.cal_damage(party[m].act_use_item())
            elif input_command == '3':
                target = enemy
                target.cal_damage(party[m].act_special())
            else:
                print("無効なコマンドです")
            print("\n")

    # エネミーの行動
    if enemy.hp <= 0:
        print("たたかいにしょうりした")
        Game = False
        break
    target = party[random.randint(0, len(party)-1)]
    target.cal_damage(enemy.act_attack())
    death_count = 0
    for k in range(len(party)):
        if party[k].hp == 0:
            death_count += 1
    if death_count == len(party):
        print("たたかいにやぶれた")
        Game = False
        break

演習Ⅱ- 1
  • コマンドバトルでは敵キャラクターと味方キャラクターの存在が必要不可欠です。
  • まずはこれらのキャラクターを実装します。
    • 既にバトルに必要不可欠な、「キャラクターの属性 [名前(name), ヒットポイント(hp), こうげきりょく(atk)]」「攻撃の処理 [act_attack()]」や「ダメージの処理 [cal_damage()]」は用意しました。
    • しかし、敵キャラクターと味方キャラクターではバトル中の行動が異なりますので、Charactorクラスをそのまま使うのは面倒になりそうな気がします。ということで、Charactorクラスを継承した新しいクラス「enemyクラス」と「playerクラス」を作成してみましょう。
  • 各クラスに必要な属性とメソッドは以下の通りです。
    image block
【コマンドを表示する処理】の例
    def command(self):
        print(f"{self.name} 1: こうげき  2: どうぐ  3: ひっさつ")

EnemyクラスとPlayerクラスが実装出来たら enemyとplayer1とplayer2のインスタンスを作成し、実行してみてください。

解答例
import random


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

    def act_attack(self):
        print(f"{self.name}の攻撃")
        damage = self.atk
        return damage

    def cal_damage(self, damage):
        self.hp -= damage
        if damage > 0:
            print(f"{self.name}{damage}のダメージ")
        elif damage < 0:
            print(f"{self.name}{-1*damage}回復した")
        elif damage == 0:
            pass
        if self.hp <= 0:
            self.hp = 0
            print(f"{self.name}はたおれた")


class Enemy(Character):
    def start_serif(self):
        print(f"{self.name}「かってもまけてもせかいのぜんぶをくれてやろう」")


class Player(Character):
    def command(self):
        print(f"{self.name} 1: こうげき  2: どうぐ  3: ひっさつ")

    def act_use_item(self):
        return 0

    def act_special(self):
        return 0


enemy = Enemy(name="大魔王かとう", hp=225, atk=25)
player1 = Player(name="勇者", hp=130, atk=16)
player2 = Player(name="魔女", hp=100, atk=11)
party = [player1, player2]

# ▲ 演習ではここより上部にコードを記述していきます
# ----------------------------------------------------------------------------

Game = True
while Game:
    print("------------------------------------------------")
    print(enemy.name, " hp:", enemy.hp)
    print("------------------------------------------------")
    print("\n")
    print("------------------------------------------------")
    for n in range(len(party)):
        print("■", party[n].name, " HP:", party[n].hp, " ATK:", party[n].atk)
    print("------------------------------------------------")

    # プレイヤーの行動
    for m in range(len(party)):
        if party[m].hp > 0:
            party[m].command()
            print("------------------------------------------------")
            input_command = input()
            if input_command == "1":
                target = enemy
                target.cal_damage(party[m].act_attack())
            elif input_command == "2":
                target = party[m]
                target.cal_damage(party[m].act_use_item())
            elif input_command == "3":
                target = enemy
                target.cal_damage(party[m].act_special())
            else:
                print("無効なコマンドです")
            print("\n")

    # エネミーの行動
    if enemy.hp <= 0:
        print("たたかいにしょうりした")
        Game = False
        break
    target = party[random.randint(0, len(party) - 1)]
    target.cal_damage(enemy.act_attack())
    death_count = 0
    for k in range(len(party)):
        if party[k].hp == 0:
            death_count += 1
    if death_count == len(party):
        print("たたかいにやぶれた")
        Game = False
        break
演習Ⅱ-2

プレイヤーキャラクターにはコマンドで"2"を選択した時、道具「ポーション」を使えるようにしたいと思います。

「プレイヤーキャラクター」と「ポーション」の関係を考え、「ポーション」のクラスを作成してコマンドで"2"を選択した時にプレイヤーキャラクターが回復できるようにしてみましょう。

image block
【Potionのuseメソッド】の例
     def use(self):
        if self.num > 0:
            self.num -= 1
            damage = -30
        else:
            print("道具をもう持っていない")
            damage = 0
        return damage
解答例
import random


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

    def act_attack(self):
        print(f"{self.name}の攻撃")
        damage = self.atk
        return damage

    def cal_damage(self, damage):
        self.hp -= damage
        if damage > 0:
            print(f"{self.name}{damage}のダメージ")
        elif damage < 0:
            print(f"{self.name}{-1*damage}回復した")
        elif damage == 0:
            pass
        if self.hp <= 0:
            self.hp = 0
            print(f"{self.name}はたおれた")


class Enemy(Character):
    def start_serif(self):
        print(f"{self.name}「かってもまけてもせかいのぜんぶをくれてやろう」")


class Player(Character):
    def __init__(self, name, hp, atk):
        super().__init__(name, hp, atk)
        self.item = Potion(3)

    def command(self):
        print(f"{self.name} 1: こうげき  2: どうぐ  3: ひっさつ")

    def act_use_item(self):
        return self.item.use()

    def act_special(self):
        return 0


class Potion:
    def __init__(self, num):
        self.num = num

    def use(self):
        if self.num > 0:
            self.num -= 1
            damage = -30
        else:
            print("道具をもう持っていない")
            damage = 0
        return damage


enemy = Enemy(name="大魔王かとう", hp=225, atk=25)
player1 = Player(name="勇者", hp=130, atk=16)
player2 = Player(name="魔女", hp=100, atk=11)
party = [player1, player2]

# ▲ 演習ではここより上部にコードを記述していきます
# ----------------------------------------------------------------------------

Game = True
while Game:
    print("------------------------------------------------")
    print(enemy.name, " hp:", enemy.hp)
    print("------------------------------------------------")
    print("\n")
    print("------------------------------------------------")
    for n in range(len(party)):
        print("■", party[n].name, " HP:", party[n].hp, " ATK:", party[n].atk)
    print("------------------------------------------------")

    # プレイヤーの行動
    for m in range(len(party)):
        if party[m].hp > 0:
            party[m].command()
            print("------------------------------------------------")
            input_command = input()
            if input_command == '1':
                target = enemy
                target.cal_damage(party[m].act_attack())
            elif input_command == '2':
                target = party[m]
                target.cal_damage(party[m].act_use_item())
            elif input_command == '3':
                target = enemy
                target.cal_damage(party[m].act_special())
            else:
                print("無効なコマンドです")
            print("\n")

    # エネミーの行動
    if enemy.hp <= 0:
        print("たたかいにしょうりした")
        Game = False
        break
    target = party[random.randint(0, len(party)-1)]
    target.cal_damage(enemy.act_attack())
    death_count = 0
    for k in range(len(party)):
        if party[k].hp == 0:
            death_count += 1
    if death_count == len(party):
        print("たたかいにやぶれた")
        Game = False
        break

演習Ⅱ-3

コマンドで「3: ひっさつ」コマンドを選択した時に発動するの必殺技をつくります。実装方法はいろいろあると思いますが、今回は各キャラクターのクラスに発動する必殺技を設定しようと思います。

現在、Playerクラスからキャラクター2人のインスタンスを作成していると思いますが、これでは2人とも同じ必殺技になってしまいます。そこで、プレイヤークラスを継承して新たなクラスを作成し、プレイヤーキャラクターによって違う必殺技が発動するようにしましょう。

新しいクラスが作成出来たら、先ほど説明したポリモーフィズムを思い出して必殺技の処理を書いていきましょう。下図ではプログラムの例を出していますが、returnがダメージ量となっていれば中身は何でもいいです。

image block
【act_special】の例
    def act_special(self):
        print(f"{self.name}のこんしんのいちげき")
        damage = int(self.atk * 2)
        return damage
    def act_special(self):
        print(f"{self.name}のまほうこうげき")
        damage = int((self.hp / 10) + self.atk)
        return damage

プログラムを実行してみて、「3:ひっさつ」のコマンドを選択した時にキャラクターによって違うものが発動すれば成功です。

解答例
import random


class Charactor:
    def __init__(self, name, hp, atk):
        self.name = name
        self.hp = hp
        self.atk = atk

    def act_attack(self):
        print(f"{self.name}の攻撃")
        damage = self.atk
        return damage

    def cal_damage(self, damage):
        self.hp -= damage
        if damage > 0:
            print(f"{self.name}{damage}のダメージ")
        elif damage < 0:
            print(f"{self.name}{-1*damage}回復した")
        elif damage == 0:
            pass
        if self.hp <= 0:
            self.hp = 0
            print(f"{self.name}はたおれた")


class Enemy(Charactor):
    def start_serif(self):
        print(f"{self.name}「かってもまけてもせかいのぜんぶをくれてやろう」")


class Player(Charactor):
    def __init__(self, name, hp, atk):
        super().__init__(name, hp, atk)
        self.item = Potion(3)

    def command(self):
        print(f"{self.name} 1: こうげき  2: どうぐ  3: ひっさつ")

    def act_use_item(self):
        return self.item.use()

    def act_special(self):
        return 0


class Brave(Player):
    def act_special(self):
        print(f"{self.name}のこんしんのいちげき")
        damage = int(self.atk * 2)
        return damage


class Witch(Player):
    def act_special(self):
        print(f"{self.name}のまほうこうげき")
        damage = int((self.hp / 10) + self.atk)
        return damage


class Potion:
    def __init__(self, num):
        self.num = num

    def use(self):
        if self.num > 0:
            self.num -= 1
            damage = -30
        else:
            print("道具をもう持っていない")
            damage = 0
        return damage


# ----------------------------------------------------------------------------
enemy = Enemy(name="大魔王かとう", hp=225, atk=25)

player1 = Brave(name="勇者", hp=130, atk=16)
player2 = Witch(name="魔女", hp=100, atk=11)
party = [player1, player2]
# ----------------------------------------------------------------------------


enemy.start_serif()

# ----------------------------------------------------------------------------
Game = True
while Game:
    print("------------------------------------------------")
    print(enemy.name, " hp:", enemy.hp)
    print("------------------------------------------------")
    print("\n")
    print("------------------------------------------------")
    for n in range(len(party)):
        print("■", party[n].name, " HP:", party[n].hp, " ATK:", party[n].atk)
    print("------------------------------------------------")

    # プレイヤーの行動
    for m in range(len(party)):
        if party[m].hp > 0:
            party[m].command()
            print("------------------------------------------------")
            input_command = input()
            if input_command == '1':
                target = enemy
                target.cal_damage(party[m].act_attack())
            elif input_command == '2':
                target = party[m]
                target.cal_damage(party[m].act_use_item())
            elif input_command == '3':
                target = enemy
                target.cal_damage(party[m].act_special())
            else:
                print("無効なコマンドです")
            print("\n")

    # エネミーの行動
    if enemy.hp <= 0:
        print("たたかいにしょうりした")
        Game = False
        break
    target = party[random.randint(0, len(party)-1)]
    target.cal_damage(enemy.act_attack())
    death_count = 0
    for k in range(len(party)):
        if party[k].hp == 0:
            death_count += 1
    if death_count == len(party):
        print("たたかいにやぶれた")
        Game = False
        break