前回作成したドラクエ1風のシミュレーターを改造して
ドラクエ2風のチーム戦が出来るようにしました。

解説動画はこちら



さて前回のプログラムを改造して行きましょう。

前回は1vs1だったので
複数vs複数に対応するように改造します。

前回の奴をそのまま使用するのと改造するもの
新規のものといろいろ出てきますが

まずは前回の流用。
キャラクタークラスはそのまま流用できますが
チーム戦になると生存フラグが必要になってきますので
フラグを追加します、1が生存0が死亡。

ダメージ計算や素早さ計算はそのまま流用します。
import numpy as np

# キャラクタークラス
class character():

    def __init__(self,name,hp,attack,defence,agility):
        self.name = name
        self.hp = hp
        self.attack = attack
        self.defence = defence
        self.agility = agility
        self.survive = 1

# ダメージ計算
def damage_calc(c1,c2):
    base = c1.attack //2 - c2.defence//4
    rand = base//16+1
    tmp = np.random.randint(0,rand*2+1)-rand
    damage = base + tmp
    return damage

# 素早さ計算
def agility_calc(c):
    base = c.agility
    tmp = base//10
    result = np.random.randint(base-tmp,base+tmp+1)
    return result

チーム戦を行うために、キャラを複数格納できる
チームクラスを作ります。
# チームクラス
class Team():

    def __init__(self,name,teams):
        self.name = name
        self.team = teams

    def append(self,chara):
        self.team.append(chara)
        
    def delete(self,index):
        del self.team[index]


前回は2キャラの対戦なのでチームでの複数対戦だと
行動の順番を決める必要があります。

行動順番は素早さを元に計算し
数値が大きい順に行動するようにします。

その際生存フラグが1のものだけにします。

# 先頭順序の計算
def turn_calc(t1,t2):
    result = {}
    for i,c in enumerate(t1.team):
        ag = agility_calc(c)
        if c.survive==1:
            result['{0}:{1}'.format(t1.name,i)] = ag
    for i,c in enumerate(t2.team):
        ag = agility_calc(c)
        if c.survive==1:
            result['{0}:{1}'.format(t2.name,i)] = ag
    return [k for k,v in sorted(result.items(),reverse=True,key=lambda x:x[1])]


戦闘順番が決まったらその順番通りに攻撃開始です。
相手チームの中で狙う相手を決めるために
相手チームの生存者を探してインデックス値で返します。

ターン中の攻撃は攻撃者からターゲットへの
一方的なやりとりだけにします。

お互いのステータスからダメージ計算し
相手のHPから引き、HPが0になったら倒れます。

# 狙う相手を計算
def target(teams):
    index = [i for i ,c in enumerate(teams.team) if c.survive==1]
    return np.random.choice(index)

# ターン中の攻撃
def attack(c1,c2):
    damage = damage_calc(c1,c2)
    c2.hp = c2.hp - damage if c2.hp - damage>=0 else 0
    print('{0}の攻撃 : {1}に{2}のダメージ'.format(c1.name,c2.name,damage))
    print('{0}のHP : {1}'.format(c2.name,c2.hp))
    if c2.hp<=0:
        print('{0}は力尽きた!!!'.format(c2.name))
        return (c2,0)
    return (c2,9)

チームの全員の生存フラグが0になったら試合終了です。
全員の生存フラグをチェックします。

ターンが終わったら全員のステータスを出すように
ログ出力します。

# 生存チェック
def check_survived(teams):
    res = 0
    for c in teams.team:
        if c.survive==1:
            res+=1
    if res > 0:
        return True
    else:
        return False

# ログ出力
def print_log(t1,t2):
    print()
    result = ''
    for c in t1.team + t2.team:
        result += '{0} , HP : {1}\t'.format(c.name , c.hp )
    print(result)
    print()

ここから戦闘中のアルゴリズムです。
順番を決めて
攻撃対象を決めて
ダメージ計算して
HP0なら生存フラグを0にして
全員生存フラグ0なら勝負ありです。

# 戦闘
def battle(t1,t2):
    print('戦闘開始')
    print_log(t1,t2)
    while True:
        # ターン内の処理
        for m in turn_calc(t1,t2):
            tm , i , flg= m.split(':')[0] , int(m.split(':')[1]),9
            # 攻撃チームの設定
            attack_team = t1 if t1.name==tm else t2
            # ターゲットチームとターゲットの指定
            target_team = t2 if t1.name==tm else t1
            t_num = target(target_team) 
            # 戦闘結果
            target_team.team[t_num],flg = attack(attack_team.team[i],target_team.team[t_num])
            if flg==0:
                target_team.team[t_num].survive=0
            if not check_survived(t1):
                print('\n{0}チームの勝ち'.format(t2.name))
                break
            elif  not check_survived(t2):
                print('\n{0}チームの勝ち'.format(t1.name))
                break
        
        # ターン後
        if not check_survived(t1) or not check_survived(t2): 
            break
        print_log(t1,t2)
    print('戦闘終了')


さて、シミュレーションしてみましょう。
c1 = character('勇者1',100,80,40,66)
c2 = character('勇者2',100,80,40,66)
c3 = character('勇者3',100,80,40,66)
c4 = character('勇者4',200,100,50,66)

s1 = character('スライム1',180,80,30,66)
s2 = character('スライム2',180,80,30,66)
s3 = character('スライム3',180,80,30,66)
s4 = character('スライム4',380,70,40,56)

team1 = Team('勇者チーム',[c1,c2,c3,c4])
team2 = Team('スライムチーム',[s1,s2,s3])

battle(team1,team2)

結果は

戦闘開始

勇者1 , HP : 100 勇者2 , HP : 100 勇者3 , HP : 100 勇者4 , HP : 200
スライム1 , HP : 180 スライム2 , HP : 180 スライム3 , HP : 180

勇者1の攻撃 : スライム2に36のダメージ
スライム2のHP : 144
勇者2の攻撃 : スライム3に34のダメージ
スライム3のHP : 146
スライム3の攻撃 : 勇者3に29のダメージ
勇者3のHP : 71
スライム1の攻撃 : 勇者3に28のダメージ
勇者3のHP : 43
勇者4の攻撃 : スライム2に41のダメージ
スライム2のHP : 103
勇者3の攻撃 : スライム3に36のダメージ
スライム3のHP : 110
スライム2の攻撃 : 勇者4に30のダメージ
勇者4のHP : 170

勇者1 , HP : 100 勇者2 , HP : 100 勇者3 , HP : 43 勇者4 , HP : 170
スライム1 , HP : 180 スライム2 , HP : 103 スライム3 , HP : 110

スライム1の攻撃 : 勇者4に29のダメージ
勇者4のHP : 141
勇者4の攻撃 : スライム2に43のダメージ
スライム2のHP : 60
勇者1の攻撃 : スライム2に32のダメージ
スライム2のHP : 28
勇者2の攻撃 : スライム2に31のダメージ
スライム2のHP : 0
スライム2は力尽きた!!!
スライム3の攻撃 : 勇者4に27のダメージ
勇者4のHP : 114
勇者3の攻撃 : スライム3に30のダメージ
スライム3のHP : 80
スライム2の攻撃 : 勇者4に26のダメージ
勇者4のHP : 88

勇者1 , HP : 100 勇者2 , HP : 100 勇者3 , HP : 43 勇者4 , HP : 88
スライム1 , HP : 180 スライム2 , HP : 0 スライム3 , HP : 80

勇者3の攻撃 : スライム3に35のダメージ
スライム3のHP : 45
勇者1の攻撃 : スライム3に36のダメージ
スライム3のHP : 9
スライム3の攻撃 : 勇者2に31のダメージ
勇者2のHP : 69
スライム1の攻撃 : 勇者3に28のダメージ
勇者3のHP : 15
勇者2の攻撃 : スライム3に34のダメージ
スライム3のHP : 0
スライム3は力尽きた!!!
勇者4の攻撃 : スライム1に43のダメージ
スライム1のHP : 137

勇者1 , HP : 100 勇者2 , HP : 69 勇者3 , HP : 15 勇者4 , HP : 88
スライム1 , HP : 137 スライム2 , HP : 0 スライム3 , HP : 0

勇者1の攻撃 : スライム1に33のダメージ
スライム1のHP : 104
勇者4の攻撃 : スライム1に41のダメージ
スライム1のHP : 63
勇者2の攻撃 : スライム1に34のダメージ
スライム1のHP : 29
勇者3の攻撃 : スライム1に36のダメージ
スライム1のHP : 0
スライム1は力尽きた!!!

勇者チームチームの勝ち
戦闘終了

見事に勇者チーム勝利wwwwwwww

お互いに殴り合うだけの
単純なシミュレーションです。

ドラクエ2風になったんじゃないかと思います。

そう考えると
ドラクエ3以降は複雑怪奇ですねーー

すぐ作れる気がしないので
この先どうなることやら・・・

今回はここまでです。
それでは。