第125回【Python】格闘ゲーム

現在取り組んでいるのは、paiza ラーニング問題集「クラス・構造体メニュー」になります。

はじめに

猫とキャンプと野球観戦と AWS が大好きな旦那、LeoSaki です。モフモフしたい。

Python をゼロから勉強してみよう、のコーナー 125 回目です。

1 問 1 問に時間がかかるようになってきました。それもまた面白い。今は部品一つの問題ですが、もっとたくさんの部品を組み合わせる必要がある問題が出てくればいいのになぁと思っています。VBA で継承を書くのは骨が折れるけれども。

それでは、今日も頑張ってみようと思います。

格闘ゲーム

友達の家で N 人で遊んでいる paiza 君は格闘ゲームを遊ぶことにしました。
格闘ゲームのルールは次の通りです。

・ 各プレイヤーは 決まった hp と 3 種類の技を持っていて、技には強化系の技と攻撃の技があり、各攻撃技には技を出すための発生フレーム F とダメージ A が設定されている。

・ hp が 0 になったプレイヤーは退場となる。

・あるプレイヤー 1 が、他のプレイヤーにある技 T_1 (発生フレーム F_1 , 攻撃力 A_1) を使って攻撃した場合、攻撃を受けたプレイヤー 2 は反撃の技 T_2 (発生フレーム F_2 , 攻撃力 A_2) を選ぶ。その後、次のようなルールに従っていずれかのプレイヤーにダメージが入る。

  • どちらか片方でもプレイヤーが退場している場合、互いに何も起こらない。
  • 強化系の技を使った場合、使ったプレイヤーの他の全ての技の発生フレーム(最短 1 フレーム) を -3 , 攻撃力を +5 する。
    相手が攻撃技を使っていた場合、その攻撃の攻撃力分 hp が減少する。
  • 互いに攻撃技を使った場合
    ・ F_1 < F_2 のとき、プレイヤー 2 の hp が A_1 減る
    ・ F_1 > F_2 のとき、プレイヤー 1 の hp が A_2 減る
    ・ F_1 = F_2 のとき、何も起こらない

各プレイヤーの持っている技についての情報と、技が出された回数、使われた技の詳細が与えられるので、全ての技が使われた後に場に残っているプレイヤーの人数を答えてください。

N K
hp_1 F1_1 A1_1 F2_1 A2_1 F3_1 A3_1
...
hp_N F1_N A1_N F2_N A2_N F3_N A3_N
P1_1 T1_1 P2_1 T2_1
...
P1_K T1_K P2_K T2_K

・ 1 行目では、プレイヤー数 N と攻撃回数 K が与えられます。

・ 続く N 行のうち i 行目(1 ≦ i ≦ N)では、 i 番目のプレイヤーの hp である hp_i,
技 1 の発生フレーム F1_i , 攻撃力 A1_i
技 2 の発生フレーム F2_i , 攻撃力 A2_i
技 3 の発生フレーム F3_i , 攻撃力 A3_i が半角スペース区切りで与えられます。
ただし、発生フレーム・攻撃力が共に 0 である技は強化技であることを表しています。

・ 続く K 行のうち、 i 行目では i 回目の攻撃内容が与えられます。
技を使ったプレイヤーの番号 P1_i と P1_i が選んだ技の番号 T1_i
技を使ったプレイヤーの番号 P2_i と P2_i が選んだ技の番号 T2_i
が半角スペース区切りで与えられます。


すべてのテストケースにおいて、以下の条件をみたします。

・ 1 ≦ N , K ≦ 1000
・ 1 ≦ hp_i ≦ 100 (1 ≦ i ≦ N)
・ 0 ≦ F1_i , F2_i , F3_i ≦ 60 (1 ≦ i ≦ N)
・ 0 ≦ A1_i , A2_i , A3_i ≦ 30 (1 ≦ i ≦ N)
・ 1 ≦ P1_i , P2_i ≦ N , P1_i ≠ P2_i (1 ≦ i ≦ K)
・ T1_i , T2_i は 1 , 2 , 3 のいずれか (1 ≦ i ≦ K)
・ 強化技は各プレイヤーに最大 1 つまで


入力例

3 6
10 1 1 2 2 3 3
10 0 0 6 1 7 2
10 0 0 7 5 8 3
1 1 2 2
1 2 3 2
1 3 2 3
2 2 3 1
2 3 3 1
1 2 3 2

出力例

2

ちゃんと整理して、クラスで何が必要かを考える必要がある。この問題の場合は狂花技(誤字じゃない)とダメージ受けちゃった、あとは、生死確認かなぁと思う。※ハナバタは登場していません。

Python
class Player:
    def __init__(self,hp,f1,a1,f2,a2,f3,a3):
        self.hp = hp
        self.f = [f1,f2,f3]
        self.a = [a1,a2,a3]
        self.alive = True
        
    def strengthen(self):
        for i in range(3):
            if self.f[i] == self.a[i] == 0:
                continue
            self.f[i] = max(self.f[i] - 3,1)
            self.a[i] += 5
            
    def recieve_damage(self,damage):
        self.hp -= 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 = [None] * N

for i in range(N):
    hp,f1,a1,f2,a2,f3,a3 = map(int,input().split())
    players[i] = Player(hp,f1,a1,f2,a2,f3,a3)
    
for i in range(K):
    p1,t1,p2,t2 = map(int,input().split())
    p1,t1,p2,t2 = p1-1,t1-1,p2-1,t2-1
    
    if not players[p1].get_alive() or not players[p2].get_alive():
        continue
    
    p1_f,p1_a = players[p1].get_status(t1)
    p2_f,p2_a = players[p2].get_status(t2)
    
    if p1_f == p1_a == p2_f == p2_a == 0:
        players[p1].strengthen()
        players[p2].strengthen()
    elif p1_f == p1_a == 0:
        players[p1].strengthen()
        players[p1].recieve_damage(p2_a)
    elif p2_f == p2_a == 0:
        players[p2].strengthen()
        players[p2].recieve_damage(p1_a)
    elif p1_f < p2_f:
        players[p2].recieve_damage(p1_a)
    elif p1_f > p2_f:
        players[p1].recieve_damage(p2_a)

cnt = 0
for player in players:
    if player.get_alive():
        cnt += 1

print(cnt)
VBA
## class_player
Private hp As Integer
Private f As Variant
Private a As Variant
Private alive As Boolean

Property Let status(h, f1, a1, f2, a2, f3, a3)

    hp = h
    f = Array(f1, f2, f3)
    a = Array(a1, a2, a3)
    alive = True
    
End Property

Function strengthen()

    For i = 0 To 2
        If Not (f(i) = 0 And a(i) = 0) Then
            f(i) = Application.WorksheetFunction.Max(f(i) - 3, 1)
            a(i) = a(i) + 5
        End If
    Next
    
End Function

Property Let recieve_damage(damage)

    hp = hp - damage
    If hp <= 0 Then
        alive = False
    End If
    
End Property

Property Get get_status(i)

    get_status = Array(f(i), a(i))
    
End Property

Property Get get_alive()

    get_alive = alive
    
End Property
## 標準モジュール
Sub class_primer__fighting_game()

    NK = Split(Cells(1, 1), " ")
    N = Val(NK(0))
    K = Val(NK(1))
    
    Dim players() As New class_player
    ReDim players(N - 1)
    
    For i = 0 To N - 1
        s = Split(Cells(i + 2, 1), " ")
        players(i).status(Val(s(0)), Val(s(1)), Val(s(2)), Val(s(3)), Val(s(4)), Val(s(5))) = Val(s(6))
    Next
    
    For i = 1 To K
        s = Split(Cells(i + N + 1, 1), " ")
        p1 = Val(s(0)) - 1
        t1 = Val(s(1)) - 1
        p2 = Val(s(2)) - 1
        t2 = Val(s(3)) - 1
        
        If Not players(p1).get_alive() Or Not players(p2).get_alive() Then
            GoTo CONTINUE
        End If
        
        p1fa = players(p1).get_status(t1)
        p2fa = players(p2).get_status(t2)
        
        If p1fa(0) = 0 And p1fa(1) = 0 And p2fa(0) = 0 And p2fa(1) = 0 Then
            players(p1).strengthen
            players(p2).strengthen
        ElseIf p1fa(0) = 0 And p1fa(1) = 0 Then
            players(p1).strengthen
            players(p1).recieve_damage = p2fa(1)
        ElseIf p2fa(0) = 0 And p2fa(1) = 0 Then
            players(p2).strengthen
            players(p2).recieve_damage = p1fa(1)
        ElseIf p1fa(0) < p2fa(0) Then
            players(p2).recieve_damage = p1fa(1)
        ElseIf p1fa(0) > p2fa(0) Then
            players(p1).recieve_damage = p2fa(1)
        End If
        
CONTINUE:

    Next
    
    cnt = 0
    For i = LBound(players) To UBound(players)
        If players(i).get_alive() Then
            cnt = cnt + 1
        End If
    Next
    
    Debug.Print cnt
    
End Sub

最後に

Python は相変わらずわかりやすくて良いですね。日本語人からすると、関数名を日本語で書ければわかりやすくていいのにって思う。しかし、VBA で関数名を日本語にはしない。最近、ネットでいろいろ調べていると、日本語関数名増えてますが、なんとなく昔からの慣習で日本語関数は使わない。

簡潔に簡潔に、と考えすぎて、逆に VBA はわかりづらくなっている気がします。上記だと、p1fa や p2fa といった配列は、ちゃんと何が入っているか展開してから利用した方が、わかりやすいかもしれません。

引き続き、よろしくお願いいたします!

Pythonpaiza,学習,Python

Posted by LeoSaki