from __future__ import annotations
import numpy as np
from draughts.boards.base import BaseBoard
from draughts.models import Color, Figure
from draughts.move import Move
from draughts.utils import (
get_short_vertical_and_horizontal_moves,
get_vertical_and_horizontal_moves,
logger,
)
# fmt: off
SQUARES= [ B10, D10, F10, H10, J10,
A9, C9, E9, G9, I9,
B8, D8, F8, H8, J8,
A7, C7, E7, G7, I7,
B6, D6, F6, H6, J6,
A5, C5, E5, G5, I5,
B4, D4, F4, H4, J4,
A3, C3, E3, G3, I3,
B2, D2, F2, H2, J2,
A1, C1, E1, G1, I1] = range(50)
# fmt: on
[docs]
class Board(BaseBoard):
"""
**Board for Frisian draughts.**
Game rules:
- Board size: 10x10
- Besides capturing diagonally, one can also capture horizontally and vertically.
Every piece can thus capture in eight directions
- If a king and a man can play a capture sequence of equal value,
it is always forced to play with the king.
- If a player has one or more kings on the board but also has one or more men left,
it is not allowed to play more than three non-capturing moves in a row with the same king.
If no capture is available for a king after its third non-capturing move,
one is forced to play with a different king or a man.
After that one can play any move with that king again,
but of course again only three times in a row if it doesn't capture.
This rule does not apply for a player that has no more men left (only kings on the board).
**Winning and drawing**
- When one player has two kings and the other player has one king,
the game is drawn after both players made 7 moves.
- When both players have one king left, the game is drawn after both players made 2 moves.
The official rules state that the game is drawn immediately when two kings are left
unless either player can win by force (which means the other king can be captured immediately
or will necessarily be captured next move). As we currently can't distinguish the positions
that win by force on lidraughts, this rule is implemented by always allowing 2 more moves to win the game.
"""
GAME_TYPE = 40
STARTING_POSITION = np.array([1] * 20 + [0] * 10 + [-1] * 20, dtype=np.int8)
STARTING_COLOR = Color.WHITE
ROW_IDX = {val: val // 5 for val in range(len(STARTING_POSITION))}
COL_IDX = {val: val % 10 for val in range(len(STARTING_POSITION))}
@property
def is_draw(self) -> bool:
return (
self.is_threefold_repetition
or self.is_5_moves_rule
or self.is_16_moves_rule
or self.is_25_moves_rule
)
@property
def is_25_moves_rule(self) -> bool:
if self.halfmove_clock < 50:
return False
logger.debug("25 moves rule")
return True
# return self.halfmove_clock >= 50
@property
def is_16_moves_rule(self) -> bool:
if self.halfmove_clock < 32:
return False
if len(self._pos[self._pos != Figure.EMPTY]) > 4:
return False
if np.abs(self._pos).sum() < Figure.KING.value * 2 + Figure.MAN.value * 2:
return False
logger.debug("16 moves rule")
return True
@property
def is_5_moves_rule(self) -> bool:
# if count of pieces is not 3 or 4
if len(self._pos[self._pos != Figure.EMPTY]) > 3:
return False
if np.abs(self._pos).sum() < Figure.KING.value * 2 + Figure.MAN.value:
return False
if self.halfmove_clock < 10:
return False
logger.debug("5 moves rule")
return True
@property
def legal_moves(self) -> list[Move]:
all_moves = []
is_capture_mandatory = False
squares_list = np.transpose(np.nonzero(self._pos * self.turn.value > 0))
for square in squares_list.flatten():
moves = self._legal_moves_from(square, is_capture_mandatory)
all_moves.extend(moves)
return all_moves
def _legal_moves_from(self, square: int, is_capture_mandatory=False) -> list[Move]:
entity = Figure(self._pos[square])
if abs(entity) == Figure.MAN:
moves = self._get_man_legal_moves_from(square, is_capture_mandatory)
else:
moves = self._get_king_legal_moves_from(square, is_capture_mandatory)
if is_capture_mandatory:
moves = [move for move in moves if len(move.captured_list) > 0]
return moves
def _get_man_legal_moves_from(
self, square: int, is_captrue_mandatory: bool
) -> list[Move]:
# legal_moves = self.DIAGONAL_SHORT_MOVES +
raise NotImplementedError
def _get_king_legal_moves_from(
square: int, is_captrue_mandatory: bool
) -> list[Move]:
raise NotImplementedError
if __name__ == "__main__":
board = Board()