catanatron.models package#

Submodules#

catanatron.models.actions module#

Move-generation functions (these return a list of actions that can be taken by current player). Main function is generate_playable_actions.

catanatron.models.actions.city_possibilities(state, color) List[Action]#
catanatron.models.actions.discard_possibilities(color) List[Action]#
catanatron.models.actions.generate_playable_actions(state: State) List[Action]#
catanatron.models.actions.initial_road_possibilities(state, color) List[Action]#
catanatron.models.actions.inner_maritime_trade_possibilities(hand_freqdeck, bank_freqdeck, port_resources)#

This inner function is to make this logic more shareable

catanatron.models.actions.maritime_trade_possibilities(state, color) List[Action]#
catanatron.models.actions.monopoly_possibilities(color) List[Action]#
catanatron.models.actions.ncr(n, r)#

n choose r. helper for discard_possibilities

catanatron.models.actions.road_building_possibilities(state, color, check_money=True) List[Action]#
catanatron.models.actions.robber_possibilities(state, color) List[Action]#
catanatron.models.actions.settlement_possibilities(state, color, initial_build_phase=False) List[Action]#
catanatron.models.actions.year_of_plenty_possibilities(color, freqdeck: List[int]) List[Action]#

catanatron.models.board module#

class catanatron.models.board.Board(catan_map=None, initialize=True)#

Bases: object

Encapsulates all state information regarding the board.

buildings#

Mapping from node id to building (if there is a building there).

Type

Dict[NodeId, Tuple[Color, FastBuildingType]]

roads#

Mapping from edge to Color (if there is a road there). Contains inverted edges as well for ease of querying.

Type

Dict[EdgeId, Color]

connected_components#

Cache datastructure to speed up maintaining longest road computation. To be queried by Color. Value is a list of node sets.

Type

Dict[Color, List[Set[NodeId]]]

board_buildable_ids#

Cache of buildable node ids in board.

Type

Set[NodeId]

road_color#

Color of player with longest road.

Type

Color

road_length#

Number of roads of longest road

Type

int

robber_coordinate#

Coordinate where robber is.

Type

Coordinate

build_city(color, node_id)#
build_road(color, edge)#
build_settlement(color, node_id, initial_build_phase=False)#

Adds a settlement, and ensures is a valid place to build.

Parameters
  • color (Color) – player’s color

  • node_id (int) – where to build

  • initial_build_phase (bool, optional) – Whether this is part of initial building phase, so as to skip connectedness validation. Defaults to True.

buildable_edges(color: Color)#

List of (n1,n2) tuples. Edges are in n1 < n2 order.

buildable_node_ids(color: Color, initial_build_phase=False)#
continuous_roads_by_player(color: Color)#
copy()#
dfs_walk(node_id, color)#

Generates set of nodes that are “connected” to given node.

Parameters
  • node_id (int) – Where to start search/walk.

  • color (Color) – Player color asking

Returns

Nodes that are “connected” to this one

by roads of the color player.

Return type

Set[int]

find_connected_components(color: Color)#
Returns

connected subgraphs. subgraphs

might include nodes that color doesnt own (on the way and on ends), just to make it is “closed” and easier for buildable_nodes to operate.

Return type

nx.Graph[]

get_edge_color(edge)#
get_node_color(node_id)#
get_player_port_resources(color)#

Yields resources (None for 3:1) of ports owned by color

is_enemy_node(node_id, color)#
is_enemy_road(edge, color)#
is_friendly_node(node_id, color)#
is_friendly_road(edge, color)#
catanatron.models.board.get_edges(land_nodes=None)#
catanatron.models.board.get_node_distances()#
catanatron.models.board.longest_acyclic_path(board: Board, node_set: Set[int], color: Color)#

catanatron.models.coordinate_system module#

class catanatron.models.coordinate_system.Direction(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)#

Bases: Enum

EAST = 'EAST'#
NORTHEAST = 'NORTHEAST'#
NORTHWEST = 'NORTHWEST'#
SOUTHEAST = 'SOUTHEAST'#
SOUTHWEST = 'SOUTHWEST'#
WEST = 'WEST'#
catanatron.models.coordinate_system.add(acoord, bcoord)#
catanatron.models.coordinate_system.cube_to_axial(cube)#
catanatron.models.coordinate_system.cube_to_offset(cube)#
catanatron.models.coordinate_system.generate_coordinate_system(num_layers)#

Generates a set of coordinates by expanding outward from a center tile on (0,0,0) with the given number of layers (as in an onion :)). Follows BFS.

catanatron.models.coordinate_system.num_tiles_for(layer)#

Including inner-layer tiles

catanatron.models.coordinate_system.offset_to_cube(offset)#

catanatron.models.decks module#

Providers helper functions to deal with representations of decks of cards

We use a histogram / ‘frequency list’ to represent decks (aliased ‘freqdeck’). This representation is concise, easy to copy, access and fast to compare.

catanatron.models.decks.draw_from_listdeck(list1: List, amount: int, card: int)#
catanatron.models.decks.freqdeck_add(list1, list2)#
catanatron.models.decks.freqdeck_can_draw(freqdeck, amount: int, card: Literal['WOOD', 'BRICK', 'SHEEP', 'WHEAT', 'ORE'])#
catanatron.models.decks.freqdeck_contains(list1, list2)#

True if list1 >= list2 element-wise

catanatron.models.decks.freqdeck_count(freqdeck, card: Literal['WOOD', 'BRICK', 'SHEEP', 'WHEAT', 'ORE'])#
catanatron.models.decks.freqdeck_draw(freqdeck, amount: int, card: Literal['WOOD', 'BRICK', 'SHEEP', 'WHEAT', 'ORE'])#
catanatron.models.decks.freqdeck_from_listdeck(listdeck: Iterable[Literal['WOOD', 'BRICK', 'SHEEP', 'WHEAT', 'ORE']])#
catanatron.models.decks.freqdeck_replenish(freqdeck, amount: int, card: Literal['WOOD', 'BRICK', 'SHEEP', 'WHEAT', 'ORE'])#
catanatron.models.decks.freqdeck_subtract(list1, list2)#
catanatron.models.decks.starting_devcard_bank()#

Returns listdeck of devcards

catanatron.models.decks.starting_devcard_proba(card: Literal['KNIGHT', 'YEAR_OF_PLENTY', 'MONOPOLY', 'ROAD_BUILDING', 'VICTORY_POINT'])#
catanatron.models.decks.starting_resource_bank()#

Returns freqdeck of resource cards

catanatron.models.enums module#

class catanatron.models.enums.Action(color, action_type, value)#

Bases: tuple

Main class to represent action. Should be immutable, and so the choice of a namedtuple.

The “value” is a polymorphic field that acts as the “parameters” for the “action_type”. e.g. where to ActionType.BUILD_SETTLEMENT or who to steal from in a ActionType.MOVE_ROBBER action.

We use this class to represent the _intent_ of say “moving a robber to Tile (0,0,0) and stealing from Blue”.

action_type#

Alias for field number 1

color#

Alias for field number 0

value#

Alias for field number 2

class catanatron.models.enums.ActionPrompt(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)#

Bases: Enum

BUILD_INITIAL_ROAD = 'BUILD_INITIAL_ROAD'#
BUILD_INITIAL_SETTLEMENT = 'BUILD_INITIAL_SETTLEMENT'#
DECIDE_ACCEPTEES = 'DECIDE_ACCEPTEES'#
DECIDE_TRADE = 'DECIDE_TRADE'#
DISCARD = 'DISCARD'#
MOVE_ROBBER = 'MOVE_ROBBER'#
PLAY_TURN = 'PLAY_TURN'#
class catanatron.models.enums.ActionRecord(action, result)#

Bases: tuple

Records an Action along with the result of that action. Useful for showing an “action log” in a UI, fully replaying a game, or undoing actions to a State.

The “result” field is polymorphic depending on the action_type. - ROLL: result is (int, int) 2 dice rolled - DISCARD: result is List[Resource] discarded - MOVE_ROBBER: result is card stolen (Resource|None) - BUY_DEVELOPMENT_CARD: result is card - …for the rest, result is None since they are deterministic actions

action#

Alias for field number 0

result#

Alias for field number 1

class catanatron.models.enums.ActionType(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)#

Bases: Enum

Type of action taken by a player.

See comments next to each ActionType for the shape of the corresponding .value field in Actions of that type.

ACCEPT_TRADE = 'ACCEPT_TRADE'#
BUILD_CITY = 'BUILD_CITY'#
BUILD_ROAD = 'BUILD_ROAD'#
BUILD_SETTLEMENT = 'BUILD_SETTLEMENT'#
BUY_DEVELOPMENT_CARD = 'BUY_DEVELOPMENT_CARD'#
CANCEL_TRADE = 'CANCEL_TRADE'#
CONFIRM_TRADE = 'CONFIRM_TRADE'#
DISCARD = 'DISCARD'#
END_TURN = 'END_TURN'#
MARITIME_TRADE = 'MARITIME_TRADE'#
MOVE_ROBBER = 'MOVE_ROBBER'#
OFFER_TRADE = 'OFFER_TRADE'#
PLAY_KNIGHT_CARD = 'PLAY_KNIGHT_CARD'#
PLAY_MONOPOLY = 'PLAY_MONOPOLY'#
PLAY_ROAD_BUILDING = 'PLAY_ROAD_BUILDING'#
PLAY_YEAR_OF_PLENTY = 'PLAY_YEAR_OF_PLENTY'#
REJECT_TRADE = 'REJECT_TRADE'#
ROLL = 'ROLL'#
class catanatron.models.enums.EdgeRef(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)#

Bases: Enum

EAST = 'EAST'#
NORTHEAST = 'NORTHEAST'#
NORTHWEST = 'NORTHWEST'#
SOUTHEAST = 'SOUTHEAST'#
SOUTHWEST = 'SOUTHWEST'#
WEST = 'WEST'#
class catanatron.models.enums.NodeRef(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)#

Bases: Enum

NORTH = 'NORTH'#
NORTHEAST = 'NORTHEAST'#
NORTHWEST = 'NORTHWEST'#
SOUTH = 'SOUTH'#
SOUTHEAST = 'SOUTHEAST'#
SOUTHWEST = 'SOUTHWEST'#

catanatron.models.map module#

class catanatron.models.map.CatanMap(tiles: Dict[Tuple[int, int, int], Union[LandTile, Port, Water]] = {}, land_tiles: Dict[Tuple[int, int, int], LandTile] = {}, port_nodes: Dict[Optional[Literal['WOOD', 'BRICK', 'SHEEP', 'WHEAT', 'ORE']], Set[int]] = {}, land_nodes: FrozenSet[int] = frozenset({}), adjacent_tiles: Dict[int, List[LandTile]] = {}, node_production: Dict[int, Counter] = {}, tiles_by_id: Dict[int, LandTile] = {}, ports_by_id: Dict[int, Port] = {})#

Bases: object

Represents a randomly initialized map.

static from_template(map_template: MapTemplate, number_placement: Literal['official_spiral', 'random'] = 'official_spiral')#
static from_tiles(tiles: Dict[Tuple[int, int, int], Union[LandTile, Port, Water]])#
catanatron.models.map.MINI_MAP_TEMPLATE = MapTemplate(numbers=[3, 4, 5, 6, 8, 9, 10], port_resources=[], tile_resources=['WOOD', None, 'BRICK', 'SHEEP', 'WHEAT', 'WHEAT', 'ORE'], topology={(0, 0, 0): <class 'catanatron.models.tiles.LandTile'>, (1, -1, 0): <class 'catanatron.models.tiles.LandTile'>, (0, -1, 1): <class 'catanatron.models.tiles.LandTile'>, (-1, 0, 1): <class 'catanatron.models.tiles.LandTile'>, (-1, 1, 0): <class 'catanatron.models.tiles.LandTile'>, (0, 1, -1): <class 'catanatron.models.tiles.LandTile'>, (1, 0, -1): <class 'catanatron.models.tiles.LandTile'>, (2, -2, 0): <class 'catanatron.models.tiles.Water'>, (1, -2, 1): <class 'catanatron.models.tiles.Water'>, (0, -2, 2): <class 'catanatron.models.tiles.Water'>, (-1, -1, 2): <class 'catanatron.models.tiles.Water'>, (-2, 0, 2): <class 'catanatron.models.tiles.Water'>, (-2, 1, 1): <class 'catanatron.models.tiles.Water'>, (-2, 2, 0): <class 'catanatron.models.tiles.Water'>, (-1, 2, -1): <class 'catanatron.models.tiles.Water'>, (0, 2, -2): <class 'catanatron.models.tiles.Water'>, (1, 1, -2): <class 'catanatron.models.tiles.Water'>, (2, 0, -2): <class 'catanatron.models.tiles.Water'>, (2, -1, -1): <class 'catanatron.models.tiles.Water'>})#

Standard 4-player map

class catanatron.models.map.MapTemplate(numbers: List[int], port_resources: List[Optional[Literal['WOOD', 'BRICK', 'SHEEP', 'WHEAT', 'ORE']]], tile_resources: List[Optional[Literal['WOOD', 'BRICK', 'SHEEP', 'WHEAT', 'ORE']]], topology: Mapping[Tuple[int, int, int], Union[Type[catanatron.models.tiles.LandTile], Type[catanatron.models.tiles.Water], Tuple[Type[catanatron.models.tiles.Port], catanatron.models.coordinate_system.Direction]]])#

Bases: object

numbers: List[int]#
port_resources: List[Optional[Literal['WOOD', 'BRICK', 'SHEEP', 'WHEAT', 'ORE']]]#
tile_resources: List[Optional[Literal['WOOD', 'BRICK', 'SHEEP', 'WHEAT', 'ORE']]]#
topology: Mapping[Tuple[int, int, int], Union[Type[LandTile], Type[Water], Tuple[Type[Port], Direction]]]#
catanatron.models.map.build_dice_probas()#
catanatron.models.map.build_map(map_type: Literal['TOURNAMENT', 'MINI', 'BASE'], number_placement: Literal['official_spiral', 'random'] = 'official_spiral')#
catanatron.models.map.get_edge_nodes(edge_ref)#

returns pair of nodes at the “ends” of a given edge

catanatron.models.map.get_node_counter_production(adjacent_tiles: Dict[int, List[LandTile]], node_id: int)#
catanatron.models.map.get_nodes_and_edges(tiles, coordinate: Tuple[int, int, int], node_autoinc)#

Get pre-existing nodes and edges in board for given tile coordinate

catanatron.models.map.init_adjacent_tiles(land_tiles: Dict[Tuple[int, int, int], LandTile]) Dict[int, List[LandTile]]#
catanatron.models.map.init_node_production(adjacent_tiles: Dict[int, List[LandTile]]) Dict[int, Counter]#

Returns node_id => Counter({WHEAT: 0.123, …})

catanatron.models.map.init_port_nodes_cache(tiles: Dict[Tuple[int, int, int], Union[LandTile, Port, Water]]) Dict[Optional[Literal['WOOD', 'BRICK', 'SHEEP', 'WHEAT', 'ORE']], Set[int]]#

Initializes board.port_nodes cache.

Parameters

tiles (Dict[Coordinate, Tile]) – initialized tiles datastructure

Returns

Mapping from FastResource to node_ids that

enable port trading. None key represents 3:1 port.

Return type

Dict[Union[FastResource, None], Set[int]]

catanatron.models.map.initialize_tiles(map_template: MapTemplate, shuffled_numbers_param=None, shuffled_port_resources_param=None, shuffled_tile_resources_param=None, number_placement: Literal['official_spiral', 'random'] = 'official_spiral') Dict[Tuple[int, int, int], Union[LandTile, Port, Water]]#

Initializes a new random board, based on the MapTemplate.

It first shuffles tiles, ports, and numbers. Then goes satisfying the topology (i.e. placing tiles on coordinates); ensuring to “attach” these to neighbor tiles (so as to not repeat nodes or edges objects).

Parameters

map_template (MapTemplate) – Template to initialize.

Raises

ValueError – Invalid tile in topology

Returns

Coordinate to initialized Tile mapping.

Return type

Dict[Coordinate, Tile]

catanatron.models.map.number_probability(number)#

catanatron.models.player module#

class catanatron.models.player.Color(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)#

Bases: Enum

Enum to represent the colors in the game

BLUE = 'BLUE'#
ORANGE = 'ORANGE'#
RED = 'RED'#
WHITE = 'WHITE'#
class catanatron.models.player.HumanPlayer(color, is_bot=False, input_fn=<built-in function input>)#

Bases: Player

Human player that selects which action to take using standard input

decide(game, playable_actions)#

Should return one of the playable_actions or an OFFER_TRADE action if its your turn and you have already rolled.

Parameters
  • game (Game) – complete game state. read-only.

  • playable_actions (Iterable[Action]) – options right now

class catanatron.models.player.Player(color, is_bot=True)#

Bases: object

Interface to represent a player’s decision logic.

Formulated as a class (instead of a function) so that players can have an initialization that can later be serialized to the database via pickle.

decide(game, playable_actions)#

Should return one of the playable_actions or an OFFER_TRADE action if its your turn and you have already rolled.

Parameters
  • game (Game) – complete game state. read-only.

  • playable_actions (Iterable[Action]) – options right now

reset_state()#

Hook for resetting state between games

class catanatron.models.player.RandomPlayer(color, is_bot=True)#

Bases: Player

Random AI player that selects an action randomly from the list of playable_actions

decide(game, playable_actions)#

Should return one of the playable_actions or an OFFER_TRADE action if its your turn and you have already rolled.

Parameters
  • game (Game) – complete game state. read-only.

  • playable_actions (Iterable[Action]) – options right now

class catanatron.models.player.SimplePlayer(color, is_bot=True)#

Bases: Player

Simple AI player that always takes the first action in the list of playable_actions

decide(game, playable_actions)#

Should return one of the playable_actions or an OFFER_TRADE action if its your turn and you have already rolled.

Parameters
  • game (Game) – complete game state. read-only.

  • playable_actions (Iterable[Action]) – options right now

Module contents#