Exemple #1
0
def simulate_move(board, move):
    if move == chess.Move.null():
        return None
    # if its a legal move, don't change it at all (generate_pseudo_legal_moves does not include pseudo legal castles)
    if move in board.generate_pseudo_legal_moves() or is_psuedo_legal_castle(board, move):
        return move
    if is_illegal_castle(board, move):
        return None
    # if the piece is a sliding piece, slide it as far as it can go
    piece = board.piece_at(move.from_square)
    if piece.piece_type in [chess.PAWN, chess.ROOK, chess.BISHOP, chess.QUEEN]:
        move = slide_move(board, move)
    return move if move in board.generate_pseudo_legal_moves() else None
def get_moves(board: chess.Board) -> List[chess.Move]:
    """ Accounts for the ability to castle through check. """
    return list(set(board.pseudo_legal_moves) | set(move for move in util.moves_without_opponent_pieces(board) if util.is_psuedo_legal_castle(board, move)))
    def choose_move(self, move_actions: List[chess.Move], seconds_left: float) -> Optional[chess.Move]:
        if seconds_left <= 20:
            return None
        # skip analyzing if in replay and colors don't match
        if REPLAY and self.turn_number % 2 != REPLAYCOLOR:
            return

        table = {}
        start = time.time()

        # Ability to pass
        moves = list(set(move for board in self.states for move in get_moves(board))) + [None]

        # Refresh engine
        self.engine = chess.engine.SimpleEngine.popen_uci(os.environ[STOCKFISH_ENV_VAR])
        # If only one board just let stockfish play it
        if len(self.states) == 1:
            board = self.states[0]
            # overwrite stockfish only if we are able to take the king this move
            # OR in checkmate but are able to castle out
            for move in get_moves(board):
                # assert board.turn == self.color
                if move.to_square == board.king(self.opponent_color):
                    return move
                elif board.is_checkmate() and util.is_psuedo_legal_castle(board, move):
                    return move

            # weird UCI exception stuff on valid board
            try:
                board.clear_stack()
                r = self.engine.play(board, chess.engine.Limit(time=(MIN_TIME + MAX_TIME)/2))
                best, score = r.move, r.info.get("score", "unknown")
            # default to move analysis
            except Exception as e:
                logger.error("Caught Stockfish error as " + str(self.color) + " (move may not be accurate)")
                logger.error("Error: " + str(e))
                while(1):
                    pass
                limit = find_time(len(moves))
                table = {move: (evaluate(board, move, self.color) if evaluate(board, move, self.color) is not None else self.stkfsh_eval(board, move, limit))
                         for move in moves}
                best = max(table, key=lambda move: table[move])
                score = table[best]
        else:
            states = self.remove_boards()
            node_count = len(moves)*len(states)
            logger.info(f"Number of nodes to analyze: {node_count}")
            limit = find_time(node_count)

            for move in moves:
                for state in states:
                    state.turn = self.color
                    # move is invalid and equivalent to a pass
                    new_move = result(state, move)
                    points = evaluate(state, new_move, self.color)

                    if points is None:
                        points = self.stkfsh_eval(state, new_move, limit)

                    # assuming probability is constant, may change later
                    table[move] = table.get(move, 0) + points/len(states)

            if len(table) == 0: return

            best = max(table, key=lambda move: table[move])
            score = table[best]

        logger.info(f"{best} {score if isinstance(score, str) else round(score, 2)}")
        logger.info(f"Time left before starting calculations for current move: {time_str(seconds_left)}")
        logger.info(f"Time left now: {time_str(seconds_left - time.time() + start)}")
        logger.debug(f"{ {str(k): round(v, 2) for k, v in table.items()} }")
        return best