Closed dlbbld closed 3 years ago
Aren't these 3 methods:
can_claim_draw()
can_claim_fifty_moves()
can_claim_threefold_repetition()
equivalent to:
Board#isDraw()
Board#getHalfMoveCounter() >= 100 // yes, we can give it a more comprehensive API name
Board#isInsufficientMaterial()
Aren't these equivalent?
PS: chesslib also has isStaleMate()
No, can_claim_fifty_moves()
for the player having the move means the following: Either with the last halfmove of the opponent 100 or more consecutive half moves without capture or pawn advance have already happened. Or there are 99 such halfmoves, and the player itself has a legal move, which will result in 100 such halfmoves. Such a continuation is of course not always possible, e.g. the player may be forced to make a capture to get out of check or to make a pawn move for Zugzwang.
In the second case, in OTB games, when continuation from 99 to 100 is possible, the player can claim the draw by announcing the intention to perform such a move, without performing this move. The need to have the method comes from this rule.
can_claim_threefold_repetition()
is likewise for threefold repetition rule. When you have a move which leads to a threefold repetition, you can claim it without performing the move. Of course, if there are already three or more repetitions on the board, you can also claim the draw. When there are five or more repetitions on the board, the game should have already been drawn by the arbiter, by the fivefold repetition rule. Likewise for seventy-five halfmoves without capture or pawn move by the seventy-five-move rule.
can_claim_draw()
is just having one of the cases above, can_claim_fifty_moves()
or can_claim_threefold_repetition()
.
Of course, python chess also has the stalemate (is_stalemate()
).
Board.isInsufficientMaterial()
is fine, both sides have insufficient material. But a method like board.isInsufficientMaterial(Side)
is also needed for checking if one side has insufficient material. When the time runs out for a player and the opponent has insufficient material, the result is automatically a draw unless it's a dead position otherwise, where it is also a draw. Otherwise, it's, of course, a win on time by for the opponent.
To find out dead position is a chapter on its own that nobody has mastered to today. So we can skip that happily.
Gotcha. I will have a crack at these for the next releases.
It looks a lot at first glance but is not. The required logic is already there, so is_seventyfive_moves()
and is_fivefold_repetition()
are one-liners. can_claim_fifty_moves()
and can_claim_threefold_repetition()
require a loop over the legal moves, using the existing halfmove clock and repetition, so do not require more than a few lines.
yes I understand the difference now. I am gonna add these.
What is the status of these methods? Are you still planning to add them?
I want to emphasize that determining the draw on timeout requires the "has_insufficient_material(color: chess.Color" so this method has practical relevance, as the others. If player A runs out of time, but player B has insufficient material according to this method, meaning having no theoretical chance to checkmate, the game is a draw.
That is if you play according to the FIDE rules. I except you are using the FIDE rules, or are you supporting any other rules like USCF? There are differences here.
I put the python code below:
def is_insufficient_material(self) -> bool:
"""
Checks if neither side has sufficient winning material
(:func:`~chess.Board.has_insufficient_material()`).
"""
return all(self.has_insufficient_material(color) for color in COLORS)
def has_insufficient_material(self, color: Color) -> bool:
"""
Checks if *color* has insufficient winning material.
This is guaranteed to return ``False`` if *color* can still win the
game.
The converse does not necessarily hold:
The implementation only looks at the material, including the colors
of bishops, but not considering piece positions. So fortress
positions or positions with forced lines may return ``False``, even
though there is no possible winning line.
"""
if self.occupied_co[color] & (self.pawns | self.rooks | self.queens):
return False
# Knights are only insufficient material if:
# (1) We do not have any other pieces, including more than one knight.
# (2) The opponent does not have pawns, knights, bishops or rooks.
# These would allow selfmate.
if self.occupied_co[color] & self.knights:
return (popcount(self.occupied_co[color]) <= 2 and
not (self.occupied_co[not color] & ~self.kings & ~self.queens))
# Bishops are only insufficient material if:
# (1) We do not have any other pieces, including bishops of the
# opposite color.
# (2) The opponent does not have bishops of the opposite color,
# pawns or knights. These would allow selfmate.
if self.occupied_co[color] & self.bishops:
same_color = (not self.bishops & BB_DARK_SQUARES) or (not self.bishops & BB_LIGHT_SQUARES)
return same_color and not self.pawns and not self.knights
return True
Closing the issue as it became stale.
There are a few game end relevant methods not yet implemented. I suggest adding them to improve the API further.
The methods are mentioned below, taken from the python chess API:
has_insufficient_material(color: chess.Color)
is_seventyfive_moves() is_fivefold_repetition()
can_claim_draw() can_claim_fifty_moves() can_claim_threefold_repetition()