Welcome to Catanatron’s documentation!#
Catanatron is a Python implementation of the Settlers of Catan core game logic.
The most basic usage of the package looks like:
from catanatron.game import Game
from catanatron.models.player import RandomPlayer, Color
players = [
RandomPlayer(Color.RED),
RandomPlayer(Color.BLUE),
RandomPlayer(Color.WHITE),
RandomPlayer(Color.ORANGE),
]
game = Game(players)
game.play() # returns winning color
The example above executes a game of 4 RandomPlayers (players that decide completly at random).
The catanatron.players has more Player implementations.
Although the package exposes an OOP API, internally we’ve been moving to a
Functional implementation for performance. Particularly, when making copies of
the state (a common operation for tree-searching algorithms), it’s much faster to
copy a dictionary of primitives than to copy.deepcopy an entire class.
Internally the Game.play() method is mainly a while-no-one-has-won loop
that asks players to decide on a possible action. This architecture naturally
makes the framework fit the Game Trees concept, and makes it easy to implement
tree-searching players.
Thus, Players must implement the following API:
from catanatron.game import Game
from catanatron.models.actions import Action
from catanatron.models.player import Player
class MyPlayer(Player):
def decide(self, game: Game, playable_actions: Iterable[Action]):
"""Should return one of the playable_actions.
Args:
game (Game): complete game state. read-only.
playable_actions (Iterable[Action]): options to choose from
Return:
action (Action): Chosen element of playable_actions
"""
raise NotImplementedError
The first parameter, game is mainly so that the player can access game.state
to take its decisions. This game.state is currently represented by a simple data
container class; you can see the documentation here:
https://catanatron.readthedocs.io/en/latest/catanatron.html#catanatron.state.State.
For now, players should not mutate this state (should treat it read-only). If one
would like to make modifications to consider actions one should copy the state with
the State.copy function.
The second parameter is the list of playable Actions. An Action is a tuple of
enums and primitives like:
(ActionType.PLAY_MONOPOLY, WHEAT)(i.e. play monopoly card and select wheat)(ActionType.BUILD_SETTLEMENT, 3)(i.e. build settlement on node 3)(ActionType.MOVE_ROBBER, (1,0,1), Color.BLUE)(i.e. move robber to tile on coordinate (1,0,1) and steal from blue)(ActionType.END_TURN, None)(i.e. do nothing else and end turn)
After a player takes a decision, the Game follows a Redux/Router pattern in which calls
generic apply_action(state, action) method that will route to the appropriate
state-mutating function in the state_functions module.
A great way to further undersand the internals is to place a breakpoint in MyPlayer or RandomPlayer
run the provided sample.py in the repo and inspect the game and playable_actions objects.
This package is published in PyPi and is pip-installable like so:
pip install catanatron