オブジェクト指向で戦闘シミュレーション?(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行目あたりに、キャラクターのパラメータをいくつか用意していますので、コメントアウト(#)を外すとそれを試すこともできます。