Xiangiqgame
AI engine for Xiangqi
Loading...
Searching...
No Matches
game_summary_plot_manager.py
Go to the documentation of this file.
1"""
2Contains the GameSummaryPlotManager class.
3"""
4
5from pathlib import Path
6
7import matplotlib.pyplot as plt
8import numpy as np
9from matplotlib.gridspec import GridSpec
10import xiangqi_bindings as bindings
11
12from xiangqipy.game_summary import GameSummary
13from xiangqipy.game_summary_io import import_game_summary
15 SearchResultsByTypePlotter,
16 SearchTimePlotter,
17 EvalScorePlotter,
18)
19
20
22 """
23 Manages the layout and file output of a figure containing multiple
24 plots of data from a GameSummary.
25 """
26 def __init__(self, game_summary: GameSummary, save_fig: bool = False):
27 plt.style.use("bmh")
28 self.game_summary = game_summary
29 self.save_fig = save_fig
30 self.fig = plt.figure(figsize=(12, 19), dpi=150)
31 self.search_type_plots = np.empty(
32 shape=(2, self.num_players_with_minimax_data), dtype=object
33 )
34 self.search_time_plots = np.empty(
35 shape=(2, self.num_players_with_minimax_data), dtype=object
36 )
37 self.eval_score_plots = np.empty(
38 shape=(1, self.num_players_with_minimax_data), dtype=object
39 )
40 self.gs = GridSpec(
41 nrows=8,
43 figure=self.fig,
44 height_ratios=[0.89, 1, 1, 0.7, 1, 1, 0.55, 1],
45 )
46 self.build_layout()
47
48 def has_minimax_data(self, player: bindings.PieceColor) -> bool:
49 return self.game_summary.get_player_summary(
50 player=player
51 ).has_search_summaries
52
53 @property
55 return sum(
56 [
57 int(self.has_minimax_data(player=bindings.PieceColor.kRed)),
58 int(self.has_minimax_data(player=bindings.PieceColor.kBlk)),
59 ]
60 )
61
62 def build_layout(self):
63 for gs_row in range(1, 3):
64 for gs_col in range(self.num_players_with_minimax_data):
65 self.search_type_plots[gs_row - 1, gs_col] = (
66 self.fig.add_subplot(
67 self.gs[gs_row, gs_col],
68 )
69 )
70
71 for gs_row in range(4, 6):
72 for gs_col in range(self.num_players_with_minimax_data):
73 self.search_time_plots[gs_row - 4, gs_col] = (
74 self.fig.add_subplot(
75 self.gs[gs_row, gs_col],
76 )
77 )
78
79 for gs_row in range(7, 8):
80 for gs_col in range(self.num_players_with_minimax_data):
81 self.eval_score_plots[gs_row - 7, gs_col] = (
82 self.fig.add_subplot(
83 self.gs[gs_row, gs_col],
84 )
85 )
86
87 plt.subplots_adjust(
88 left=0.08,
89 right=0.73,
90 top=0.89,
91 bottom=0.05,
92 hspace=0.075,
93 wspace=0.075,
94 )
95
96 self.fig.text(
97 x=0.05,
98 y=0.97,
99 s=f"Summary plots for Game ID # {self.game_summary.game_id}",
100 fontsize=22,
101 )
102
103 self.fig.text(
104 x=0.05,
105 y=0.85,
106 s=f"RED player type: {self.game_summary.get_player_summary(bindings.PieceColor.kRed).player_type}\n"
107 f"RED max search depth: {self.game_summary.get_player_summary(bindings.PieceColor.kRed).max_search_depth}\n"
108 f"RED Zobrist key size: {self.game_summary.get_player_summary(bindings.PieceColor.kRed).zobrist_key_size} bits\n\n"
109 f"BLACK player type: {self.game_summary.get_player_summary(bindings.PieceColor.kBlk).player_type}\n"
110 f"BLACK max search depth: {self.game_summary.get_player_summary(bindings.PieceColor.kBlk).max_search_depth}\n"
111 f"BLACK Zobrist key size: {self.game_summary.get_player_summary(bindings.PieceColor.kBlk).zobrist_key_size} bits\n\n"
112 f"Result = {self.game_summary.game_state.name}",
113 fontsize=14,
114 )
115
116 self.fig.add_artist(
117 plt.Line2D(
118 [0.05, 0.95],
119 [0.83, 0.83],
120 transform=self.fig.transFigure,
121 color="black",
122 )
123 )
124
125 self.fig.text(
126 x=0.05,
127 y=0.81,
128 s="Minimax Node Counts by Search Result Type",
129 fontsize=18,
130 )
131
132 self.fig.add_artist(
133 plt.Line2D(
134 [0.05, 0.95],
135 [0.51, 0.51],
136 transform=self.fig.transFigure,
137 color="black",
138 )
139 )
140
141 self.fig.text(
142 x=0.05,
143 y=0.49,
144 s="Move Selection Time",
145 fontsize=18,
146 )
147
148 self.fig.add_artist(
149 plt.Line2D(
150 [0.05, 0.95],
151 [0.19, 0.19],
152 transform=self.fig.transFigure,
153 color="black",
154 )
155 )
156
157 self.fig.text(
158 x=0.05,
159 y=0.17,
160 s="Minimax Evaulation Scores",
161 fontsize=18,
162 )
163
164 def save_figure(self, path: Path):
165 if path.exists():
166 raise FileExistsError(f"{path} already exists")
167 path.parent.mkdir(parents=True, exist_ok=True)
168 plt.savefig(str(path), dpi=self.fig.dpi)
169 print(f"Plots of summary data saved to:\n{str(path.resolve())}")
170
171 def plot(
172 self,
173 show_plot: bool = True
174 ):
175 search_results_by_type_plotter = SearchResultsByTypePlotter(
176 axes=self.search_type_plots,
177 red_data=self.game_summary.get_player_summary(
178 player=bindings.PieceColor.kRed
179 ).first_searches_by_type,
180 black_data=self.game_summary.get_player_summary(
181 player=bindings.PieceColor.kBlk
182 ).first_searches_by_type,
183 )
184 search_results_by_type_plotter.plot()
185
186 search_time_plotter = SearchTimePlotter(
187 axes=self.search_time_plots,
188 red_data=self.game_summary.get_player_summary(
189 player=bindings.PieceColor.kRed
190 ).first_search_stats,
191 black_data=self.game_summary.get_player_summary(
192 player=bindings.PieceColor.kBlk
193 ).first_search_stats,
194 )
195 search_time_plotter.plot()
196
197 eval_score_plotter = EvalScorePlotter(
198 axes=self.eval_score_plots,
199 red_data=self.game_summary.get_player_summary(
200 player=bindings.PieceColor.kRed
201 ).first_search_stats,
202 black_data=self.game_summary.get_player_summary(
203 player=bindings.PieceColor.kBlk
204 ).first_search_stats,
205 add_plot_column_titles=False,
206 )
207 eval_score_plotter.plot()
208
209 if show_plot:
210 plt.show()
211
212
213if __name__ == "__main__":
214
215 my_game_summary_path = (
216 Path(__file__).parent.parent.parent
217 / "data"
218 / "game_summaries"
219 / "20241108172951135840-test"
220 / "20241108172951135840.json"
221 )
222
223 my_game_summary = import_game_summary(path=my_game_summary_path)
224 plot_manager = GameSummaryPlotManager(game_summary=my_game_summary)
225 plot_manager.plot(show_plot=True)
Manages the layout and file output of a figure containing multiple plots of data from a GameSummary.
def __init__(self, GameSummary game_summary, bool save_fig=False)
Implements GameSummaryPlotter, and plots evaluated score of each move of each Player using a Minimax ...
Implements GameSummaryPlotter, and produces stacked plots of Minimax search result counts grouped by ...
Implements GameSummaryPlotter, and produces plots showing time spent by core MinimaxMoveEvaluator(s) ...
Contains functions for importing / exporting a GameSummary from / to .json file.
Contains the GameSummaryPlotter abstract base class, and multiple subclasses that implement it.
GameSummary class and its component classes.
Definition: game_summary.py:1