This commit is contained in:
Nikolaj
2026-03-19 14:53:33 +01:00
parent cf9176edbd
commit 0de769284c
6 changed files with 399 additions and 95 deletions

View File

@@ -14,11 +14,10 @@ from game import (
)
from models import Card as CardModel, Deck as DeckModel, DeckCard as DeckCardModel, User as UserModel
from card import compute_deck_type
from ai import AI_USER_ID, run_ai_turn, get_random_personality, choose_cards
logger = logging.getLogger("app")
AI_USER_ID = "ai"
## Storage
active_games: dict[str, GameState] = {}
@@ -376,15 +375,22 @@ def create_solo_game(
player_cards: list,
ai_cards: list,
deck_id: str,
difficulty: int = 5,
) -> str:
ai_personality = get_random_personality()
ai_deck = choose_cards(ai_cards, difficulty, ai_personality)
player_deck_type = compute_deck_type(player_cards) or "Balanced"
ai_deck_type = compute_deck_type(ai_cards) or "Balanced"
ai_deck_type = compute_deck_type(ai_deck) or "Balanced"
state = create_game(
user_id, username, player_deck_type, player_cards,
AI_USER_ID, "Computer", ai_deck_type, ai_cards,
AI_USER_ID, "Computer", ai_deck_type, ai_deck,
)
state.ai_difficulty = difficulty
state.ai_personality = ai_personality.value
active_games[state.game_id] = state
connections[state.game_id] = {}
active_deck_ids[user_id] = deck_id
@@ -422,86 +428,3 @@ def calculate_combat_animation_time(events: list[CombatEvent]) -> float:
total += ANIMATION_DELAYS["post_combat_buffer"]
return total
async def run_ai_turn(game_id: str):
state = active_games.get(game_id)
if not state or state.result:
return
if state.active_player_id != AI_USER_ID:
return
human_id = state.opponent_id(AI_USER_ID)
waited = 0
while not connections[game_id].get(human_id) and waited < 10:
await asyncio.sleep(0.5)
waited += 0.5
await asyncio.sleep(calculate_combat_animation_time(state.last_combat_events))
player = state.players[AI_USER_ID]
ws = connections[game_id].get(human_id)
async def send_state(state: GameState):
if ws:
try:
await ws.send_json({
"type": "state",
"state": serialize_state(state, human_id),
})
except Exception:
pass
most_expensive_in_hand = max((c.cost for c in player.hand), default=0)
if player.energy < most_expensive_in_hand:
for slot in range(BOARD_SIZE):
slot_card = player.board[slot]
if slot_card is not None and player.energy + slot_card.cost <= most_expensive_in_hand:
if ws:
try:
await ws.send_json({
"type": "sacrifice_animation",
"instance_id": slot_card.instance_id,
})
except Exception:
pass
await asyncio.sleep(0.65)
action_sacrifice(state, slot)
await send_state(state)
await asyncio.sleep(0.35)
play_order = list(range(BOARD_SIZE))
random.shuffle(play_order)
for slot in play_order:
if player.board[slot] is not None:
continue
affordable = [i for i, c in enumerate(player.hand) if c.cost <= player.energy]
if not affordable:
break
best = max(affordable, key=lambda i: player.hand[i].cost)
action_play_card(state, best, slot)
await send_state(state)
await asyncio.sleep(0.5)
action_end_turn(state)
await send_state(state)
if state.result:
from database import SessionLocal
db = SessionLocal()
try:
record_game_result(state, db)
if ws:
await ws.send_json({
"type": "state",
"state": serialize_state(state, human_id),
})
finally:
db.close()
active_deck_ids.pop(human_id, None)
active_deck_ids.pop(AI_USER_ID, None)
active_games.pop(game_id, None)
connections.pop(game_id, None)
return
if state.active_player_id == AI_USER_ID:
asyncio.create_task(run_ai_turn(game_id))