見出し画像

オブジェクト指向で戦闘シミュレーション?(3)

前回はRPG風戦闘プログラムを作ってみました。
そのままでは少し寂しいので、艦隊これくしょん(艦これ)の戦闘ダメージ計算を導入してみました。

艦これダメージ計算

「艦これ」は、DMM GAMESと「艦これ」運営鎮守府による艦隊育成シミュレーションゲームです。公式ページはこちら

ゲームの戦闘に関しては、有志による戦闘結果の統計・解析により、計算式がかなり明らかになっています。
ここでは艦これWikiの「与ダメージの算定に関わる要素の考察」を参考にさせていただき、ダメージ計算を組んでみたいと思います。(先人たちの多大なる努力に感謝します)

艦これダメージ計算の要素

詳細は上記のWikiを参照していただくとして、大まかな計算は次のとおりです。

ダメージは、攻撃力から防御力を引いたものです。
(ここでは補正についての変数は、考慮しないよう1.0か省略。以下同様)
引いた結果が負になる場合は、カスダメの計算を行います。

攻撃力は、「火力+5」が基になり、自身の損傷度合いで割引されます。
さらに、交戦形態、陣形の影響が乗じられた上で、キャップ計算(上限)で削られます。
最後に、クリティカルが発生していれば1.5倍して、計算終了です。

防御力は、装甲の0.7〜1.3倍がランダムに使われます。

なお適当ですが、命中率は50%、回避率は0%としました。

サンプルプログラム

これらを、前回の戦闘シミュレーションのクラスに組み込んでみました。

import random
import math

class Player():
   def __init__(self, hp , karyoku, soukou):
       self.HP= hp
       self.Karyoku= karyoku   #火力
       self.Soukou = soukou    #装甲
       
   def GetOffense(self): #攻撃力
       #昼・砲撃戦バージョン
       Jinkei= 0        #0:単縦/1:複縦/2:輪/3:梯/4:単横/5:警戒
       KousenKeitai= 0  #0:同航戦/1:反航戦/2:T字有利/3:T字不利
       KaisyuHou= 0.0   #改修強化値
       Sonsyo=0         #0:全快/1:小破/2:中破/3:大破/4:攻撃不能
       Chritical= 1.0   #クリティカル補正
       Cap= 180.0       #キャップ:昼戦砲撃戦

       CapMaeHosei= [1.0, 0.8, 1.2, 0.6][KousenKeitai]  \
                    *[1.00, 0.80, 0.70, 0.75, 0.60, 0.5][Jinkei]
       
       #基本攻撃力
       KihonKougeki= (self.Karyoku +KaisyuHou +5)             \
                          *[1.0, 1.0, 0.7, 0.4, 0.0][Sonsyo]

       #命中・クリティカル判定
       HitLev= (self.GetHit() -self.GetAvoidance()) /100.0
       ChriticalDice= random.random()
       if ChriticalDice>=HitLev:                          #MISS
           return 0
       if ChriticalDice<(0.125 *math.sqrt(HitLev) +0.01): #クリティカルヒット発生
           Chritical= 1.5

       #キャップ前攻撃力
       CapMae= KihonKougeki *CapMaeHosei
       
       #攻撃力キャップ
       if CapMae<=Cap:
           CapGo= CapMae
       else:
           CapGo= Cap + math.sqrt(CapMae -Cap)

       #最終攻撃力算出
       A= int(CapGo)
       SaisyuKougeki= int(A *Chritical)    # クリティカル熟練度補正

       return SaisyuKougeki
       
   def GetDefense(self):                 #防御力
       Bougyo= self.Soukou *0.7 +random.randint(0, self.Soukou -1) *0.6
       return Bougyo
       
   def GetHit(self):                      #命中(%)
       return 50.0

   def GetAvoidance(self):               #回避(%)
       return 0.0
   
class Attack():
   def Action(self, Player1, Player2):
       DanyakuHosei= 1.0   #弾薬補正

       Damage= int((Player1.GetOffense() -Player2.GetDefense()) *DanyakuHosei)
       
       if Damage<0:        #カスダメ
           if Player2.HP>1:
               Damage= int(Player2.HP *0.06 +random.randint(0, Player2.HP -1) *0.08)
           else:
               Damage= 0
               
       print(f"{Damage}のダメージ!")
       return Damage

class Battle():
   def Progress(self, Player1, Player2):
       AttackObject= Attack()
       print("吹雪の攻撃!")
       
       # 100回攻撃してみる
       dl= []
       for i in range(100):
           dl.append(AttackObject.Action(P1, P2))

       print(f"最小:{min(dl)}、最大:{max(dl)}")
       
#ここからメインルーチン
P1= Player(15, 10, 5)      #吹雪 初期
P2= Player(20, 5, 5)       #駆逐イ級
BattleObject= Battle()
BattleObject.Progress(P1, P2)

キャラクターのモデルとして、吹雪(初期値)と駆逐イ級のパラメータをお借りしました。
プログラムのBattleクラスでは、100回の攻撃を行い、ダメージの最大/最小を求めました。

最小:1、最大:18

検算

求めた値が正しかったか、確かめてみます。

正解の値として、「艦これダメージ計算機」を使用させていただきました。
これによると、通常:9〜11、クリティカル:16〜18でした。

プログラムにおいて、クリティカルを出さないよう、30行目あたりのChriticalDiceを0.4に固定してみます。

ChriticalDice= 0.4

結果は、

最小:9、最大:11

逆に、クリティカルを出すようにしてみると、(ChriticalDice= 0)

最小:16、最大:18

それなりに計算できているようで、一安心です。

プログラムをいじって遊ぶ

今回は、paiza.ioを使って、実際にプログラムをいじれるようにしてみました。

こちらのリンクからpaiza.ioのエディタに入ってください。

エディタに用意されたプログラムは書き換えることができますし、ページを閉じれば元に戻ります。

実行する場合は、「→実行(Ctrl+Enter)」ボタンを押してください。

90行目あたりに、キャラクターのパラメータをいくつか用意していますので、コメントアウト(#)を外すとそれを試すこともできます。

この記事が参加している募集

この記事が気に入ったらサポートをしてみませんか?