Source code for pieces

"""This module has the Piece base class, Bishop, King, Knight, Pawn,
Rook, and Queen subclasses, and several factory methods for creating
import sys
from typing import Any, Dict, Iterable, Literal, Tuple, Union, overload
from enums import Color, PieceType, Positions, Rank, SetOrder

[docs]class Piece: """ Base class to derive the Bishop, King, Knight, Pawn, Rook, and Queen subclasses. :param color: Color.WHITE (default value) or Color.BLACK :type color: Color :param position: two-item integer tuple (default is ``None``) :type position: tuple """ def __init__(self, *, color: Color=Color.WHITE, position: tuple=None): """Constuctor method. """ self._color, self._position = color, position self._first_move = True
[docs] def __repr__(self) -> str: """Returns string as "<piece name> (color=<bool>, position=<None|tuple>)". """ name = self.__class__.__name__ return f"{name} (color={self._color!r}, position={self._position!r})"
[docs] def __str__(self) -> str: """ Returns string as "<piece name> <color name>[ <position>]". """ color = str(Color(self._color).name).capitalize() name, notation = self.__class__.__name__, '' if self._position: file, rank = self._position notation = ''.join([' ', chr(file), str(rank)]) return f"{name} {color}{notation}"
@property def color(self) -> Color: """Piece color. :getter: ``True`` for white, ``False`` for black :type: bool :raises AttributeError: read-only property """ return self._color @property def first_move(self) -> bool: """First move for the piece. :getter: ``True`` for first move, ``False`` if not :type: bool :raises AttributeError: read-only property """ return self._first_move @property def position(self) -> None | tuple: """Position on the board. When position is updated for first time, first move will change from ``True`` to ``False``. :getter: ``None`` (not set) or ``(file, rank)`` :type: None | tuple :setter: ``(file, rank)`` :type: tuple """ return self._position @position.setter def position(self, position: Tuple[int, int]) -> None: if self._first_move and self._position: self._first_move = False self._position = position
[docs]class Bishop(Piece): """A bishop can move diagonally from one to seven positions. """
[docs]class King(Piece): """A king can move one position in any direction, or two positions horizontally when castling with a rook. """ def __init__(self, color: Color = Color.WHITE, position: tuple = None): super().__init__(color=color, position=position) self._check = False @property def check(self) -> bool: """Check by another piece. :getter: ``True`` if checked, ``False`` if not (default is ``False``) :type: bool :setter: ``True`` or ``False`` :type: bool """ return self._check @check.setter def check(self, value: bool) -> None: self._check = value
[docs]class Knight(Piece): """A knight can jump two positions in one direction and one position over. """
[docs]class Pawn(Piece): """A pawn can only move foward. One or two positions on the first move, one position on or after the first move, and diagonally one position for capture or *en passant*. """
[docs]class Queen(Piece): """A queen can move one to seven positions in any direction. """
[docs]class Rook(Piece): """A rook can move one to seven positions horizontally or vertically. """
[docs]def factory_piece(piece: PieceType, *, color: Color = Color.WHITE, \ position: tuple = None) -> Piece: """Factory method to create a piece. :param piece: BISHOP, KING, KNIGHT, PAWN, QUEEN, ROOK :type piece: PieceType :param color: ``Color.WHITE`` or ``Color.BLACK`` (default is ``Color.WHITE``) :type color: Color :param position: ``(file, rank)`` (default is ``None``) :type position: tuple :return: specified piece :rtype: Piece :raises ValueError: invalid PieceType for piece """ pieces: Dict[PieceType, Any] = {piece: getattr(sys.modules[__name__], for piece in PieceType} if piece in pieces: return pieces.get(piece, lambda *args: None)(color=color, position=position) raise ValueError(f"Bad piece creation with {str(piece)}")
[docs]def factory_set(*, color: Color = Color.WHITE) -> Iterable: """Factory method to create a set of 16 pieces with assigned positions based on color. Calls the ``factory_piece()`` method to create indivdual pieces. :param color: ``Color.WHITE`` or ``Color.BLACK`` (default is ``Color.WHITE``) :type color: Color :return: map object with 16 tuples, ``((file, rank), Piece)`` :rtype: Iterable """ pieces = SetOrder.HIGH + SetOrder.PAWN ranks_high = [(file, Rank.HIGH[int(not color)]) for file in Positions.FILE_NUMBERS.value] ranks_pawn = [(file, Rank.PAWN[int(not color)]) for file in Positions.FILE_NUMBERS.value] return map(lambda piece, position: (position, factory_piece(piece, color=color, position=position)), pieces, ranks_high + ranks_pawn)