格闘ゲーム

https://paiza.jp/works/mondai/class_primer/class_primer__fighting_game


前回の経験から、まずは例を使って実際にやってみる
ということはわかったんで、とりあえずやってみました

```
プレーヤー１ (p1)
hp = 10
f1 = 1
a1 = 1
f2 = 2
a2 = 2
f3 = 3
a3 = 3

プレーヤー２ (p2)
hp = 10
f1 = 0 #強化
a1 = 0
f2 = 6 
a2 = 1
f3 = 7
a3 = 2

プレーヤー3 (p3)
hp = 10
f1 = 0 #強化
a1 = 0
f2 = 7 
a2 = 5
f3 = 8
a3 = 3

１回目: 1 1 2 2
プレーヤー１技１で攻撃（f=1,a=1)
プレーヤー２技２で攻撃 (f=6,a=1)
⇒P1.f1(1) < p2.f2(6) なので、プレイヤー２の hp が p1.f1(1) 減る
  プレーヤー１:10
  プレーヤー２:9
  プレーヤー３:10
 
２回目: 1 2 3 2
プレーヤー１技２で攻撃（f=2,a=2)
プレーヤー３技２で攻撃（f=7,a=5)
⇒p1.f2(2) < p3.f2(7) なので、プレイヤー３の hp が p1.a1(2) 減る
 プレーヤー１:10
 プレーヤー２:9
 プレーヤー３:8

３回目: 1 3 2 3
プレーヤー１技３で攻撃（f=3,a=3)
プレーヤー２技３で攻撃（f=7,a=2)
⇒p1.f3(3) < p2.f3(7) なので、プレイヤー２の hp が p1.a3(3) 減る
  プレーヤー１:10
  プレーヤー２:6
  プレーヤー３:8

４回目: 2 2 3 1
プレーヤー２技２で攻撃（f=6,a=1)
プレーヤー３技１で強化 (f=0,a=0)
⇒プレイヤー３の hp が p2.a2(1) 減る
  プレーヤー１:10
  プレーヤー２:6
  プレーヤー３:7
⇒プレイヤー３の全ての技の発生フレーム（最短 1 フレーム) を -3 , 攻撃力を +5 する。
  f1 = 0 (0は0のまま)
  a1 = 0 (0は0のまま)
  f2 = 7-3=4 
  a2 = 5+5=10
  f3 = 8-3=5
  a3 = 3+5=8

５回目: 2 3 3 1
プレーヤー２技３で攻撃（f=7,a=2)
プレーヤー３技１で攻撃（f=0,a=0)
⇒プレイヤー３の hp が p2.a3(2) 減る
  プレーヤー１:10
  プレーヤー２:6
  プレーヤー３:5
⇒プレイヤー３の全ての技の発生フレーム（最短 1 フレーム) を -3 , 攻撃力を +5 する。
  f1 = 0 (0は0のまま)
  a1 = 0 (0は0のまま)
  f2 = 4-3=1 
  a2 = 10+5=15
  f3 = 5-3=2
  a3 = 8+5=13

６回目: 1 2 3 2
プレーヤー１技２で攻撃（f=2,a=2)
プレーヤー３技２で攻撃（f=1,a=15)
⇒p1.f2(2) > p3.f2(1) なので、プレイヤー１の hp が p3.a2(15) 減る
  プレーヤー１:0->退場
  プレーヤー２:6
  プレーヤー３:5
終了
生き残ったのは
2人（p2,p3)

```
とりあえず理屈はわかったんですが、
ここから一般化するにはどうすればいいか全く見当がつきませんでした。。。
具体的には
・強化技と攻撃技の２つあって、それらをどうメソッドにするか
　たぶんfが０、aが０だったら強化技とするみたいな？
・メソッドから各技のフレームや攻撃力をどうやって上下するか
・各プレーヤーの各技のフレームをどうやって比較するか
最初この３つが考えつかなかったです。。。
前回はただそのまま足したりひいたりするのが、if条件がついて難しくなった感じですね。

それと出口のない迷路では、２通りのルートをメソッドにしましたが
今回は３通りなのと数値をどうやって切り分けるかが見当つかないです。
今回はここでギブしました。

```py
class Status():
    def __init__(self,hp,f1,a1,f2,a2,f3,a3):
        self.hp = hp
        self.f1 = f1
        self.a1 = a1
        self.f2 = f2
        self.a2 = a2
        self.f3 = f3
        self.a3 = a3
        
    def skill_1(self,f1,a1):
        
    def skill_2(self,f2,a2):
        
    def skill_3(self,f3,a3):
        
        

N,K = map(int,input().split())
#戦う者たちのステータスを登録
braves = [Status(*input().split()) for _ in range(N)]

#バトル
for _ in range(K):
    p1,t1,p2,t2 = map(int,input().split())
    #各技のフレームを比較したい
    if braves[int(p1)-1].??? < braves[int(p2)-1].???
    

```

ここで解答みると、、、全く考えつかないなという解答が出ました。。。
そりゃ無理だわ。
配列を使うという発想が全く出てこなかったです。
後でもう一回します。

***

max関数は一応自分の解釈で
フレームの計算はmax値が見つからない場合はデフォルト値として１を表示する？という
結論でした
理由としては「他の全ての技の発生フレーム（最短 1 フレーム) を -3」とかいてあるので
最短が1なんですよね。たとえば−１とかはだめなので1を表示するという。
でもmax関数ってイテラブルなものに対してmaxのものを出力するというのがあるのだけど
今回の場合って１つの要素だけなので、どういう意味なのか結局わかってないんですよね汗
一応参考にしたのはpythonのドキュメントですが。

https://docs.python.org/ja/3/library/functions.html#max

=> そもそもドキュメントを読み間違えていたようで、イテラブルだけでなく、要素もいけました。
ここの部分ですね。
max(arg1, arg2, *args, key=None)
iterable の中で最大の要素、または2つ以上の引数の中で最大のものを返します。と書いてるのに。。。
ドキュメント嫌いなのを直さないとだめだなと思いました。

で、書き直しました。

```py

class Player():
    def __init__(self,hp,f1,a1,f2,a2,f3,a3):
        self.hp = int(hp)
        self.f =[int(f1),int(f2),int(f3)]
        self.a =[int(a1),int(a2),int(a3)]
        self.alive = True
        
    def enhance(self):
        #各技を強化
        for i in range(3):
            #自身が強化技ならスキップ
            if self.f[i] == 0 and self.a[i] == 0:
                continue
            #−３した結果１より下なら１で固定
            self.f[i] = max(self.f[i]-3,1)
            self.a[i] += 5

    def calc_hp(self, damage):
        self.hp -= int(damage)
        
        if self.hp <= 0:
            self.alive = False
            
    def get_status(self,i):
        return(self.f[i],self.a[i])
    
    def get_alive(self):
        return(self.alive)

N,K = map(int,input().split())
#戦う者たちのステータスを登録
players = [Player(*input().split()) for _ in range(N)]

#バトル
for _ in range(K):
    #各プレーヤーの出した技
    p1,t1,p2,t2 = map(int,input().split())
    p1 -= 1
    t1 -= 1
    p2 -= 1
    t2 -= 1
    #各技のフレーム・攻撃力を変数へ
    f1,a1 = players[p1].get_status(t1)
    f2,a2 = players[p2].get_status(t2)
    
    #どっちかのHPが０ならバトルなしでスキップ
    if players[p1].alive == False or players[p2].alive == False:
        continue
    
    #どっちもまたはどっちかが強化技、攻撃技かで分岐
    if f1 == 0 and a1 == 0 and f2 == 0 and a2 == 0:
        players[p1].enhance()
        players[p2].enhance()
    elif f1 == 0 and a1 == 0:
        players[p1].enhance()
        players[p1].calc_hp(a2)
    elif f2 == 0 and a2 == 0:
        players[p2].enhance()
        players[p2].calc_hp(a1)
    else:
        if f1 > f2:
            players[p1].calc_hp(a2)
        elif f1 < f2:
            players[p2].calc_hp(a1)
        else:
            pass

        
ans = 0
for player in players:
    if player.alive == True:
        ans += 1

print(ans)    
```
細かい部分で正解とはちょっと異なってますが、大筋は同じです。
型変換とかしないといけない部分があってそこはクラスの方を変えてますね。
念の為コメントとかも入れましたが。