Skip to content

Engine module

Provide the class that handles the game.

This module allows the game to run. It is the game engine.

Examples:

>>> player1 = RandomComputerPlayer(Mark("X"))
>>> player2 = RandomComputerPlayer(Mark("O"))
>>> TicTacToe(player1, player2, ConsoleRenderer()).play()

The module contains the following class: - TicTacToe

TicTacToe dataclass

A class used to represebt the game engine.

Attributes:

Name Type Description
player1 Player

Player An instance of subclass of the Player class that represents a human or computer.

player2 Player

Player An instance of subclass of the Player class that represents a human or computer.

renderer Renderer

Renderer An instance of subclass of the Renderer class that handles UI rendering.

error_handler ErrorHandler | None

ErrorHandler | None = None A placehholder for a callback function that handles InvalidMove exceptions.

Methods:

Name Description
play

Mark = Mark("X")) -> None: Handles the flow of the game. The engine itself

def get_current_player

GameState) -> Player: Determines current player base on the current game state

Source code in src\backend\game\engine.py
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
@dataclass(frozen=True)
class TicTacToe:
    """A class used to represebt the game engine.

    Attributes:
        player1: Player
            An instance of subclass of the Player class that represents a human or computer.
        player2: Player
            An instance of subclass of the Player class that represents a human or computer.
        renderer: Renderer
            An instance of subclass of the Renderer class that handles UI rendering.
        error_handler: ErrorHandler | None = None
            A placehholder for a callback function that handles InvalidMove exceptions.

    Methods:
        play(self, starting_mark: Mark = Mark("X")) -> None:
            Handles the flow of the game. The engine itself
        def get_current_player(self, game_state: GameState) -> Player:
            Determines current player base on the current game state
    """
    player1: Player
    player2: Player
    renderer: Renderer
    error_handler: ErrorHandler | None = None

    def __post_init__(self):
        """Post instantiation hook that verifies that the player instantiation was corrected
        """
        validate_players(self.player1, self.player2)

    def play(self, starting_mark: Mark = Mark("X")) -> None:
        """Starts and handles the game until the game is over

        Args:
            starting_mark (Mark, optional): Initial Mark. Defaults to Mark("X").
        """
        game_state = GameState(Grid(), starting_mark)
        while True:
            self.renderer.render(game_state)
            if game_state.game_over:
                break
            player = self.get_current_player(game_state)
            try:
                game_state = player.make_move(game_state)
            except InvalidMove as ex:
                if self.error_handler:
                    self.error_handler(ex)

    def get_current_player(self, game_state: GameState) -> Player:
        """Determines current player base on the current game state

        Args:
            game_state (GameState): current GameState, consisting of a current Grid (9 elemets that
                that can be X, O or spaces) and a starting Mark (default X).

        Returns:
            Player: The player that has to play current turn
        """
        if game_state.current_mark is self.player1.mark:
            return self.player1
        return self.player2

__post_init__()

Post instantiation hook that verifies that the player instantiation was corrected

Source code in src\backend\game\engine.py
52
53
54
55
def __post_init__(self):
    """Post instantiation hook that verifies that the player instantiation was corrected
    """
    validate_players(self.player1, self.player2)

get_current_player(game_state)

Determines current player base on the current game state

Parameters:

Name Type Description Default
game_state GameState

current GameState, consisting of a current Grid (9 elemets that that can be X, O or spaces) and a starting Mark (default X).

required

Returns:

Name Type Description
Player Player

The player that has to play current turn

Source code in src\backend\game\engine.py
75
76
77
78
79
80
81
82
83
84
85
86
87
def get_current_player(self, game_state: GameState) -> Player:
    """Determines current player base on the current game state

    Args:
        game_state (GameState): current GameState, consisting of a current Grid (9 elemets that
            that can be X, O or spaces) and a starting Mark (default X).

    Returns:
        Player: The player that has to play current turn
    """
    if game_state.current_mark is self.player1.mark:
        return self.player1
    return self.player2

play(starting_mark=Mark('X'))

Starts and handles the game until the game is over

Parameters:

Name Type Description Default
starting_mark Mark

Initial Mark. Defaults to Mark("X").

Mark('X')
Source code in src\backend\game\engine.py
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
def play(self, starting_mark: Mark = Mark("X")) -> None:
    """Starts and handles the game until the game is over

    Args:
        starting_mark (Mark, optional): Initial Mark. Defaults to Mark("X").
    """
    game_state = GameState(Grid(), starting_mark)
    while True:
        self.renderer.render(game_state)
        if game_state.game_over:
            break
        player = self.get_current_player(game_state)
        try:
            game_state = player.make_move(game_state)
        except InvalidMove as ex:
            if self.error_handler:
                self.error_handler(ex)