diff --git a/backend/app/api/v1/wheel.py b/backend/app/api/v1/wheel.py index 27a45ca..012f99f 100644 --- a/backend/app/api/v1/wheel.py +++ b/backend/app/api/v1/wheel.py @@ -182,7 +182,7 @@ async def spin_wheel(marathon_id: int, current_user: CurrentUser, db: DbSession) await db.refresh(assignment) # Calculate drop penalty (considers active event for double_risk) - drop_penalty = points_service.calculate_drop_penalty(participant.drop_count, active_event) + drop_penalty = points_service.calculate_drop_penalty(participant.drop_count, challenge.points, active_event) # Get challenges count (avoid lazy loading in async context) challenges_count = 0 @@ -238,7 +238,7 @@ async def get_current_assignment(marathon_id: int, current_user: CurrentUser, db # Calculate drop penalty (considers active event for double_risk) active_event = await event_service.get_active_event(db, marathon_id) - drop_penalty = points_service.calculate_drop_penalty(participant.drop_count, active_event) + drop_penalty = points_service.calculate_drop_penalty(participant.drop_count, challenge.points, active_event) return AssignmentResponse( id=assignment.id, @@ -496,7 +496,7 @@ async def drop_assignment(assignment_id: int, current_user: CurrentUser, db: DbS active_event = await event_service.get_active_event(db, marathon_id) # Calculate penalty (0 if double_risk event is active) - penalty = points_service.calculate_drop_penalty(participant.drop_count, active_event) + penalty = points_service.calculate_drop_penalty(participant.drop_count, assignment.challenge.points, active_event) # Update assignment assignment.status = AssignmentStatus.DROPPED.value diff --git a/backend/app/services/gpt.py b/backend/app/services/gpt.py index 6d5aa99..36601b3 100644 --- a/backend/app/services/gpt.py +++ b/backend/app/services/gpt.py @@ -40,7 +40,7 @@ class GPTService: - description: что нужно сделать на русском (1-2 предложения) - type: один из [completion, no_death, speedrun, collection, achievement, challenge_run] - difficulty: easy/medium/hard -- points: очки (easy: 30-50, medium: 60-100, hard: 120-200) +- points: очки (easy: 20-40, medium: 45-75, hard: 90-150) - estimated_time: примерное время в минутах - proof_type: screenshot/video/steam (что лучше подойдёт для проверки) - proof_hint: что должно быть на скриншоте/видео для подтверждения на русском @@ -77,10 +77,17 @@ class GPTService: if proof_type not in ["screenshot", "video", "steam"]: proof_type = "screenshot" - # Validate points - points = ch.get("points", 50) + # Validate points based on difficulty + points = ch.get("points", 30) if not isinstance(points, int) or points < 1: - points = 50 + points = 30 + # Clamp points to expected ranges + if difficulty == "easy": + points = max(20, min(40, points)) + elif difficulty == "medium": + points = max(45, min(75, points)) + elif difficulty == "hard": + points = max(90, min(150, points)) challenges.append(ChallengeGenerated( title=ch.get("title", "Unnamed Challenge")[:100], diff --git a/backend/app/services/points.py b/backend/app/services/points.py index 62f4d1a..d16c1af 100644 --- a/backend/app/services/points.py +++ b/backend/app/services/points.py @@ -13,12 +13,12 @@ class PointsService: } MAX_STREAK_MULTIPLIER = 0.4 - DROP_PENALTIES = { - 0: 0, # First drop is free - 1: 10, - 2: 25, + # Drop penalty as percentage of challenge points + DROP_PENALTY_PERCENTAGES = { + 0: 0.5, # 1st drop: 50% + 1: 0.75, # 2nd drop: 75% } - MAX_DROP_PENALTY = 50 + MAX_DROP_PENALTY_PERCENTAGE = 1.0 # 3rd+ drop: 100% # Event point multipliers EVENT_MULTIPLIERS = { @@ -66,6 +66,7 @@ class PointsService: def calculate_drop_penalty( self, consecutive_drops: int, + challenge_points: int, event: Event | None = None ) -> int: """ @@ -73,6 +74,7 @@ class PointsService: Args: consecutive_drops: Number of drops since last completion + challenge_points: Base points of the challenge being dropped event: Active event (optional) Returns: @@ -82,10 +84,11 @@ class PointsService: if event and event.type == EventType.DOUBLE_RISK.value: return 0 - return self.DROP_PENALTIES.get( + penalty_percentage = self.DROP_PENALTY_PERCENTAGES.get( consecutive_drops, - self.MAX_DROP_PENALTY + self.MAX_DROP_PENALTY_PERCENTAGE ) + return int(challenge_points * penalty_percentage) def apply_event_multiplier(self, base_points: int, event: Event | None) -> int: """Apply event multiplier to points"""