chessai.core.ui
1import abc 2import argparse 3import typing 4 5import chessai.core.gamestate 6 7class UI(abc.ABC): 8 """ 9 UIs represent the basic way that a game interacts with the user, 10 by displaying the state of the game. 11 """ 12 13 def __init__(self, 14 **kwargs: typing.Any) -> None: 15 self._update_count: int = 0 16 """ Keep track of the number of times update() has been called. """ 17 18 def update(self, 19 state: chessai.core.gamestate.GameState, 20 termination_reason: chessai.core.types.TerminationReason | None = None, 21 ) -> None: 22 """ 23 Update the UI with the current state of the game. 24 This is the main entry point for the game into the UI. 25 """ 26 27 self.draw(state, termination_reason = termination_reason) 28 29 self._update_count += 1 30 31 def game_start(self, 32 initial_state: chessai.core.gamestate.GameState, 33 ) -> None: 34 """ Initialize the UI with the game's initial state. """ 35 36 self.update(initial_state) 37 38 def game_complete(self, 39 final_state: chessai.core.gamestate.GameState, 40 termination_reason: chessai.core.types.TerminationReason, 41 ) -> None: 42 """ Update the UI with the game's final state. """ 43 44 self.update(final_state, termination_reason) 45 46 def close(self) -> None: 47 """ Close the UI and release all owned resources. """ 48 49 @abc.abstractmethod 50 def draw(self, state: chessai.core.gamestate.GameState, **kwargs: typing.Any) -> None: 51 """ 52 Visualize the state of the game to the UI. 53 This is the typically the main override point for children. 54 Note that how this method visualizes the game completely unrelated 55 to how the draw_image() method works. 56 draw() will render to whatever the specific UI for the child class is, 57 while draw_image() specifically creates an image which will be used for animations. 58 If the child UI is also image-based than it can leverage draw_image(), 59 but there is no requirement to do that. 60 """ 61 62def set_cli_args(parser: argparse.ArgumentParser) -> argparse.ArgumentParser: 63 """ 64 Set common CLI arguments. 65 This is a sibling to init_from_args(), as the arguments set here can be interpreted there. 66 """ 67 68 parser.add_argument('--ui', dest = 'ui', 69 action = 'store', type = str, default = chessai.util.alias.UI_STDIO.short, 70 help = ('Set the UI/graphics to use (default: %(default)s).' 71 + ' Builtin options:' 72 + f' `{chessai.util.alias.UI_NULL.short}` (`{chessai.util.alias.UI_NULL.long}`)' 73 + ' -- Do not show any ui/graphics (best if you want to run fast and just need the result),' 74 + f' `{chessai.util.alias.UI_STDIO.short}` (`{chessai.util.alias.UI_STDIO.long}`)' 75 + ' -- Use stdin/stdout from the terminal (default).')) 76 77 return parser 78 79def init_from_args( 80 args: argparse.Namespace, 81 num_uis: int = 0, 82 null_out_uis: int = 0, 83 additional_args: dict | None = None, 84 ) -> argparse.Namespace: 85 """ 86 Take in args from a parser that was passed to set_cli_args(), 87 and initialize the proper components. 88 Constructed UIs will be placed `args._uis`. 89 If `num_uis` is not provided (or <= 0), 90 then `args.num_games` will be used. 91 If `null_out_uis` is > 0, then at most that number of UIs (starting at the beginning) 92 will be converted to null UIs. 93 This will not change the total number of UIs, just null out the first number of UIs. 94 """ 95 96 ui_args = { 97 # 'fps': args.fps, 98 # 'animation_path': args.animation_path, 99 # 'animation_fps': args.animation_fps, 100 # 'animation_skip_frames': args.animation_skip_frames, 101 # 'animation_optimize': args.animation_optimize, 102 } 103 104 if (additional_args is not None): 105 ui_args.update(additional_args) 106 107 if (num_uis <= 0): 108 num_uis = args.num_games 109 110 uis = [] 111 for i in range(num_uis): 112 ui_name = args.ui 113 if (i < null_out_uis): 114 ui_name = chessai.util.alias.UI_NULL.long 115 116 uis.append(chessai.util.reflection.new_object(ui_name, **ui_args)) 117 118 setattr(args, '_uis', uis) 119 120 return args
8class UI(abc.ABC): 9 """ 10 UIs represent the basic way that a game interacts with the user, 11 by displaying the state of the game. 12 """ 13 14 def __init__(self, 15 **kwargs: typing.Any) -> None: 16 self._update_count: int = 0 17 """ Keep track of the number of times update() has been called. """ 18 19 def update(self, 20 state: chessai.core.gamestate.GameState, 21 termination_reason: chessai.core.types.TerminationReason | None = None, 22 ) -> None: 23 """ 24 Update the UI with the current state of the game. 25 This is the main entry point for the game into the UI. 26 """ 27 28 self.draw(state, termination_reason = termination_reason) 29 30 self._update_count += 1 31 32 def game_start(self, 33 initial_state: chessai.core.gamestate.GameState, 34 ) -> None: 35 """ Initialize the UI with the game's initial state. """ 36 37 self.update(initial_state) 38 39 def game_complete(self, 40 final_state: chessai.core.gamestate.GameState, 41 termination_reason: chessai.core.types.TerminationReason, 42 ) -> None: 43 """ Update the UI with the game's final state. """ 44 45 self.update(final_state, termination_reason) 46 47 def close(self) -> None: 48 """ Close the UI and release all owned resources. """ 49 50 @abc.abstractmethod 51 def draw(self, state: chessai.core.gamestate.GameState, **kwargs: typing.Any) -> None: 52 """ 53 Visualize the state of the game to the UI. 54 This is the typically the main override point for children. 55 Note that how this method visualizes the game completely unrelated 56 to how the draw_image() method works. 57 draw() will render to whatever the specific UI for the child class is, 58 while draw_image() specifically creates an image which will be used for animations. 59 If the child UI is also image-based than it can leverage draw_image(), 60 but there is no requirement to do that. 61 """
UIs represent the basic way that a game interacts with the user, by displaying the state of the game.
19 def update(self, 20 state: chessai.core.gamestate.GameState, 21 termination_reason: chessai.core.types.TerminationReason | None = None, 22 ) -> None: 23 """ 24 Update the UI with the current state of the game. 25 This is the main entry point for the game into the UI. 26 """ 27 28 self.draw(state, termination_reason = termination_reason) 29 30 self._update_count += 1
Update the UI with the current state of the game. This is the main entry point for the game into the UI.
32 def game_start(self, 33 initial_state: chessai.core.gamestate.GameState, 34 ) -> None: 35 """ Initialize the UI with the game's initial state. """ 36 37 self.update(initial_state)
Initialize the UI with the game's initial state.
39 def game_complete(self, 40 final_state: chessai.core.gamestate.GameState, 41 termination_reason: chessai.core.types.TerminationReason, 42 ) -> None: 43 """ Update the UI with the game's final state. """ 44 45 self.update(final_state, termination_reason)
Update the UI with the game's final state.
50 @abc.abstractmethod 51 def draw(self, state: chessai.core.gamestate.GameState, **kwargs: typing.Any) -> None: 52 """ 53 Visualize the state of the game to the UI. 54 This is the typically the main override point for children. 55 Note that how this method visualizes the game completely unrelated 56 to how the draw_image() method works. 57 draw() will render to whatever the specific UI for the child class is, 58 while draw_image() specifically creates an image which will be used for animations. 59 If the child UI is also image-based than it can leverage draw_image(), 60 but there is no requirement to do that. 61 """
Visualize the state of the game to the UI. This is the typically the main override point for children. Note that how this method visualizes the game completely unrelated to how the draw_image() method works. draw() will render to whatever the specific UI for the child class is, while draw_image() specifically creates an image which will be used for animations. If the child UI is also image-based than it can leverage draw_image(), but there is no requirement to do that.
63def set_cli_args(parser: argparse.ArgumentParser) -> argparse.ArgumentParser: 64 """ 65 Set common CLI arguments. 66 This is a sibling to init_from_args(), as the arguments set here can be interpreted there. 67 """ 68 69 parser.add_argument('--ui', dest = 'ui', 70 action = 'store', type = str, default = chessai.util.alias.UI_STDIO.short, 71 help = ('Set the UI/graphics to use (default: %(default)s).' 72 + ' Builtin options:' 73 + f' `{chessai.util.alias.UI_NULL.short}` (`{chessai.util.alias.UI_NULL.long}`)' 74 + ' -- Do not show any ui/graphics (best if you want to run fast and just need the result),' 75 + f' `{chessai.util.alias.UI_STDIO.short}` (`{chessai.util.alias.UI_STDIO.long}`)' 76 + ' -- Use stdin/stdout from the terminal (default).')) 77 78 return parser
Set common CLI arguments. This is a sibling to init_from_args(), as the arguments set here can be interpreted there.
80def init_from_args( 81 args: argparse.Namespace, 82 num_uis: int = 0, 83 null_out_uis: int = 0, 84 additional_args: dict | None = None, 85 ) -> argparse.Namespace: 86 """ 87 Take in args from a parser that was passed to set_cli_args(), 88 and initialize the proper components. 89 Constructed UIs will be placed `args._uis`. 90 If `num_uis` is not provided (or <= 0), 91 then `args.num_games` will be used. 92 If `null_out_uis` is > 0, then at most that number of UIs (starting at the beginning) 93 will be converted to null UIs. 94 This will not change the total number of UIs, just null out the first number of UIs. 95 """ 96 97 ui_args = { 98 # 'fps': args.fps, 99 # 'animation_path': args.animation_path, 100 # 'animation_fps': args.animation_fps, 101 # 'animation_skip_frames': args.animation_skip_frames, 102 # 'animation_optimize': args.animation_optimize, 103 } 104 105 if (additional_args is not None): 106 ui_args.update(additional_args) 107 108 if (num_uis <= 0): 109 num_uis = args.num_games 110 111 uis = [] 112 for i in range(num_uis): 113 ui_name = args.ui 114 if (i < null_out_uis): 115 ui_name = chessai.util.alias.UI_NULL.long 116 117 uis.append(chessai.util.reflection.new_object(ui_name, **ui_args)) 118 119 setattr(args, '_uis', uis) 120 121 return args
Take in args from a parser that was passed to set_cli_args(),
and initialize the proper components.
Constructed UIs will be placed args._uis.
If num_uis is not provided (or <= 0),
then args.num_games will be used.
If null_out_uis is > 0, then at most that number of UIs (starting at the beginning)
will be converted to null UIs.
This will not change the total number of UIs, just null out the first number of UIs.