import random import math from datetime import datetime from sqlalchemy import select from sqlalchemy.orm import Session from sqlalchemy.ext.asyncio import AsyncSession from database import User, UpgradeRPU, Upgrade MAX_WIN_STREAK = 3 MAX_LOSE_STREAK = 5 def get_upgrade_rpu(db: Session, user_id: int) -> UpgradeRPU: rpu = db.query(UpgradeRPU).filter(UpgradeRPU.user_id == user_id).first() if not rpu: rpu = UpgradeRPU(user_id=user_id) db.add(rpu) from rpu import _rpu_commit_or_flush _rpu_commit_or_flush(db) db.refresh(rpu) return rpu async def get_upgrade_rpu_async(db: AsyncSession, user_id: int) -> UpgradeRPU: result = await db.execute(select(UpgradeRPU).where(UpgradeRPU.user_id == user_id)) rpu = result.scalar_one_or_none() if not rpu: rpu = UpgradeRPU(user_id=user_id) db.add(rpu) from rpu import _rpu_commit_or_flush_async await _rpu_commit_or_flush_async(db) await db.refresh(rpu) return rpu def calculate_upgrade_probability(input_price: float, target_price: float) -> float: if input_price <= 0 or target_price <= 0: return 50.0 if target_price <= input_price: return -1.0 probability = (input_price / target_price) * 100 return max(1.0, min(75.0, probability)) def get_adjusted_upgrade_probability(db: Session, user_id: int, base_probability: float) -> float: if base_probability < 0: return -1.0 rpu = get_upgrade_rpu(db, user_id) adjusted = base_probability * rpu.upgrade_multiplier if rpu.current_win_streak >= MAX_WIN_STREAK: penalty = (rpu.current_win_streak - MAX_WIN_STREAK + 1) * 0.15 adjusted *= (1.0 - penalty) elif rpu.current_lose_streak >= MAX_LOSE_STREAK: boost = (rpu.current_lose_streak - MAX_LOSE_STREAK + 1) * 0.2 adjusted *= (1.0 + boost) return max(1.0, min(75.0, adjusted)) async def get_adjusted_upgrade_probability_async(db: AsyncSession, user_id: int, base_probability: float) -> float: if base_probability < 0: return -1.0 rpu = await get_upgrade_rpu_async(db, user_id) adjusted = base_probability * rpu.upgrade_multiplier if rpu.current_win_streak >= MAX_WIN_STREAK: penalty = (rpu.current_win_streak - MAX_WIN_STREAK + 1) * 0.15 adjusted *= (1.0 - penalty) elif rpu.current_lose_streak >= MAX_LOSE_STREAK: boost = (rpu.current_lose_streak - MAX_LOSE_STREAK + 1) * 0.2 adjusted *= (1.0 + boost) return max(1.0, min(75.0, adjusted)) def spin_upgrade_wheel(success_probability: float) -> tuple[bool, float, int, float]: raw_angle = random.uniform(0, 360) half_green = (success_probability / 100) * 180 success = 180 - half_green <= raw_angle <= 180 + half_green margin = max(3, half_green * 0.12) if success: rotations = random.randint(7, 9) lo = max(0, 180 - half_green + margin) hi = min(360, 180 + half_green - margin) target_angle = random.uniform(lo, hi) if lo < hi else random.uniform( max(0, 180 - half_green + 1), min(360, 180 + half_green - 1)) else: rotations = random.randint(6, 8) left_size = max(0, 180 - half_green - 3) right_start = min(360, 180 + half_green + 3) right_size = max(0, 360 - right_start) lo, hi = (0, max(0, 180 - half_green - 3)) if left_size >= right_size else (min(360, 180 + half_green + 3), 360) target_angle = random.uniform(lo, hi) if lo < hi else random.uniform(min(360, 180 + half_green + 3), 360) final_angle = target_angle + rotations * 360 return success, final_angle, rotations, raw_angle def update_upgrade_stats(db: Session, user_id: int, success: bool, input_price: float): rpu = get_upgrade_rpu(db, user_id) rpu.total_attempts += 1 if success: rpu.total_success += 1 rpu.current_win_streak += 1 rpu.current_lose_streak = 0 if rpu.current_win_streak > rpu.best_win_streak: rpu.best_win_streak = rpu.current_win_streak else: rpu.total_spent_value += input_price rpu.current_lose_streak += 1 rpu.current_win_streak = 0 if rpu.current_lose_streak > rpu.worst_lose_streak: rpu.worst_lose_streak = rpu.current_lose_streak if rpu.auto_adjust and rpu.total_attempts >= 10: if rpu.current_win_streak >= MAX_WIN_STREAK: rpu.upgrade_multiplier = max(0.3, rpu.upgrade_multiplier - 0.15) if rpu.current_lose_streak >= MAX_LOSE_STREAK: rpu.upgrade_multiplier = min(2.5, rpu.upgrade_multiplier + 0.2) rate = rpu.total_success / rpu.total_attempts if rate < 0.2: rpu.upgrade_multiplier = min(2.5, rpu.upgrade_multiplier + 0.1) elif rate > 0.6: rpu.upgrade_multiplier = max(0.3, rpu.upgrade_multiplier - 0.1) from rpu import _rpu_commit_or_flush _rpu_commit_or_flush(db) async def update_upgrade_stats_async(db: AsyncSession, user_id: int, success: bool, input_price: float): rpu = await get_upgrade_rpu_async(db, user_id) rpu.total_attempts += 1 if success: rpu.total_success += 1 rpu.current_win_streak += 1 rpu.current_lose_streak = 0 if rpu.current_win_streak > rpu.best_win_streak: rpu.best_win_streak = rpu.current_win_streak else: rpu.total_spent_value += input_price rpu.current_lose_streak += 1 rpu.current_win_streak = 0 if rpu.current_lose_streak > rpu.worst_lose_streak: rpu.worst_lose_streak = rpu.current_lose_streak if rpu.auto_adjust and rpu.total_attempts >= 10: if rpu.current_win_streak >= MAX_WIN_STREAK: rpu.upgrade_multiplier = max(0.3, rpu.upgrade_multiplier - 0.15) if rpu.current_lose_streak >= MAX_LOSE_STREAK: rpu.upgrade_multiplier = min(2.5, rpu.upgrade_multiplier + 0.2) rate = rpu.total_success / rpu.total_attempts if rate < 0.2: rpu.upgrade_multiplier = min(2.5, rpu.upgrade_multiplier + 0.1) elif rate > 0.6: rpu.upgrade_multiplier = max(0.3, rpu.upgrade_multiplier - 0.1) from rpu import _rpu_commit_or_flush_async await _rpu_commit_or_flush_async(db)