Spaces:
Sleeping
Sleeping
File size: 5,909 Bytes
0dd780c |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
import json
import os
import sys
# Add project root to path
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
import engine_rust
from ai.utils.benchmark_decks import parse_deck
from engine.game.data_loader import CardDataLoader # Only for descriptions
from engine.game.desc_utils import get_action_desc
from engine.game.game_state import GameState # Only for descriptions
def verify_abilities():
print("--- AI Ability Visibility Verification (Rust Engine) ---")
# 1. Load DB
db_path = "engine/data/cards_compiled.json"
with open(db_path, "r", encoding="utf-8") as f:
db_content = f.read()
db_json = json.loads(db_content)
# Initialize Python GameState for descriptions
loader = CardDataLoader(db_path)
members, lives, energy = loader.load()
GameState.initialize_class_db(members, lives)
py_gs = GameState()
# 2. Setup Rust Engine State
db = engine_rust.PyCardDatabase(db_content)
gs = engine_rust.PyGameState(db)
# Load a benchmark deck to get valid IDs
deck_file = "ai/decks/liella_cup.txt"
main_deck, lives_deck, energy_deck = parse_deck(
deck_file, db_json["member_db"], db_json["live_db"], db_json.get("energy_db", {})
)
# Standard sizes
test_lives = (lives_deck * 10)[:12]
test_deck = (main_deck * 10)[:48]
test_energy = (energy_deck * 10)[:12]
gs.initialize_game(test_deck, test_deck, test_energy, test_energy, test_lives, test_lives)
# Fast-forward to Main Phase
# Phase Flow: MULLIGAN_P1 -> MULLIGAN_P2 -> LIVE_SET -> MAIN
print(f"Skipping Mulligan P1 (Current: {gs.phase})...")
gs.step(0) # Confirm Mulligan P1
print(f"Skipping Mulligan P2 (Current: {gs.phase})...")
gs.step(0) # Confirm Mulligan P2
# In Live Set, we need to set a card.
# Actions 400-459 are Live Set.
# Player 1 (index 0) sets a card.
print(f"Setting Live Card (Current: {gs.phase})...")
gs.step(400) # Set first card in hand as live
# Player 2 (index 1) sets a card.
gs.step(400)
# Sync Python GS for descriptions
hand = list(gs.get_player(0).hand)
py_gs.players[0].hand = hand
py_gs.current_player = gs.current_player
py_gs.phase = gs.phase
# 3. Find or Inject Ability Card
ability_card_id = -1
hand_idx = -1
for i, cid in enumerate(hand):
if cid in members:
card = members[cid]
# Check for ACTIVATED trigger
if any(ab.trigger.name == "ACTIVATED" for ab in card.abilities):
ability_card_id = cid
hand_idx = i
break
# Sync Python GS for descriptions
hand = list(gs.get_player(0).hand)
py_gs.players[0].hand = hand
py_gs.current_player = gs.current_player
py_gs.phase = gs.phase
# 3. Inject and Play Ability Card (Keke ID 247)
target_cid = 247
print(f"Injecting Card ID {target_cid} into hand...")
# Update Rust State
gs.get_player(0).hand = [target_cid] + list(gs.get_player(0).hand)
# Update Python Stage for get_action_desc
py_gs.players[0].hand = [target_cid] + list(py_gs.players[0].hand)
# Check if card has an activated ability in py_gs
card = members[target_cid]
abs = [ab for ab in card.abilities if ab.trigger.name == "ACTIVATED"]
print(f"Card {card.name} has {len(abs)} activated abilities.")
for ab in abs:
print(f" - Ability: {ab.raw_text}")
print(f"Playing {get_action_desc(500, py_gs)} to Center...")
# Action ID 2 (Hand 0 to Center)
gs.step(2)
# Update Python Stage
py_gs.players[0].stage[1] = target_cid
py_gs.players[0].hand = list(gs.get_player(0).hand)
# Check legality
def check_legal(gs, py_gs):
legal_actions = list(gs.get_legal_action_ids())
print(f"Phase: {gs.phase} | Legal IDs: {len(legal_actions)}")
if 201 in legal_actions:
print("SUCCESS: Action 201 (Center Ability) is legal.")
return True
print("Action 201 is NOT legal.")
if len(legal_actions) < 20: # Show only if list is small
for a in legal_actions:
print(f" - Action {a}: {get_action_desc(a, py_gs)}")
return False
if not check_legal(gs, py_gs):
print("Skipping to next turn's Main Phase...")
# Finish Turn 1
gs.step(0) # End Main
gs.step(0) # End Live Start
gs.step(0) # End Live Set
gs.step(0) # End Performance
gs.step(0) # End Turn
# Turn 2
gs.step(0) # End Active/Standby
gs.step(0) # End Draw
# Now we should be in Turn 2 Main Phase
# Re-sync Python GS
py_gs.phase = gs.phase
py_gs.current_player = gs.current_player
check_legal(gs, py_gs)
# 4. Run MCTS
model_path = "ai/models/alphanet_best.onnx"
mcts = engine_rust.PyHybridMCTS(model_path, 0.0)
print("\nRunning MCTS (1600 sims)...")
suggestions = mcts.get_suggestions(gs, 1600)
print("\nTop MCTS Suggestions:")
for action_id, score, visits in sorted(suggestions, key=lambda x: x[2], reverse=True)[:10]:
desc = get_action_desc(int(action_id), py_gs)
print(f" Action {action_id:4}: {visits:5} visits | {score:.4f} score | {desc}")
# 5. Final confirmation
ability_actions = [a for (a, s, v) in suggestions if 200 <= a <= 202]
if ability_actions:
print(f"\nCONFIRMED: MCTS explored ability actions: {[int(a) for a in ability_actions]}")
for a in ability_actions:
print(f" - {get_action_desc(int(a), py_gs)}")
else:
print("\nISSUE: MCTS did NOT explore ability actions.")
if __name__ == "__main__":
verify_abilities()
|