Foxgrad's picture
Add game engine and bots
3304d77 verified
Raw History Blame Contribute Delete
2.72 kB
"""Une partie : deux équipes de soldats, chaque équipe pilotée par un bot, tour par tour."""
from __future__ import annotations
from dataclasses import dataclass
import numpy as np
from . import shot as S
from .world import World
@dataclass
class Turn:
team: int
shooter: int
shot: object
result: S.ShotResult
outcome: str # "kill", "teamkill", "obstacle", "out"
class Match:
def __init__(self, bot_left, bot_right, rng: np.random.Generator, soldiers: int = 3, max_turns: int = 40):
self.bots = [bot_left, bot_right]
self.world = World.random(rng, (soldiers, soldiers))
self.team = int(rng.integers(2)) # qui commence
self.cursor = [0, 0]
self.turns: list[Turn] = []
self.max_turns = max_turns
self.stats = [{"tirs": 0, "kills": 0, "teamkills": 0} for _ in range(2)]
def next_shooter(self, team):
alive = self.world.alive(team)
idx = alive[self.cursor[team] % len(alive)]
self.cursor[team] += 1
return idx
def over(self) -> bool:
return self.winner() is not None or len(self.turns) >= self.max_turns
def winner(self):
a, b = len(self.world.alive(0)), len(self.world.alive(1))
if a and not b:
return 0
if b and not a:
return 1
if not a and not b:
return -1
if len(self.turns) >= self.max_turns:
return 0 if a > b else 1 if b > a else -1 # au temps : plus de survivants
return None
def plan(self):
"""Le bot de l'équipe dont c'est le tour choisit son tir (sans encore l'appliquer)."""
team = self.team
shooter = self.next_shooter(team)
sh = self.bots[team].act(self.world, shooter)
res = S.simulate(self.world, shooter, sh.g, sh.z, sh.target)
return team, shooter, sh, res
def commit(self, team, shooter, sh, res) -> Turn:
st = self.stats[team]
st["tirs"] += 1
if res.event == "soldier":
victim = self.world.soldiers[res.hit_index]
outcome = "teamkill" if victim.team == team else "kill"
st["kills" if outcome == "kill" else "teamkills"] += 1
else:
outcome = res.event
S.apply(self.world, res)
t = Turn(team, shooter, sh, res, outcome)
self.turns.append(t)
self.team = 1 - team
if not self.world.alive(self.team): # l'autre équipe n'a plus personne
self.team = team
return t
def step(self) -> Turn:
return self.commit(*self.plan())
def play(self):
while not self.over():
self.step()
return self.winner()