Source code for gogame.player
from __future__ import annotations
from abc import ABC, abstractmethod
import functools
from typing import (
Optional,
TYPE_CHECKING
)
import numpy as np
from .enum import Color
if TYPE_CHECKING:
from .territory import Territory
from .board import Board
def in_game(func):
@functools.wraps(func)
def f(self, *args, **kwargs):
if self._in_game:
if self._color and self._board:
return func(self, *args, **kwargs)
else:
raise Exception("Player is in game but is not fully initialized")
else:
raise Exception("Player is not currently in game")
return f
[docs]
class Player(ABC):
"""Represents a go player.
This class has to be overridden to implement the :func:`play()` method"""
def __init__(self, name: Optional[str] = None, color: Optional[Color] = None):
"""
Args:
name: The name of the player (only used to identify it)
color: The color the player will player, if set to None, it's automatically set by the board
"""
self._in_game: bool = False
self._board: Optional[Board] = None
self._color: Optional[Color] = color
self.name = name
def __str__(self):
if self.name:
return self.name
else:
return self.__repr__()
def __repr__(self):
return f"<{self.__class__.__name__} color={self._color} board={self._board}>"
def _initiate(self, board: Board):
self._in_game = True
self._board = board
def _clear_state(self):
self._in_game = False
self._board = None
self._color = None
@property
def is_in_game(self) -> bool:
"""Check if the player is currently linked to a board"""
return self._in_game
@property
def color(self) -> Optional[Color]:
"""Returns the color of the player if any"""
return self._color
@property
def board(self) -> Optional[Board]:
"""Returns the associated board if any"""
return self._board
[docs]
@in_game
def get_board_matrix(self) -> np.ndarray:
"""Returns the current state of the board (0 for empty, 1 for the player, -1 for the opponent)"""
return self._board.matrix()
[docs]
@in_game
def playable_moves(self) -> list[tuple[int, int]]:
"""Returns the list of all vertices available for playing"""
return self._board.playable_moves(self._color)
[docs]
@in_game
def my_vertices(self) -> list[tuple[int, int]]:
"""Returns a list of all vertices owned by the player"""
return self._board.vertices(self._color)
[docs]
@in_game
def get_vertices(self, color: Color) -> list[tuple[int, int]]:
"""Returns a list of all vertices owned by the opponent"""
return self._board.vertices(color)
[docs]
@in_game
def free_vertices(self) -> list[tuple[int, int]]:
"""Returns a list of all empty vertices on the board"""
return self._board.vertices(Color.Empty)
[docs]
@in_game
def my_territories(self) -> list[Territory]:
"""Returns a list of territories owned by the player"""
return self._board.territories(self._color)
[docs]
@in_game
def get_territories(self, color: Color) -> list[Territory]:
"""Returns a list of territories owned by the opponent"""
return self._board.territories(color)
[docs]
@in_game
def territories(self) -> list[Territory]:
"""Returns all territories on the board"""
return self._board.territories()
[docs]
@abstractmethod
def play(self) -> Optional[tuple[int, int]]:
"""This method has to be overridden by subclasses
It's called when the player has to play and must return a 2-tuple (x, y) representing a move, or None for skipping the turn"""
pass