Version 2.0.0: Animation fixes, timing improvements, and E2E test suite
Animation fixes: - Fix held card positioning bug (was appearing at bottom of page) - Fix discard pile blank/white flash on turn transitions - Fix blank card at round end by skipping animations during round_over/game_over - Set card content before triggering flip animation to prevent flash - Center suit symbol on 10 cards Timing improvements: - Reduce post-discard delay from 700ms to 500ms - Reduce post-swap delay from 1800ms to 1000ms - Speed up swap flip animation from 1150ms to 550ms - Reduce CPU initial thinking delay from 150-250ms to 80-150ms - Pause now happens after swap completes (showing result) instead of before E2E test suite: - Add Playwright-based test bot that plays full games - State parser extracts game state from DOM for validation - AI brain ports decision logic for automated play - Freeze detector monitors for UI hangs - Visual validator checks CSS states - Full game, stress, and visual test specs Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -19,7 +19,7 @@ from typing import Optional
|
||||
|
||||
from fastapi import WebSocket
|
||||
|
||||
from ai import assign_profile, assign_specific_profile, get_profile, release_profile
|
||||
from ai import assign_profile, assign_specific_profile, get_profile, release_profile, cleanup_room_profiles
|
||||
from game import Game, Player
|
||||
|
||||
|
||||
@@ -33,11 +33,12 @@ class RoomPlayer:
|
||||
in-game state like cards and scores.
|
||||
|
||||
Attributes:
|
||||
id: Unique player identifier.
|
||||
id: Unique player identifier (connection_id for multi-tab support).
|
||||
name: Display name.
|
||||
websocket: WebSocket connection (None for CPU players).
|
||||
is_host: Whether this player controls game settings.
|
||||
is_cpu: Whether this is an AI-controlled player.
|
||||
auth_user_id: Authenticated user ID for stats/limits (None for guests).
|
||||
"""
|
||||
|
||||
id: str
|
||||
@@ -45,6 +46,7 @@ class RoomPlayer:
|
||||
websocket: Optional[WebSocket] = None
|
||||
is_host: bool = False
|
||||
is_cpu: bool = False
|
||||
auth_user_id: Optional[str] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -73,6 +75,7 @@ class Room:
|
||||
player_id: str,
|
||||
name: str,
|
||||
websocket: WebSocket,
|
||||
auth_user_id: Optional[str] = None,
|
||||
) -> RoomPlayer:
|
||||
"""
|
||||
Add a human player to the room.
|
||||
@@ -80,9 +83,10 @@ class Room:
|
||||
The first player to join becomes the host.
|
||||
|
||||
Args:
|
||||
player_id: Unique identifier for the player.
|
||||
player_id: Unique identifier for the player (connection_id).
|
||||
name: Display name.
|
||||
websocket: The player's WebSocket connection.
|
||||
auth_user_id: Authenticated user ID for stats/limits (None for guests).
|
||||
|
||||
Returns:
|
||||
The created RoomPlayer object.
|
||||
@@ -93,6 +97,7 @@ class Room:
|
||||
name=name,
|
||||
websocket=websocket,
|
||||
is_host=is_host,
|
||||
auth_user_id=auth_user_id,
|
||||
)
|
||||
self.players[player_id] = room_player
|
||||
|
||||
@@ -117,9 +122,9 @@ class Room:
|
||||
The created RoomPlayer, or None if profile unavailable.
|
||||
"""
|
||||
if profile_name:
|
||||
profile = assign_specific_profile(cpu_id, profile_name)
|
||||
profile = assign_specific_profile(cpu_id, profile_name, self.code)
|
||||
else:
|
||||
profile = assign_profile(cpu_id)
|
||||
profile = assign_profile(cpu_id, self.code)
|
||||
|
||||
if not profile:
|
||||
return None
|
||||
@@ -157,9 +162,9 @@ class Room:
|
||||
room_player = self.players.pop(player_id)
|
||||
self.game.remove_player(player_id)
|
||||
|
||||
# Release CPU profile back to the pool
|
||||
# Release CPU profile back to the room's pool
|
||||
if room_player.is_cpu:
|
||||
release_profile(room_player.name)
|
||||
release_profile(room_player.name, self.code)
|
||||
|
||||
# Assign new host if needed
|
||||
if room_player.is_host and self.players:
|
||||
|
||||
Reference in New Issue
Block a user