Spaces:
Running
Running
| import os | |
| import time | |
| import engine_rust | |
| def run_battle(): | |
| # Load DB | |
| db_path = "data/cards_compiled.json" | |
| if not os.path.exists(db_path): | |
| print(f"Error: {db_path} not found") | |
| return | |
| with open(db_path, "r", encoding="utf-8") as f: | |
| db_json = f.read() | |
| db = engine_rust.PyCardDatabase(db_json) | |
| # Models | |
| models = { | |
| "Original (New)": "original", | |
| "Simple (Old)": "simple", | |
| } | |
| # Battle setup | |
| contestants = list(models.keys()) | |
| results = {c: {"wins": 0, "games": 0} for c in contestants} | |
| # Deck setup (Standard starter) | |
| lives0 = [30000, 30001, 30002] | |
| deck0 = [ | |
| 101, | |
| 102, | |
| 103, | |
| 104, | |
| 105, | |
| 106, | |
| 107, | |
| 108, | |
| 109, | |
| 110, | |
| 111, | |
| 112, | |
| 113, | |
| 114, | |
| 115, | |
| 116, | |
| 117, | |
| 118, | |
| 119, | |
| 120, | |
| ] + lives0 | |
| deck1 = deck0.copy() | |
| lives1 = lives0.copy() | |
| print(f"{'Battle':<20} | {'Winner':<20} | {'Duration'}") | |
| print("-" * 60) | |
| # Round robin (partial for speed, can adjust) | |
| for i in range(len(contestants)): | |
| for j in range(i + 1, len(contestants)): | |
| p0_name = contestants[i] | |
| p1_name = contestants[j] | |
| p0_agent = models[p0_name] | |
| p1_agent = models[p1_name] | |
| # Run 1 game | |
| start = time.time() | |
| game = engine_rust.PyGameState(db) | |
| game.initialize_game(deck0, deck1, [], [], lives0, lives1) | |
| step_count = 0 | |
| while not game.is_terminal() and step_count < 1000: | |
| curr_p = game.current_player | |
| phase = game.phase | |
| turn = game.turn | |
| agent_name = p0_name if curr_p == 0 else p1_name | |
| agent = p0_agent if curr_p == 0 else p1_agent | |
| print(f"\n{'=' * 40}") | |
| print(f"Step {step_count} | Turn {turn} | Player {curr_p} ({agent_name}) | Phase {phase}") | |
| # Show Legal Actions | |
| legal_ids = game.get_legal_action_ids() | |
| print(f" Legal Actions ({len(legal_ids)}): {legal_ids}") | |
| if phase in [-1, 0]: | |
| sel = game.get_player(curr_p).mulligan_selection | |
| print(f" Mulligan Selection Mask: {sel:016b}") | |
| if isinstance(agent, engine_rust.PyHybridMCTS): | |
| stats = agent.get_suggestions(game, 0, 0.5) | |
| else: | |
| stats = game.search_mcts(0, 0.5, agent) | |
| # Show Top 5 | |
| stats.sort(key=lambda x: x[2], reverse=True) | |
| print(" Top Actions (MCTS Visits/Score):") | |
| for act, score, visits in stats[:5]: | |
| print(f" - Action {act:<4}: Score {score:.4f}, Visits {visits}") | |
| # Trace Best Path (Next 3 steps) | |
| if stats and step_count % 10 == 0: | |
| print(" Predicted Best Path (Simulated):") | |
| try: | |
| # Attempt to use copy() or fallback to manual property copy | |
| if hasattr(game, "copy"): | |
| temp_game = game.copy() | |
| else: | |
| temp_game = engine_rust.PyGameState(db) | |
| temp_game.current_player = game.current_player | |
| temp_game.first_player = game.first_player | |
| temp_game.phase = game.phase | |
| temp_game.turn = game.turn | |
| temp_game.set_player(0, game.get_player(0)) | |
| temp_game.set_player(1, game.get_player(1)) | |
| path_str = [] | |
| trace_curr = temp_game | |
| for depth in range(3): | |
| p = trace_curr.current_player | |
| ph = trace_curr.phase | |
| t = trace_curr.turn | |
| # For the first step, use the MCTS top action | |
| if depth == 0: | |
| best_act = stats[0][0] | |
| else: | |
| # Quick MCTS search for lookahead (100 sims) | |
| t_stats = trace_curr.search_mcts(100, 0.0, "original") | |
| if not t_stats: | |
| break | |
| t_stats.sort(key=lambda x: x[2], reverse=True) | |
| best_act = t_stats[0][0] | |
| path_str.append(f"[T{t} P{p} Ph{ph} Act{best_act}]") | |
| trace_curr.step(best_act) | |
| if trace_curr.is_terminal(): | |
| break | |
| print(f" {' -> '.join(path_str)}") | |
| except Exception as e: | |
| print(f" (Path trace failed: {e})") | |
| action = stats[0][0] if stats else 0 | |
| game.step(action) | |
| step_count += 1 | |
| # Check for progress | |
| if step_count % 10 == 0: | |
| p0 = game.get_player(0) | |
| p1 = game.get_player(1) | |
| print( | |
| f"--- P0: Lives {len(p0.success_lives)}, Hand {len(p0.hand)} | P1: Lives {len(p1.success_lives)}, Hand {len(p1.hand)}" | |
| ) | |
| winner_idx = game.get_winner() | |
| winner_name = "Draw" | |
| if winner_idx == 0: | |
| winner_name = p0_name | |
| results[p0_name]["wins"] += 1 | |
| elif winner_idx == 1: | |
| winner_name = p1_name | |
| results[p1_name]["wins"] += 1 | |
| results[p0_name]["games"] += 1 | |
| results[p1_name]["games"] += 1 | |
| elapsed = time.time() - start | |
| print(f"{p0_name} vs {p1_name:<10} | {winner_name:<20} | {elapsed:.1f}s") | |
| print("\nFinal Scoreboard:") | |
| for name, stats in results.items(): | |
| wr = (stats["wins"] / stats["games"] * 100) if stats["games"] > 0 else 0 | |
| print(f"{name:<20}: {stats['wins']}/{stats['games']} ({wr:.1f}% Win Rate)") | |
| if __name__ == "__main__": | |
| run_battle() | |