Xiangiqgame
AI engine for Xiangqi
Loading...
Searching...
No Matches
terminal_output.py
Go to the documentation of this file.
1"""
2Classes for terminal UI output including board representation and, messages
3requesting info, and status messages.
4"""
5
6import os
7import colorama as cr
8import subprocess
9from dataclasses import dataclass
10from typing import Dict
11
13from xiangqi_bindings import (
14 GameBoard,
15 GamePiece,
16 Move,
17 opponent_of,
18 PieceColor,
19 PieceType,
20)
21from xiangqipy.game_interfaces import MoveReporter
22from xiangqipy.enums import GameState, EvaluatorType
23from xiangqipy.player_summary import PlayerSummary
24
25
26@dataclass
28 """
29 Provides messages requesting input from a Player.
30 """
31 input_prompt: str = "Enter a move in the form 'from_space, to_space': "
32 invalid_input_msg: str = "Invalid input"
33 illegal_move_msg: str = "Illegal move. Please enter a different move."
34
36 print(self.invalid_input_msg)
37
39 print(self.illegal_move_msg)
40
41
43 """
44 Outputs a text-base game board with GamePiece locations in algebraic
45 notation.
46 """
47
48 _disp_format = {
49 PieceColor.kRed: cr.Style.BRIGHT + cr.Fore.WHITE + cr.Back.RED,
50 PieceColor.kBlk: cr.Style.BRIGHT + cr.Fore.BLACK + cr.Back.WHITE,
51 PieceColor.kNul: cr.Fore.RESET + cr.Back.RESET,
52 }
53
54 _display_team_name = {PieceColor.kRed: "Red", PieceColor.kBlk: "Black"}
55
56 _color_to_code = {
57 PieceColor.kRed: "r",
58 PieceColor.kBlk: "b",
59 PieceColor.kNul: "-",
60 }
61
62 _type_to_code = {
63 PieceType.kCha: "R",
64 PieceType.kHor: "H",
65 PieceType.kEle: "E",
66 PieceType.kAdv: "A",
67 PieceType.kGen: "G",
68 PieceType.kCan: "C",
69 PieceType.kSol: "S",
70 PieceType.kNnn: "-",
71 }
72
73 @staticmethod
75 _ = subprocess.call("clear" if os.name == "posix" else "cls")
76
77 def encode_piece(self, piece: GamePiece):
78 return (
79 f"{self._disp_format[piece.piece_color]}"
80 f"{self._type_to_code[piece.piece_type]}"
81 f"{self._color_to_code[piece.piece_color]}"
82 f"{cr.Style.RESET_ALL}"
83 )
84
85 def format_board_output(self, board: GameBoard):
86 file_labels = [
87 f" {chr(char_num)} " for char_num in range(ord("a"), ord("j"))
88 ]
89 file_labels.insert(0, "\t")
90 file_labels.insert(len(file_labels), "\n")
91
92 board_list = [
93 [
94 f" {self.encode_piece(board.map()[row][col])} "
95 for col in range(len(board.map()[0]))
96 ]
97 for row in range(len(board.map()))
98 ]
99 for row_index in range(len(board_list)):
100 board_list[row_index].insert(0, f" {str(10 - row_index)}\t")
101 board_list.insert(0, file_labels)
102 board_list = ["".join(row) for row in board_list]
103
104 return str("\n\n".join([str(rank) for rank in board_list]))
105
106 @staticmethod
108 player_summary: PlayerSummary,
109 ) -> Dict[str, str]:
110 display_dispatch = {
111 "Minimax": f"Minimax, max search depth = "
112 f"{player_summary.max_search_depth}, zobrist hash key size = "
113 f"{player_summary.zobrist_key_size} bits",
114 "Random": "Random",
115 }
116
117 return display_dispatch
118
119 def display_player_info(self, player_summary: PlayerSummary):
120
121 player_type_string = f"Player Type = {player_summary.player_type.name}"
122 move_evaluator_string = (
123 f", Move Evaluator = {player_summary.move_evaluator_type.name}"
124 if player_summary.move_evaluator_type != EvaluatorType.NULL
125 else ""
126 )
127 search_depth_string = (
128 f", Max Search Depth = {player_summary.max_search_depth}"
129 if player_summary.max_search_depth
130 else ""
131 )
132
133 zobrist_key_size_string = (
134 f", Zobrist Key Size = {player_summary.zobrist_key_size}"
135 if player_summary.zobrist_key_size
136 else ""
137 )
138
139 print(
140 f"\n{self._display_team_name[player_summary.color]} Player:\n"
141 f"{player_type_string}{move_evaluator_string}{search_depth_string}{zobrist_key_size_string}"
142 )
143
144 def display_prev_move(self, color: PieceColor, prev_move: Move = None):
145 if prev_move:
146 print(
147 f"Most recent move:\n"
148 f"{mt.convert_move_to_input_str(prev_move)} "
149 f"({self._display_team_name[color]})\n"
150 )
151 else:
152 print("Most recent move:\n" "NA... No moves executed yet.\n")
153
154 def display_whose_turn(self, color: PieceColor):
155 print(f"Whose turn:\n{self._display_team_name[color]}\n")
156
157 def display_if_is_in_check(self, color: PieceColor, is_in_check: bool):
158 if is_in_check:
159 print(f"{self._display_team_name[color]} is in check.")
160
161 def display_final_move(self, color: PieceColor, final_move: Move):
162 print(
163 f"Final move:\n"
164 f"{mt.convert_move_to_input_str(final_move)} "
165 f"({self._display_team_name[color]})\n"
166 )
167
168 @staticmethod
169 def display_winner(game_state: GameState):
170 if game_state == GameState.RED_WON:
171 print("Red won the game.")
172 if game_state == GameState.BLACK_WON:
173 print("Black won the game.")
174 if game_state == GameState.DRAW:
175 print("Game ended in a draw.")
176
178 self,
179 red_player_summary: PlayerSummary,
180 black_player_summary: PlayerSummary,
181 game_state: GameState,
182 game_board: GameBoard,
183 whose_turn: PieceColor,
184 is_in_check: bool,
185 move_count: int,
186 prev_move: Move = None,
187 ):
188 self.clear_screen()
189 print(f"{self.format_board_output(game_board)}\n")
190 self.display_player_info(player_summary=red_player_summary)
191 self.display_player_info(player_summary=black_player_summary)
192 print(f"\nMove count: {move_count}\n")
193
194 if game_state == GameState.UNFINISHED:
196 color=opponent_of(whose_turn), prev_move=prev_move
197 )
198 self.display_whose_turn(whose_turn)
200 color=whose_turn, is_in_check=is_in_check
201 )
202
203 else:
205 color=opponent_of(whose_turn), final_move=prev_move
206 )
207 self.display_winner(game_state)
Provides messages requesting input from a Player.
Outputs a text-base game board with GamePiece locations in algebraic notation.
def display_if_is_in_check(self, PieceColor color, bool is_in_check)
def display_final_move(self, PieceColor color, Move final_move)
def report_game_info(self, PlayerSummary red_player_summary, PlayerSummary black_player_summary, GameState game_state, GameBoard game_board, PieceColor whose_turn, bool is_in_check, int move_count, Move prev_move=None)
Dict[str, str] move_evaluator_translator(PlayerSummary player_summary)
def display_prev_move(self, PieceColor color, Move prev_move=None)
def display_player_info(self, PlayerSummary player_summary)
Enums that are only used on the Python side of the app.
Definition: enums.py:1
Python abstract classes used by a Game.
Contains functions used to convert algebraic board notation into integer indices array notation.
Contains PlayerSummary class.