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), }, } @dataclass 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 ]) @classmethod def from_array(cls, arr: np.ndarray) -> SkillVector: return cls(*arr.tolist()) @property 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 @dataclass class PlayerProfile: """Complete player profile with skill and metadata.""" profile_id: str rank: Rank skill_vector: SkillVector hours_played: int is_cheater: bool = False @classmethod 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()