chore: initial commit — CS2 Simulator
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
import json
|
||||
import asyncio
|
||||
import random
|
||||
import math
|
||||
from typing import Set, Dict, Optional
|
||||
from fastapi import WebSocket
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class ConnectionManager:
|
||||
def __init__(self):
|
||||
self.active_connections: Dict[int, Set[WebSocket]] = {}
|
||||
self._lock = asyncio.Lock()
|
||||
|
||||
async def connect(self, websocket: WebSocket, user_id: int):
|
||||
await websocket.accept()
|
||||
async with self._lock:
|
||||
if user_id not in self.active_connections:
|
||||
self.active_connections[user_id] = set()
|
||||
self.active_connections[user_id].add(websocket)
|
||||
|
||||
async def disconnect(self, websocket: WebSocket, user_id: int):
|
||||
async with self._lock:
|
||||
if user_id in self.active_connections:
|
||||
self.active_connections[user_id].discard(websocket)
|
||||
if not self.active_connections[user_id]:
|
||||
del self.active_connections[user_id]
|
||||
|
||||
async def send_personal(self, user_id: int, message: dict):
|
||||
async with self._lock:
|
||||
if user_id in self.active_connections:
|
||||
dead = set()
|
||||
for ws in self.active_connections[user_id]:
|
||||
try:
|
||||
await ws.send_json(message)
|
||||
except Exception:
|
||||
dead.add(ws)
|
||||
self.active_connections[user_id] -= dead
|
||||
if not self.active_connections[user_id]:
|
||||
del self.active_connections[user_id]
|
||||
|
||||
async def broadcast(self, message: dict):
|
||||
async with self._lock:
|
||||
dead: Dict[int, Set[WebSocket]] = {}
|
||||
for uid, sockets in self.active_connections.items():
|
||||
for ws in sockets:
|
||||
try:
|
||||
await ws.send_json(message)
|
||||
except Exception:
|
||||
dead.setdefault(uid, set()).add(ws)
|
||||
for uid, sockets in dead.items():
|
||||
self.active_connections[uid] -= sockets
|
||||
if not self.active_connections[uid]:
|
||||
del self.active_connections[uid]
|
||||
|
||||
async def broadcast_except(self, exclude_user_id: int, message: dict):
|
||||
async with self._lock:
|
||||
for uid, sockets in self.active_connections.items():
|
||||
if uid == exclude_user_id:
|
||||
continue
|
||||
for ws in sockets:
|
||||
try:
|
||||
await ws.send_json(message)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@property
|
||||
def online_count(self) -> int:
|
||||
"""Количество уникальных пользователей онлайн"""
|
||||
return len(self.active_connections)
|
||||
|
||||
|
||||
manager = ConnectionManager()
|
||||
|
||||
|
||||
# ─── Crash Game State ────────────────────────────────────────────────────────
|
||||
|
||||
class CrashGameState:
|
||||
def __init__(self):
|
||||
self.running = False
|
||||
self.current_multiplier = 1.0
|
||||
self.crash_point = 1.0
|
||||
self.bets: Dict[int, float] = {}
|
||||
self.cashed_out: Dict[int, float] = {}
|
||||
self.phase = "waiting"
|
||||
self.timer = 0
|
||||
self.round = 0
|
||||
self.history: list = []
|
||||
self._start_time = 0.0
|
||||
self._elapsed = 0.0
|
||||
|
||||
def generate_crash_point(self) -> float:
|
||||
"""True CS2-style provably fair crash point using exponential distribution"""
|
||||
# Используем распределение: чем выше множитель, тем меньше шанс
|
||||
r = random.random()
|
||||
# Формула: crash_point = 1 / (1 - r) с ограничением
|
||||
# Это даёт экспоненциальное распределение
|
||||
crash_point = 1.0 / (1.0 - r * 0.99)
|
||||
# В редких случаях может быть очень высоким (>1000), ограничиваем
|
||||
crash_point = min(crash_point, 1000.0)
|
||||
return round(crash_point, 2)
|
||||
|
||||
def get_multiplier_at_time(self, elapsed_seconds: float) -> float:
|
||||
"""Экспоненциальный рост множителя: e^(t * speed)"""
|
||||
speed = 0.08 # скорость роста
|
||||
return round(math.exp(elapsed_seconds * speed), 2)
|
||||
|
||||
def get_time_for_multiplier(self, mult: float) -> float:
|
||||
"""Сколько времени нужно для достижения множителя"""
|
||||
return math.log(mult) / 0.08
|
||||
|
||||
def calculate_payout(self, bet_amount: float, cashout_at: float) -> float:
|
||||
return round(bet_amount * cashout_at, 2)
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
"phase": self.phase,
|
||||
"round": self.round,
|
||||
"current_multiplier": self.current_multiplier,
|
||||
"crash_point": self.crash_point,
|
||||
"timer": self.timer,
|
||||
"bet_count": len(self.bets),
|
||||
"total_bets": sum(self.bets.values()),
|
||||
"cashed_out": {str(k): v for k, v in self.cashed_out.items()},
|
||||
"history": self.history[-20:],
|
||||
}
|
||||
|
||||
|
||||
crash_game = CrashGameState()
|
||||
Reference in New Issue
Block a user