def check_game_over( self, message: Dict[str, str], bot_handler: Any, new_board: chess.Board ) -> bool: """Checks if a game is over due to - checkmate, - stalemate, - insufficient material, - 50 moves without a capture or pawn move, or - 3-fold repetition. Replies to the bot handler if it is game over. Parameters: - message: The Zulip Bots message object. - bot_handler: The Zulip Bots bot handler object. - new_board: The board object. Returns: True if it is game over, false if it's not. """ # This assumes that the players will claim a draw after 3-fold # repetition or 50 moves go by without a capture or pawn move. # According to the official rules, the game is only guaranteed to # be over if it's *5*-fold or *75* moves, but if either player # wants the game to be a draw, after 3 or 75 it a draw. For now, # just assume that the players would want the draw. if new_board.is_game_over(True): game_over_output = '' if new_board.is_checkmate(): game_over_output = make_loss_response( new_board, 'was checkmated' ) elif new_board.is_stalemate(): game_over_output = make_draw_response('stalemate') elif new_board.is_insufficient_material(): game_over_output = make_draw_response( 'insufficient material' ) elif new_board.can_claim_fifty_moves(): game_over_output = make_draw_response( '50 moves without a capture or pawn move' ) elif new_board.can_claim_threefold_repetition(): game_over_output = make_draw_response('3-fold repetition') bot_handler.send_reply( message, game_over_output ) return True return False
def write_json(self, board: chess.Board): """ Writes all of the board info in json """ best_move = self.get_best_move(board) output = OrderedDict([ ('fen', board.fen()), ('fullmoveNumber', board.fullmove_number), ('result', board.result()), ('isGameOver', board.is_game_over()), ('isCheckmate', board.is_checkmate()), ('isStalemate', board.is_stalemate()), ('isInsufficientMaterial', board.is_insufficient_material()), ('isSeventyfiveMoves', board.is_seventyfive_moves()), ('isFivefoldRepetition', board.is_fivefold_repetition()), ('white', OrderedDict([ ('hasKingsideCastlingRights', board.has_kingside_castling_rights(chess.WHITE)), ('hasQueensideCastlingRights', board.has_queenside_castling_rights(chess.WHITE)), ])), ('black', OrderedDict([ ('hasKingsideCastlingRights', board.has_kingside_castling_rights(chess.BLACK)), ('hasQueensideCastlingRights', board.has_queenside_castling_rights(chess.BLACK)), ])), ('turn', OrderedDict([ ('color', 'white' if board.turn is chess.WHITE else 'black'), ('isInCheck', board.is_check()), ('bestMove', best_move), ('legalMoves', [move.uci() for move in board.legal_moves]), ('canClaimDraw', board.can_claim_draw()), ('canClaimFiftyMoves', board.can_claim_fifty_moves()), ('canClaimThreefoldRepetition', board.can_claim_threefold_repetition()), ])), ]) self.finish(output)
def get_game_over_reason(board: chess.Board, claim_draw: bool = False, both_agreed: bool = False) -> str: if claim_draw and both_agreed: return "Both opponents agreed to a draw" reasons = [ "Checkmate", "Stalemate", "Insufficient material", "Draw by the seventyfive-move rule", "Draw by the fivefold repetition rule", ] checks = [ board.is_checkmate(), board.is_stalemate(), board.is_insufficient_material(), board.is_seventyfive_moves(), board.is_fivefold_repetition(), ] if claim_draw: reasons = [ *reasons, *[ "Draw by the fifty-move rule", "Draw by the threefold repetition rule" ], ] checks = [ *checks, *[ board.can_claim_fifty_moves(), board.can_claim_threefold_repetition() ], ] possible = [reason for reason, check in zip(reasons, checks) if check] if len(possible) > 0: return possible[0] else: raise RuntimeError("No possible game over reason")