Example #1
0
 def get_state_planes(self):
     """Transform the current board state to a plane"""
     return board_to_planes(
         self.board,
         board_occ=self._board_occ,
         normalize=True,
         crazyhouse_only=main_config['policy_version'] == 1)
def board_to_planes(board, board_occ=0, normalize=True):
    """
    Gets the plane representation of a given board state.
    (No history of past board positions is used.)

    ## Crazyhouse:

    Feature | Planes

    --- | ---

    P1 piece | 6 (pieces are ordered: PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING)

    P2 piece | 6 (pieces are ordered: PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING)

    Repetitions | 2 (two planes (full zeros/ones) indicating how often the board positions has occurred)

    P1 prisoner count | 5 (pieces are ordered: PAWN, KNIGHT, BISHOP, ROOK, QUEEN) (excluding the KING)

    P2 prisoner count | 5 (pieces are ordered: PAWN, KNIGHT, BISHOP, ROOK, QUEEN) (excluding the KING)

    P1 Promoted Pawns Mask | 1 (binary map indicating the pieces which have been promoted)

    P2 Promoted Pawns Mask | 1 (binary map indicating the pieces which have been promoted)

    En-passant square | 1 (Binary map indicating the square where en-passant capture is possible)

    ---
    27 planes

    * * *

    Colour | 1 (all zeros for black and all ones for white)

    Total move count | 1 (integer value setting the move count (uci notation))

    P1 castling | 2 (One if castling is possible, else zero)

    P2 castling | 2 (One if castling is possible, else zero)

    No-progress count | 1 (Setting the no progress counter as integer values, (described by uci halfmoves format)

    # --------------
    7 planes

    The history list of the past 7 board states have been removed
    The total number of planes is calculated as follows:

    27 + 7
    Total: 34 planes

    :param board: Board handle (Python-chess object)
    :param board_occ: Sets how often the board state has occurred before (by default 0)
    :param normalize: True if the inputs shall be normalized to the range [0.-1.]
    :return: planes - the plane representation of the current board state
    """

    # return the plane representation of the given board
    return variants.board_to_planes(board, board_occ, normalize, mode=MODE_CRAZYHOUSE)
Example #3
0
def board_to_planes(board, board_occ=0, normalize=True):
    """
    Gets the plane representation of a given board state.
    (No history of past board positions is used.)

    ## Chess:

    Feature | Planes

    --- | ---

    P1 piece | 6 (pieces are ordered: PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING)

    P2 piece | 6 (pieces are ordered: PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING)

    Repetitions | 2 (two planes (full zeros/ones) indicating how often the board positions has occurred)

    En-passant square | 1 (Binary map indicating the square where en-passant capture is possible)

    ---
    15 planes

    * * *

    Colour | 1 (all zeros for black and all ones for white)

    Total move count | 1 (integer value setting the move count (uci notation))

    P1 castling | 2 (One if castling is possible, else zero)

    P2 castling | 2 (One if castling is possible, else zero)

    No-progress count | 1 (Setting the no progress counter as integer values, (described by uci halfmoves format)

    ---
    7 planes

    * * *

    Last 8 moves | 16 (indicated by origin and destination square, the most recent move is described by first 2 planes)

    ---
    16 planes

    * * *

    is960 = | 1 (boolean, 1 when active)

    ---
    1 plane

    The total number of planes is calculated as follows:
    # --------------
    15 + 7 + 1 + 16
    Total: 39 planes

    :param board: Board handle (Python-chess object)
    :param board_occ: Sets how often the board state has occurred before (by default 0)
    :param normalize: True if the inputs shall be normalized to the range [0.-1.]
    :return: planes - the plane representation of the current board state
    """

    # return the plane representation of the given board
    return variants.board_to_planes(board,
                                    board_occ,
                                    normalize,
                                    mode=MODE_CHESS)
Example #4
0
def get_planes_from_game(game, mate_in_one=False):
    """
    Returns all plane descriptions of a given game and their corresponding target values:
    - the game outcome (-1, 0, 1)
    - the next move which will be played in each position

    :param game: Game handle which is a python-chess object
    (e.g. mv_hist_len = 8 means that the current position and the 7 previous positions are exported)
    :param mate_in_one: Decide weather only to export the position before the last mate-in-one move
                        (this option is for evaluation and DEBUG purposes)
    :return: x - the position description of all moves in the game
             y_value - the target values of the scene description. Here the game outcome.
                  returns -1 if the current player lost, +1 if the current player won, 0 for draw
             y_policy - the policy vector one-hot encoded indicating the next move the player current player chose
              in this position
             plys_to_end - array of how many plys to the end of the game for each position.
              This can be used to apply discounting
    """

    fen_dic = {
    }  # A dictionary which maps the fen description to its number of occurrences
    x = []
    y_value = []
    y_policy = []
    board = game.board()  # get the initial board state
    # update the y value accordingly
    if board.turn == chess.WHITE:
        y_init = 1
    else:
        y_init = -1
    if game.headers["Result"] == "0-1":
        y_init *= -1
    elif game.headers["Result"] == "1/2-1/2":
        y_init = 0

    all_moves = []  # Extract all moves first and save them into a list
    for move in game.main_line():
        all_moves.append(move)
    # Iterate through all moves (except the last one) and play them on a board.
    # you don't want to push the last move on the board because you had no movement policy to learn from in this case
    # The moves get pushed at the end of the for-loop and is only used in the next loop.
    # Therefore we can iterate over 'all' moves
    plys = 0
    for move in all_moves:
        board_occ = 0  # by default the positions hasn't occurred before
        fen = board.fen()
        # remove the halfmove counter & move counter from this fen to make repetitions possible
        fen = fen[:fen.find(" ") + 2]
        # save the board state to the fen dictionary
        if fen in list(fen_dic.keys()):
            board_occ = fen_dic[fen]
            fen_dic[fen] += 1
        else:
            fen_dic[fen] = 1  # create a new entry
        # we insert the move i (and not i+1), because the start is the empty board position
        next_move = all_moves[plys]

        # check if you need to export a mate_in_one_scenario
        if not mate_in_one or plys == len(all_moves) - 1:
            # build the last move vector by putting the most recent move on top followed by the remaining past moves
            last_moves = [None] * NB_LAST_MOVES
            if plys != 0:
                last_moves[0:min(plys, NB_LAST_MOVES)] = all_moves[
                    max(plys - NB_LAST_MOVES, 0):plys][::-1]

            # receive the board and the evaluation of the current position in plane representation
            # We don't want to store float values because the integer datatype is cheaper,
            #  that's why normalize is set to false
            x_cur = board_to_planes(board,
                                    board_occ,
                                    normalize=False,
                                    mode=main_config["mode"],
                                    last_moves=last_moves)

            # add the evaluation of 1 position to the list
            x.append(x_cur)
            y_value.append(y_init)
            # add the next move defined in policy vector notation to the policy list
            # the network always sees the board as if he's the white player, that's the move is mirrored fro black
            y_policy.append(
                move_to_policy(next_move, is_white_to_move=board.turn))

        y_init *= -1  # flip the y_init value after each move
        board.push(move)  # push the next move on the board
        plys += 1

    plys_to_end = np.arange(plys)[::-1]

    # check if there has been any moves
    if x and y_value and y_policy:
        x = np.stack(x, axis=0)
        y_value = np.stack(y_value, axis=0)
        y_policy = np.stack(y_policy, axis=0)
    else:
        print("game.headers:")
        print(game.headers)
        print("len(all_moves)", len(all_moves))
        print("game", game)
        raise Exception("The given pgn file's mainline is empty!")

    return x, y_value, y_policy, plys_to_end
def board_to_planes(board, board_occ=0, normalize=True):
    """
    Gets the plane representation of a given board state.
    (No history of past board positions is used.)

    ## Chess Variants:

    Feature | Planes

    --- | ---

    P1 piece | 6 (pieces are ordered: PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING)

    P2 piece | 6 (pieces are ordered: PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING)

    Repetitions | 2 (two planes (full zeros/ones) indicating how often the board positions has occurred)

    P1 prisoner count | 5 (pieces are ordered: PAWN, KNIGHT, BISHOP, ROOK, QUEEN) (excluding the KING)

    P2 prisoner count | 5 (pieces are ordered: PAWN, KNIGHT, BISHOP, ROOK, QUEEN) (excluding the KING)

    P1 Promoted Pawns Mask | 1 (binary map indicating the pieces which have been promoted)

    P2 Promoted Pawns Mask | 1 (binary map indicating the pieces which have been promoted)

    En-passant square | 1 (Binary map indicating the square where en-passant capture is possible)

    ---
    27 planes

    * * *

    Colour | 1 (all zeros for black and all ones for white)

    Total move count | 1 (integer value setting the move count (uci notation))

    P1 castling | 2 (One if castling is possible, else zero)

    P2 castling | 2 (One if castling is possible, else zero)

    No-progress count | 1 (Setting the no progress counter as integer values, (described by uci halfmoves format)

    P1 remaining-checks | 2 (only needed for the 3check variant, after 3 checks by one player the game ends)

    P2 remaining-checks | 2 (only needed for the 3check variant, after 3 checks by one player the game ends)

    ---
    11 planes

    * * *

    is960 = | 1 (boolean, 1 when active)

    Variants indicator each variant gets a whole channel assigned. All variants are one-hot encoded

    1 - "chess" | 1
    2 - "crazyhouse" | 1
    3 - "kingofthehill" | 1
    4 - "3check" | 1
    5 - "giveaway" | 1
    6 - "atomic" | 1
    7 - "horde" | 1
    8 - "racingkings" | 1

    ---
    9 planes

    # --------------

    * * *

    Last 8 moves | 16 (indicated by origin and destination square, the most recent move is described by first 2 planes)
    -> added since version 2

    ---
    16 planes

    The total number of planes is calculated as follows:

    27 + 11 + 9 + 16
    Total: 63 planes (version 2)
    Total: 47 planes (version 1)

    :param board: Board handle (Python-chess object)
    :param board_occ: Sets how often the board state has occurred before (by default 0)
    :param normalize: True if the inputs shall be normalized to the range [0.-1.]
    :param mode: 0 - MODE_CRAZYHOUSE: Crazyhouse only specification.
                 (Visit variants.crazyhouse.input_representation for detailed documentation)
                 1 - MODE_LICHESS: Specification for all supported variants on lichess.org
                 (Visit variants.lichess.input_representation for detailed documentation)
                 2 - MODE_CHESS: Specification for chess only with chess960 support
                 (Visit variants.chess.input_representation for detailed documentation)
    :return: planes - the plane representation of the current board state
    """

    # return the plane representation of the given board
    return variants.board_to_planes(board,
                                    board_occ,
                                    normalize,
                                    mode=MODE_LICHESS)
Example #6
0
 def get_state_planes(self):
     """Transform the current board state to a plane"""
     return board_to_planes(self.board,
                            board_occ=self._board_occ,
                            normalize=True,
                            mode=main_config['mode'])