Download graphwar/world.py from Foxgrad/graphwar-arena: direct link, hf CLI and curl.
- Browser
- Download file 3.05 kB
-
https://huggingface.co/Foxgrad/graphwar-arena/resolve/main/graphwar/world.py
- Command line
-
hf download hf://Foxgrad/graphwar-arena/graphwar/world.py
-
curl -L -o world.py https://huggingface.co/Foxgrad/graphwar-arena/resolve/main/graphwar/world.py
3.05 kB
| """Le monde : obstacles (cylindres), cratères et soldats.""" | |
| from __future__ import annotations | |
| from dataclasses import dataclass, field | |
| import numpy as np | |
| from . import config as C | |
| class Soldier: | |
| x: float | |
| y: float | |
| team: int # 0 = gauche (tire vers +x), 1 = droite (tire vers -x) | |
| alive: bool = True | |
| def dir(self) -> int: | |
| return 1 if self.team == 0 else -1 | |
| class World: | |
| obstacles: np.ndarray # (M, 4) : x, y, rayon, hauteur | |
| soldiers: list[Soldier] = field(default_factory=list) | |
| craters: np.ndarray = field(default_factory=lambda: np.zeros((0, 3))) # (K, 3) : x, y, rayon | |
| # ------------------------------------------------------------------ génération | |
| def random(rng: np.random.Generator, team_sizes=(3, 3)) -> "World": | |
| n = int(rng.integers(C.OBST_COUNT[0], C.OBST_COUNT[1] + 1)) | |
| obs = np.column_stack([ | |
| rng.uniform(-22, 22, n), | |
| rng.uniform(-14, 14, n), | |
| rng.uniform(*C.OBST_RADIUS, n), | |
| rng.uniform(*C.OBST_HEIGHT, n), | |
| ]) | |
| w = World(obstacles=obs) | |
| for team, count in enumerate(team_sizes): | |
| for _ in range(count): | |
| w.soldiers.append(w._free_soldier(rng, team)) | |
| return w | |
| def _free_soldier(self, rng, team) -> Soldier: | |
| for _ in range(500): | |
| x = rng.uniform(3, 24) * (-1 if team == 0 else 1) | |
| y = rng.uniform(-13.5, 13.5) | |
| if self.is_free(x, y, C.SPAWN_MARGIN) and all( | |
| np.hypot(s.x - x, s.y - y) > 3.0 for s in self.soldiers | |
| ): | |
| return Soldier(x, y, team) | |
| # carte trop chargée : on retire l'obstacle le plus proche et on réessaie | |
| d = np.hypot(self.obstacles[:, 0] - x, self.obstacles[:, 1] - y) - self.obstacles[:, 2] | |
| self.obstacles = np.delete(self.obstacles, int(np.argmin(d)), axis=0) | |
| return self._free_soldier(rng, team) | |
| # ------------------------------------------------------------------ requêtes | |
| def is_free(self, x: float, y: float, margin: float = 0.0) -> bool: | |
| o = self.obstacles | |
| inside = np.hypot(o[:, 0] - x, o[:, 1] - y) < o[:, 2] + margin | |
| if not inside.any(): | |
| return True | |
| if len(self.craters) and margin == 0.0: | |
| c = self.craters | |
| if (np.hypot(c[:, 0] - x, c[:, 1] - y) < c[:, 2]).any(): | |
| return True | |
| return False | |
| def add_crater(self, x: float, y: float, r: float = C.CRATER_R) -> None: | |
| self.craters = np.vstack([self.craters, [x, y, r]]) | |
| def alive(self, team: int | None = None) -> list[int]: | |
| return [i for i, s in enumerate(self.soldiers) if s.alive and (team is None or s.team == team)] | |
| def copy(self) -> "World": | |
| return World( | |
| obstacles=self.obstacles.copy(), | |
| soldiers=[Soldier(s.x, s.y, s.team, s.alive) for s in self.soldiers], | |
| craters=self.craters.copy(), | |
| ) | |