139 lines
4.6 KiB
Python
139 lines
4.6 KiB
Python
"""
|
|
This module contains the base class for any game.
|
|
|
|
If you'd like to create a new game, please copy this module and fill in
|
|
all the necessary methods in order to have a functioning game.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from enum import Enum, auto
|
|
from typing import Any
|
|
|
|
class FinishState(Enum):
|
|
draw = auto()
|
|
loss = auto()
|
|
win = auto()
|
|
|
|
class Game:
|
|
"""
|
|
Base class for all games.
|
|
|
|
A game is always a snapshot of a game that is paused because it waits
|
|
for a user to make a move.
|
|
"""
|
|
|
|
def action_name(self) -> str:
|
|
"""
|
|
Return the type of action to take. Please only use alphanumeric
|
|
characters.
|
|
|
|
This helps the player understand what they are supposed to do.
|
|
For example, in Risk, you can use this to explain whether they are
|
|
expected to "recruit" or "attack" or "move" with their troops.
|
|
|
|
If all moves require the same action (such as with tic-tac-toe),
|
|
you can leave this to return an empty string.
|
|
"""
|
|
return ""
|
|
|
|
def as_seen_by(self, player : int) -> dict[str, Any]:
|
|
"""
|
|
From the perspective of a given player, return the game's state.
|
|
|
|
Note that it is very common in games for players to not have ALL
|
|
the details available. For example, in card games, you are
|
|
generally unable to see the cards in your opponents' hands.
|
|
|
|
The game's state is formatted in a way that makes it easy to
|
|
convert it to JSON or a tensor.
|
|
|
|
:param player: Player. Counting starts from one.
|
|
:type player: int
|
|
:return: The game's state from the perspective of the player.
|
|
:rtype: dict[str, Any]
|
|
"""
|
|
return {}
|
|
|
|
@classmethod
|
|
def empty(cls) -> "Game":
|
|
"""
|
|
Create a new game.
|
|
|
|
Use this method to shuffle the cards, to arrange pieces on the
|
|
board, and set up the state in a way where the first player can
|
|
start to make its move.
|
|
|
|
:return: A game that's ready to start.
|
|
:rtype: Game
|
|
"""
|
|
return cls()
|
|
|
|
def game_name(self) -> str:
|
|
"""
|
|
Return a non-empty string that uniquely identifies the game.
|
|
When creating a new unspecified game, please respect the Java
|
|
package naming convention.
|
|
"""
|
|
return "default-game"
|
|
|
|
def move_default(self) -> "Game":
|
|
"""
|
|
Fallback move option for when a user isn't available or cannot
|
|
decide. Program this move to be predictable, and resemble an
|
|
attempted skip as much as possible. For example:"
|
|
|
|
- In Go, place a tile in an empty space near the top-left corner
|
|
- In Monopoly, choose not to buy anything
|
|
- In poker, check. (Or fold after a raise.)
|
|
- In a maze, choose the left-most path
|
|
"""
|
|
# NOTE: Games are meant to be immutable values!
|
|
# As such, you should always consider creating a deep copy of oneself,
|
|
# do not simply return self if it might update.
|
|
return self
|
|
|
|
def move(self, payload : dict[str, Any] | None = None) -> "Game":
|
|
"""
|
|
Make a move on behalf of whose turn it is.
|
|
|
|
:param payload: Dictionary containing the player's response.
|
|
:type payload: dict[str, Any] | None
|
|
:return: A new instance of the game where a new action is required.
|
|
:rtype: Game
|
|
"""
|
|
if not isinstance(payload, dict):
|
|
return self.move_default()
|
|
|
|
# NOTE: Games are meant to be immutable values!
|
|
# As such, you should always consider creating a deep copy of oneself,
|
|
# do not simply return self if it might update.
|
|
return self
|
|
|
|
def player_to_move(self) -> int:
|
|
"""
|
|
Return which player is currently meant to move.
|
|
|
|
:return: Which player to move. Counting starts from one.
|
|
:rtype: int
|
|
"""
|
|
return 1
|
|
|
|
def to_dict(self) -> dict[str, Any]:
|
|
"""
|
|
Return a dictionary containing the full game state.
|
|
|
|
:return: The current game's state.
|
|
:rtype: dict[str, Any]
|
|
"""
|
|
return {}
|
|
|
|
def winner(self) -> dict[int, FinishState] | None:
|
|
"""
|
|
Determine whether the game has ended.
|
|
|
|
:return: A list detailing which players have won, lost or drawn - or None if the game hasn't finished.
|
|
:rtype: dict[int, FinishState] | None
|
|
"""
|
|
return {}
|