|
| 1 | +""" |
| 2 | +Lightweight agent-versus-agent runner using shared utilities. |
| 3 | +
|
| 4 | +This script used to duplicate play/timing logic; it now delegates to |
| 5 | +`scripts.agent_utils` to keep behavior consistent with other scripts. |
| 6 | +""" |
1 | 7 | import argparse |
2 | 8 | import chess |
3 | | -import time |
4 | | -from src.agents.base_agent import BaseAgent |
5 | | -from src.agents import MinimaxAgent, AlphaBetaAgent, ExpectimaxAgent |
6 | | -from evaluation import evaluate |
7 | | - |
8 | | - |
9 | | -def play_single_game(white_agent: BaseAgent, black_agent: BaseAgent, timeout_seconds: int = 120): |
10 | | - """ |
11 | | - Play one game between agents with a hard timeout and move-time tracking. |
12 | | - Returns: |
13 | | - result (str): "white", "black", "draw", or "timeout" |
14 | | - white_avg (float) |
15 | | - black_avg (float) |
16 | | - """ |
17 | | - board = chess.Board() |
18 | | - |
19 | | - white_times = [] |
20 | | - black_times = [] |
21 | | - |
22 | | - start_game_time = time.time() |
23 | | - |
24 | | - while not board.is_game_over(): |
25 | | - # Hard 2 minute timeout |
26 | | - if time.time() - start_game_time > timeout_seconds: |
27 | | - print("Game terminated due to timeout.") |
28 | | - return "timeout", 0, 0 |
29 | | - |
30 | | - current_agent = white_agent if board.turn == chess.WHITE else black_agent |
31 | | - |
32 | | - move_start = time.time() |
33 | | - print(f"{current_agent}") |
34 | | - move = current_agent.choose_move(board) |
35 | | - move_end = time.time() |
36 | | - |
37 | | - if move is None: |
38 | | - print("Error: Agent returned None move.") |
39 | | - return "error", 0, 0 |
40 | | - |
41 | | - # Track move time |
42 | | - if board.turn == chess.WHITE: |
43 | | - white_times.append(move_end - move_start) |
44 | | - else: |
45 | | - black_times.append(move_end - move_start) |
46 | | - |
47 | | - board.push(move) |
48 | | - |
49 | | - # Compute averages |
50 | | - white_avg = sum(white_times) / len(white_times) if white_times else 0 |
51 | | - black_avg = sum(black_times) / len(black_times) if black_times else 0 |
52 | | - |
53 | | - # Determine outcome |
54 | | - if board.is_checkmate(): |
55 | | - winner = "white" if board.turn == chess.BLACK else "black" |
56 | | - else: |
57 | | - winner = "draw" |
58 | | - |
59 | | - return winner, white_avg, black_avg |
60 | | - |
61 | | - |
62 | | -def make_agents_play(white_agent: BaseAgent, black_agent: BaseAgent, iterations: int): |
63 | | - """ |
64 | | - Run `iterations` number of games and report average move times. |
65 | | - """ |
66 | | - white_avg_list = [] |
67 | | - black_avg_list = [] |
68 | | - |
69 | | - for game_idx in range(1, iterations + 1): |
70 | | - print(f"\n=== Starting Game {game_idx}/{iterations} ===") |
71 | | - result, w_avg, b_avg = play_single_game(white_agent, black_agent) |
72 | | - |
73 | | - print(f"Game {game_idx} result: {result}") |
74 | | - print(f" White ({white_agent.name}) avg move time: {w_avg:.4f} sec") |
75 | | - print(f" Black({black_agent.name}) avg move time: {b_avg:.4f} sec") |
76 | | - |
77 | | - white_avg_list.append(w_avg) |
78 | | - black_avg_list.append(b_avg) |
79 | | - |
80 | | - print("\n===== FINAL RESULTS ACROSS ALL GAMES =====") |
81 | | - print(f"{white_agent.name} mean move time: {sum(white_avg_list)/iterations:.4f} sec") |
82 | | - print(f"{black_agent.name} mean move time: {sum(black_avg_list)/iterations:.4f} sec") |
| 9 | +from scripts.agent_utils import create_agent, play_single_game_with_stats |
83 | 10 |
|
84 | 11 |
|
85 | 12 | def main(): |
86 | | - parser = argparse.ArgumentParser(description="Play chess with agents") |
87 | | - parser.add_argument( |
88 | | - "--white-agent", |
89 | | - choices=["minimax", "alphabeta", "expectimax"], |
90 | | - default="minimax", |
91 | | - ) |
92 | | - parser.add_argument( |
93 | | - "--black-agent", |
94 | | - choices=["minimax", "alphabeta", "expectimax"], |
95 | | - default="alphabeta", |
96 | | - ) |
97 | | - parser.add_argument( |
98 | | - "--depth", |
99 | | - type=int, |
100 | | - default=3, |
101 | | - choices=[2, 3, 4, 5], |
102 | | - help="Search depth for AI agents (default: 3)", |
103 | | - ) |
104 | | - parser.add_argument( |
105 | | - "--num-games", |
106 | | - type=int, |
107 | | - default=1, |
108 | | - help="Number of games to run (default: 1)" |
109 | | - ) |
| 13 | + parser = argparse.ArgumentParser(description="Play games between two agents") |
| 14 | + parser.add_argument("--white-agent", default="minimax", help="Agent key for White") |
| 15 | + parser.add_argument("--black-agent", default="alphabeta", help="Agent key for Black") |
| 16 | + parser.add_argument("--depth", type=int, default=3, help="Default search depth for search agents") |
| 17 | + parser.add_argument("--num-games", type=int, default=1, help="Number of games to run") |
| 18 | + parser.add_argument("--vi-iterations", type=int, default=3, help="ValueIteration iterations") |
| 19 | + parser.add_argument("--q-train", type=int, default=0, help="QLearning training episodes") |
| 20 | + parser.add_argument("--q-epsilon", type=float, default=0.0, help="QLearning epsilon during matches") |
110 | 21 | args = parser.parse_args() |
111 | 22 |
|
112 | | - def create_agent(agent_type, color): |
113 | | - if agent_type == "minimax": |
114 | | - return MinimaxAgent(evaluate, depth=args.depth, name="Minimax", color=color) |
115 | | - elif agent_type == "alphabeta": |
116 | | - return AlphaBetaAgent(evaluate, depth=args.depth, name="AlphaBeta", color=color) |
117 | | - elif agent_type == "expectimax": |
118 | | - return ExpectimaxAgent(evaluate, depth=args.depth, name="Expectimax", color=color) |
119 | | - raise RuntimeError("Invalid agent type") |
| 23 | + white = create_agent(args.white_agent, chess.WHITE, depth=args.depth, vi_iterations=args.vi_iterations, q_numTraining=args.q_train, q_epsilon=args.q_epsilon) |
| 24 | + black = create_agent(args.black_agent, chess.BLACK, depth=args.depth, vi_iterations=args.vi_iterations, q_numTraining=args.q_train, q_epsilon=args.q_epsilon) |
| 25 | + |
| 26 | + print(f"Running {args.num_games} games: White={white}, Black={black}") |
| 27 | + |
| 28 | + white_times = [] |
| 29 | + black_times = [] |
120 | 30 |
|
121 | | - white_agent = create_agent(args.white_agent, chess.WHITE) |
122 | | - black_agent = create_agent(args.black_agent, chess.BLACK) |
| 31 | + for i in range(1, args.num_games + 1): |
| 32 | + print(f"\n=== Game {i}/{args.num_games} ===") |
| 33 | + result = play_single_game_with_stats(white, black) |
| 34 | + print(f"Result: {result}") |
123 | 35 |
|
124 | | - print(f"Running {args.num_games} games:") |
125 | | - print(f" White = {white_agent.name}") |
126 | | - print(f" Black = {black_agent.name}") |
127 | 36 |
|
128 | | - make_agents_play(white_agent, black_agent, iterations=args.num_games) |
| 37 | + if white_times: |
| 38 | + print(f"\nWhite mean move time: {sum(white_times)/len(white_times):.4f}s") |
| 39 | + if black_times: |
| 40 | + print(f"Black mean move time: {sum(black_times)/len(black_times):.4f}s") |
129 | 41 |
|
130 | 42 |
|
131 | 43 | if __name__ == "__main__": |
|
0 commit comments