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
class UI(abc.ABC):
 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.

def update( self, state: chessai.core.gamestate.GameState, termination_reason: chessai.core.types.TerminationReason | None = None) -> None:
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.

def game_start(self, initial_state: chessai.core.gamestate.GameState) -> None:
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.

def game_complete( self, final_state: chessai.core.gamestate.GameState, termination_reason: chessai.core.types.TerminationReason) -> None:
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.

def close(self) -> None:
47    def close(self) -> None:
48        """ Close the UI and release all owned resources. """

Close the UI and release all owned resources.

@abc.abstractmethod
def draw(self, state: chessai.core.gamestate.GameState, **kwargs: Any) -> None:
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.

def set_cli_args(parser: argparse.ArgumentParser) -> argparse.ArgumentParser:
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.

def init_from_args( args: argparse.Namespace, num_uis: int = 0, null_out_uis: int = 0, additional_args: dict | None = None) -> argparse.Namespace:
 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.