Spaces:
Running
on
Zero
Running
on
Zero
| from __future__ import annotations | |
| import numpy as np | |
| from dataclasses import dataclass, field | |
| from typing import Optional, Dict, Any, Tuple | |
| from enum import Enum | |
| # Skill correlation matrix - represents realistic correlations between player skills | |
| # Rows/cols: raw_aim, spray_control, crosshair_placement, reaction_speed, game_sense, movement, consistency, mental_resilience | |
| SKILL_CORRELATION_MATRIX = np.array([ | |
| # aim spray cross react sense move cons mental | |
| [1.00, 0.70, 0.50, 0.30, 0.20, 0.40, 0.30, 0.10], # raw_aim | |
| [0.70, 1.00, 0.40, 0.20, 0.30, 0.30, 0.40, 0.10], # spray_control | |
| [0.50, 0.40, 1.00, 0.20, 0.60, 0.50, 0.50, 0.20], # crosshair_placement | |
| [0.30, 0.20, 0.20, 1.00, 0.30, 0.40, 0.20, 0.30], # reaction_speed | |
| [0.20, 0.30, 0.60, 0.30, 1.00, 0.50, 0.40, 0.40], # game_sense | |
| [0.40, 0.30, 0.50, 0.40, 0.50, 1.00, 0.30, 0.20], # movement | |
| [0.30, 0.40, 0.50, 0.20, 0.40, 0.30, 1.00, 0.50], # consistency | |
| [0.10, 0.10, 0.20, 0.30, 0.40, 0.20, 0.50, 1.00], # mental_resilience | |
| ]) | |
| SKILL_STD = np.array([15.0, 15.0, 15.0, 12.0, 15.0, 12.0, 18.0, 20.0]) | |
| SKILL_NAMES = ["raw_aim", "spray_control", "crosshair_placement", "reaction_speed", | |
| "game_sense", "movement", "consistency", "mental_resilience"] | |
| class Rank(Enum): | |
| SILVER = "silver" | |
| GOLD_NOVA = "gold_nova" | |
| MASTER_GUARDIAN = "master_guardian" | |
| LEGENDARY_EAGLE = "legendary_eagle" | |
| SUPREME_GLOBAL = "supreme_global" | |
| PRO = "pro" | |
| RANK_STATISTICS = { | |
| Rank.SILVER: { | |
| "skill_mean": 25.0, | |
| "hs_percent": (0.25, 0.35), | |
| "accuracy": (0.06, 0.08), | |
| "reaction_time_ms": (280.0, 350.0), | |
| "kd_ratio": (0.5, 0.85), | |
| "adr": (35.0, 55.0), | |
| "edpi": (1200, 2400), | |
| "hours_played": (0, 300), | |
| }, | |
| Rank.GOLD_NOVA: { | |
| "skill_mean": 40.0, | |
| "hs_percent": (0.35, 0.42), | |
| "accuracy": (0.08, 0.10), | |
| "reaction_time_ms": (250.0, 290.0), | |
| "kd_ratio": (0.85, 1.1), | |
| "adr": (50.0, 70.0), | |
| "edpi": (1000, 1800), | |
| "hours_played": (200, 600), | |
| }, | |
| Rank.MASTER_GUARDIAN: { | |
| "skill_mean": 55.0, | |
| "hs_percent": (0.40, 0.48), | |
| "accuracy": (0.10, 0.12), | |
| "reaction_time_ms": (220.0, 260.0), | |
| "kd_ratio": (1.0, 1.2), | |
| "adr": (60.0, 80.0), | |
| "edpi": (800, 1400), | |
| "hours_played": (400, 1200), | |
| }, | |
| Rank.LEGENDARY_EAGLE: { | |
| "skill_mean": 70.0, | |
| "hs_percent": (0.45, 0.52), | |
| "accuracy": (0.12, 0.14), | |
| "reaction_time_ms": (200.0, 240.0), | |
| "kd_ratio": (1.15, 1.35), | |
| "adr": (70.0, 90.0), | |
| "edpi": (700, 1200), | |
| "hours_played": (800, 2000), | |
| }, | |
| Rank.SUPREME_GLOBAL: { | |
| "skill_mean": 82.0, | |
| "hs_percent": (0.48, 0.55), | |
| "accuracy": (0.14, 0.16), | |
| "reaction_time_ms": (180.0, 220.0), | |
| "kd_ratio": (1.25, 1.5), | |
| "adr": (75.0, 95.0), | |
| "edpi": (600, 1100), | |
| "hours_played": (1200, 3500), | |
| }, | |
| Rank.PRO: { | |
| "skill_mean": 92.0, | |
| "hs_percent": (0.55, 0.66), | |
| "accuracy": (0.17, 0.20), | |
| "reaction_time_ms": (140.0, 180.0), | |
| "kd_ratio": (1.3, 2.0), | |
| "adr": (85.0, 110.0), | |
| "edpi": (550, 1000), | |
| "hours_played": (3000, 10000), | |
| }, | |
| } | |
| class SkillVector: | |
| """8-dimensional skill vector with realistic correlations.""" | |
| raw_aim: float | |
| spray_control: float | |
| crosshair_placement: float | |
| reaction_speed: float | |
| game_sense: float | |
| movement: float | |
| consistency: float | |
| mental_resilience: float | |
| def to_array(self) -> np.ndarray: | |
| return np.array([ | |
| self.raw_aim, self.spray_control, self.crosshair_placement, | |
| self.reaction_speed, self.game_sense, self.movement, | |
| self.consistency, self.mental_resilience | |
| ]) | |
| def from_array(cls, arr: np.ndarray) -> SkillVector: | |
| return cls(*arr.tolist()) | |
| def mean_skill(self) -> float: | |
| return float(self.to_array().mean()) | |
| def generate_correlated_skills( | |
| rank: Rank, | |
| rng: Optional[np.random.Generator] = None | |
| ) -> np.ndarray: | |
| """Generate correlated skill vector using Cholesky decomposition.""" | |
| if rng is None: | |
| rng = np.random.default_rng() | |
| stats = RANK_STATISTICS[rank] | |
| skill_mean = stats["skill_mean"] | |
| # Create covariance matrix from correlation and std | |
| cov = np.outer(SKILL_STD, SKILL_STD) * SKILL_CORRELATION_MATRIX | |
| # Cholesky decomposition for correlated sampling | |
| L = np.linalg.cholesky(cov) | |
| # Generate uncorrelated standard normal | |
| z = rng.standard_normal(8) | |
| # Transform to correlated with correct mean/cov | |
| skills = skill_mean + L @ z | |
| # Clip to valid range [0, 100] | |
| skills = np.clip(skills, 0.0, 100.0) | |
| return skills | |
| class PlayerProfile: | |
| """Complete player profile with skill and metadata.""" | |
| profile_id: str | |
| rank: Rank | |
| skill_vector: SkillVector | |
| hours_played: int | |
| is_cheater: bool = False | |
| def generate( | |
| cls, | |
| rank: str | Rank, | |
| seed: Optional[int] = None, | |
| profile_id: Optional[str] = None, | |
| ) -> PlayerProfile: | |
| """Generate a random player profile for given rank.""" | |
| if isinstance(rank, str): | |
| rank = Rank(rank) | |
| rng = np.random.default_rng(seed) | |
| # Generate correlated skills | |
| skills = generate_correlated_skills(rank, rng) | |
| skill_vector = SkillVector.from_array(skills) | |
| # Generate hours played | |
| stats = RANK_STATISTICS[rank] | |
| hours_low, hours_high = stats["hours_played"] | |
| hours_played = int(rng.uniform(hours_low, hours_high)) | |
| # Generate profile ID if not provided | |
| if profile_id is None: | |
| profile_id = f"player_{rng.integers(0, 2**32):08x}" | |
| return cls( | |
| profile_id=profile_id, | |
| rank=rank, | |
| skill_vector=skill_vector, | |
| hours_played=hours_played, | |
| is_cheater=False, | |
| ) | |
| def get_expected_stats(self) -> Dict[str, Tuple[float, float]]: | |
| """Get expected stat ranges based on rank and skill.""" | |
| return RANK_STATISTICS[self.rank].copy() | |