スレッドを使って戦闘シミレーションを作ろう
今回はスレッドを使って、戦闘シミュレーションを作りましょう。
これはThreadクラスを継承したクラスを定義して、そのクラスから2つのインスタンスを作り、互いに相手を攻撃するプログラムです。
実行イメージ
2人のプレイヤーが自動で相手を攻撃して、先にHP(ヒットポイント)が0になった方が負けになります。
プレイヤーのパラメーターは、HP、攻撃力、敏捷性がランダムで設定されます。
ターン制ではないので、敏捷性の値が高ければ早く攻撃ができるようになり、場合によっては連続して攻撃します。
実行例
C:\>python battle1-1.py
戦士A HP[28] 攻撃力[ 6] 敏捷性[16]
戦士B HP[60] 攻撃力[13] 敏捷性[ 4]
戦士Aは戦士Bに7のダメージ
→ 戦士Bの残HP[53]
戦士Bは戦士Aに13のダメージ
→ 戦士Aの残HP[15]
戦士Aは戦士Bに8のダメージ
→ 戦士Bの残HP[45]
戦士Aは戦士Bに7のダメージ
→ 戦士Bの残HP[38]
戦士Bは戦士Aに14のダメージ
→ 戦士Aの残HP[1]
戦士Aは戦士Bに16のダメージ
→ 戦士Bの残HP[22]
戦士Aは戦士Bに14のダメージ
→ 戦士Bの残HP[8]
戦士Bは戦士Aに13のダメージ
→ 戦士Aの残HP[0]
++ 戦士Bの勝利! ++
Pythonスクリプト
Pythonスクリプトは、以下のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
### インポート import time import random import threading ### 定数 PLAYER = ["戦士A","戦士B"] # プレイヤー名 ############################ ### プレイヤークラス ############################ class Player(threading.Thread): ############################ ### 初期化メソッド ############################ def __init__(self, name): ### Threadクラスの初期化 threading.Thread.__init__(self) ### クラス変数設定 self.name = name # プレイヤー名 self.hp = random.randint(10, 99) # 体力 self.atk = random.randint( 1, 20) # 攻撃力 self.agi = random.randint( 1, 20) # 敏捷性 ### ステータスを表示 print("{:<4} HP[{:>2}] 攻撃力[{:>2}] 敏捷性[{:>2}]".format(self.name, self.hp, self.atk, self.agi)) ############################ ### 攻撃メソッド ############################ def run(self): ### 自分のHPが0になるまでループ while self.hp > 0: ### 次の攻撃まで待機 time.sleep(5 / (self.agi + random.randint(0, 10))) ### Main以外のスレッドを取得 for enemy in threading.enumerate()[1:]: ### 自スレッドだったら飛ばす if enemy is threading.currentThread(): continue ### 自分または相手のHPが0なら終了 if self.hp == 0 or enemy.hp == 0: break ### 相手プレイヤーのHPを減算 damage = self.atk + random.randint(0, 10) enemy.hp -= damage ### 相手プレイヤーのHPが0未満なら0にする if enemy.hp < 0: enemy.hp = 0 ### 画面表示 print("{}は{}に{}のダメージ".format(self.name, enemy.name, damage)) print(" → {}の残HP[{}]".format(enemy.name, enemy.hp)) ### 相手がいなければ終了 if threading.active_count()-1 == 1: print("++ {}の勝利! ++".format(self.name)) break ############################ ### メイン関数 ############################ def main(): ### プレイヤーを作成 players = [Player(name) for name in PLAYER] ### スレッドを開始 for player in players: player.start() ############################ ### メイン関数呼び出し ############################ if __name__ == "__main__": ### 処理開始 main() |
スクリプト解説
24~26行目
各パラメーターにランダムで値を設定します。
37行目
自分のHPが0になるまでループします。
40行目
5秒を敏捷性の値とランダムで与えられたボーナスポイントを足した値で割った時間の間待機します。
43行目
現在動いているスレッドの一覧を取得します。
[1:]と記述することによって、配列の先頭は飛ばされます。
46、47行目
取得したスレッドが自スレッドだったら飛ばします。
50、51行目
自分または相手のHPが0だった場合、処理を終了します。
54、55行目
ダメージ値を計算して、相手のHPを減らします。
ダメージ値は、元の攻撃力の値にランダムで与えられたボーナスポイントを足します。
58、59行目
相手のHPが0未満だったら0にします。
66~68行目
現在動いているスレッドの数を取得して、Mainスレッドを除いた数が1だった場合は処理を終了します。
76行目
内包表記を使って、Playerクラスからプレイヤー数分インスタンスを作成します。
内包表記は、こちらの記事を参照してください。
79、80行目
作成したインスタンスのスレッドを開始します。