为主教生成对角线移动的位板不起作用

Generating bitboard with diagonal moves for the bishop not working

我正在编写国际象棋人工智能程序。在尝试计算象的所有可能对角线移动时,我遇到了 运行 问题。我认为问题在于函数:reverse_bits()。我不认为我在我的程序中正确处理负二进制数,但我可能是错的。

# ranks
rank1 = int("0000000000000000000000000000000000000000000000000000000011111111", 2)
rank2 = int("0000000000000000000000000000000000000000000000001111111100000000", 2)
rank3 = int("0000000000000000000000000000000000000000111111110000000000000000", 2)
rank4 = int("0000000000000000000000000000000011111111000000000000000000000000", 2)
rank5 = int("0000000000000000000000001111111100000000000000000000000000000000", 2)
rank6 = int("0000000000000000111111110000000000000000000000000000000000000000", 2)
rank7 = int("0000000011111111000000000000000000000000000000000000000000000000", 2)
rank8 = int("1111111100000000000000000000000000000000000000000000000000000000", 2)

# files
filea = int("1000000010000000100000001000000010000000100000001000000010000000", 2)
fileb = int("0100000001000000010000000100000001000000010000000100000001000000", 2)
filec = int("0010000000100000001000000010000000100000001000000010000000100000", 2)
filed = int("0001000000010000000100000001000000010000000100000001000000010000", 2)
filee = int("0000100000001000000010000000100000001000000010000000100000001000", 2)
filef = int("0000010000000100000001000000010000000100000001000000010000000100", 2)
fileg = int("0000001000000010000000100000001000000010000000100000001000000010", 2)
fileh = int("0000000100000001000000010000000100000001000000010000000100000001", 2)

# diagonals
d0 = int("0000000100000000000000000000000000000000000000000000000000000000", 2)
d1 = int("0000001000000001000000000000000000000000000000000000000000000000", 2)
d2 = int("0000010000000010000000010000000000000000000000000000000000000000", 2)
d3 = int("0000100000000100000000100000000100000000000000000000000000000000", 2)
d4 = int("0001000000001000000001000000001000000001000000000000000000000000", 2)
d5 = int("0010000000010000000010000000010000000010000000010000000000000000", 2)
d6 = int("0100000000100000000100000000100000000100000000100000000100000000", 2)
d7 = int("1000000001000000001000000001000000001000000001000000001000000001", 2)
d8 = int("0000000010000000010000000010000000010000000010000000010000000010", 2)
d9 = int("0000000000000000100000000100000000100000000100000000100000000100", 2)
d10 = int("0000000000000000000000001000000001000000001000000001000000001000", 2)
d11 = int("0000000000000000000000000000000010000000010000000010000000010000", 2)
d12 = int("0000000000000000000000000000000000000000100000000100000000100000", 2)
d13 = int("0000000000000000000000000000000000000000000000001000000001000000", 2)
d14 = int("0000000000000000000000000000000000000000000000000000000010000000", 2)

# anti-diagonal

ad0 = int("1000000000000000000000000000000000000000000000000000000000000000", 2)
ad1 = int("0100000010000000000000000000000000000000000000000000000000000000", 2)
ad2 = int("0010000001000000100000000000000000000000000000000000000000000000", 2)
ad3 = int("0001000000100000010000001000000000000000000000000000000000000000", 2)
ad4 = int("0000100000010000001000000100000010000000000000000000000000000000", 2)
ad5 = int("0000010000001000000100000010000001000000100000000000000000000000", 2)
ad6 = int("0000001000000100000010000001000000100000010000001000000000000000", 2)
ad7 = int("0000000100000010000001000000100000010000001000000100000010000000", 2)
ad8 = int("0000000000000001000000100000010000001000000100000010000001000000", 2)
ad9 = int("0000000000000000000000010000001000000100000010000001000000100000", 2)
ad10 = int("0000000000000000000000000000000100000010000001000000100000010000", 2)
ad11 = int("0000000000000000000000000000000000000001000000100000010000001000", 2)
ad12 = int("0000000000000000000000000000000000000000000000010000001000000100", 2)
ad13 = int("0000000000000000000000000000000000000000000000000000000100000010", 2)
ad14 = int("0000000000000000000000000000000000000000000000000000000000000001", 2)

# masks
rankmask = [rank1, rank2, rank3, rank4, rank5, rank6, rank7, rank8]
filemask = [filea, fileb, filec, filed, filee, filef, fileg, fileh]
diagonal = [d14, d13, d12, d11, d10, d9, d8, d7, d6, d5, d4, d3, d2, d1, d0]
antidiagonal = [ad14, ad13, ad12, ad11, ad10, ad9, ad8, ad7, ad6, ad5, ad4, ad3, ad2, ad1, ad0]
last_black_pm = [53, 45]

# bitboards

wp = 0
wr = 0
wn = 0
wb = 0
wq = 0
wk = 0
bp = 0
br = 0
bn = 0
bb = 0
bq = 0
bk = 0


def print_bitboard(bitboard):
    board = '{:064b}'.format(bitboard)
    for i in range(8):
        print(board[8*i+0] + " " + board[8*i+1] + " " + board[8*i+2] + " " + board[8*i+3] + " " + board[8*i+4] + " " + board[8*i+5] + " " + board[8*i+6] + " " + board[8*i+7])


def print_chess_board(bitboard):
    board = bitboard
    for i in range(8):
        print(board[8*i+0] + " " + board[8*i+1] + " " + board[8*i+2] + " " + board[8*i+3] + " " + board[8*i+4] + " " + board[8*i+5] + " " + board[8*i+6] + " " + board[8*i+7])


def integer_to_bitboard(integer):
    bitboard = '{:064b}'.format(integer)
    return bitboard


def create_starting_bitboards():
    global last_black_pm, wp, wr, wn, wb, wq, wk, bp, bn, bb, bq, bk, br
    bitboard_all_pieces = "rnbqkbnrpppppppp0000000000B000000000000000000000PPPPPPPPRNBQKBNR"
    print_chess_board(bitboard_all_pieces)

    for i in range(64):
        if bitboard_all_pieces[i] == "P":
            wp += 2**(63-i)
        if bitboard_all_pieces[i] == "R":
            wr += 2**(63-i)
        if bitboard_all_pieces[i] == "N":
            wn += 2**(63-i)
        if bitboard_all_pieces[i] == "B":
            wb += 2**(63-i)
        if bitboard_all_pieces[i] == "Q":
            wq += 2**(63-i)
        if bitboard_all_pieces[i] == "K":
            wk += 2**(63-i)
        if bitboard_all_pieces[i] == "p":
            bp += 2**(63-i)
        if bitboard_all_pieces[i] == "r":
            br += 2**(63-i)
        if bitboard_all_pieces[i] == "n":
            bn += 2**(63-i)
        if bitboard_all_pieces[i] == "b":
            bb += 2**(63-i)
        if bitboard_all_pieces[i] == "q":
            bq += 2**(63-i)
        if bitboard_all_pieces[i] == "k":
            bk += 2**(63-i)

    occupied = wp | wr | wn | wb | wq | wk | bp | br | bn | bb | bq | bk

    # g_white_pawn_moves(wp, wr, wn, wb, wq, wk, bp, br, bn, bb, bq, bk)

    g_white_bishop_moves(wp, wr, wn, wb, wq, wk, occupied)


def reverse_bits(num):
    num = '{:064b}'.format(num)[::-1]
    if num[-1] == "-":
        num = num[:-1]
    return int(num, 2)


def vertical_horizontal_moves(s, occupied):
    global rankmask, filemask
    ranknum = int(s/8)
    filenum = 7 - int(s % 8)
    slider = 1 << s
    horizontal = ((occupied - 2*slider) ^ reverse_bits(reverse_bits(occupied)-2*reverse_bits(slider))) & rankmask[ranknum]
    vertical = (((occupied & filemask[filenum]) - 2 * slider) ^ reverse_bits(reverse_bits(occupied & filemask[filenum]) - 2 * reverse_bits(slider))) & filemask[filenum]
    print_bitboard(vertical ^ horizontal)
    return vertical ^ horizontal


def diagonal_antidiagonal_moves(s, occupied):
    global diagonal, antidiagonal
    diagonalnum = 7 - int(s % 8) + int(s/8)
    antidiagonalnum = int(s / 8) + int(s % 8)
    slider = 1 << s
    diag1 = (((occupied & diagonal[diagonalnum]) - 2 * slider) ^ reverse_bits(reverse_bits(occupied & diagonal[diagonalnum]) - 2 * reverse_bits(slider))) & diagonal[diagonalnum]
    diag2 = (((occupied & antidiagonal[antidiagonalnum]) - 2 * slider) ^ reverse_bits(reverse_bits(occupied & antidiagonal[antidiagonalnum]) - 2 * reverse_bits(slider))) & antidiagonal[antidiagonalnum]
    return diag1 ^ diag2


def g_white_bishop_moves(wp, wr, wn, wb, wq, wk, occupied):
    white_pieces = wp | wr | wn | wb | wq | wk
    moves_list = []
    for i in range(64):
        if (wb >> i) & 1 == 1:
            moves = diagonal_antidiagonal_moves(i, occupied) & ~white_pieces
            for j in range(64):
                if (moves >> j) & 1 == 1:
                    moves_list.extend((i, j))

    print("")
    print_bitboard(moves)


def g_white_pawn_moves(wp, wr, wn, wb, wq, wk, bp, br, bn, bb, bq, bk):
    global rank8, rank4, rank5, fileh, filea, filemask
    empty = ~(wp | wr | wn | wb| wq | wk | bp | br | bn | bb | bq | bk)
    black = bp | br | bn | bb | bq
    moves_list = []

    # pawn 1 forward
    moves = (wp << 8) & empty & ~ rank8
    for i in range(64):
        if (moves >> i) & 1 == 1:
            moves_list.extend((i-8, i, ""))

    # pawn 2 forward
    moves = (wp << 16) & empty & (empty << 8) & rank4
    for i in range(64):
        if (moves >> i) & 1 == 1:
            moves_list.extend((i-16, i, ""))

    # pawn left capture
    moves = (wp << 9) & black & ~ rank8 & ~ fileh
    for i in range(64):
        if (moves >> i) & 1 == 1:
            moves_list.extend((i - 9, i, ""))

    # pawn right capture
    moves = (wp << 7) & black & ~ rank8 & ~ filea
    for i in range(64):
        if (moves >> i) & 1 == 1:
            moves_list.extend((i - 9, i, ""))

    # en passant
    if last_black_pm[0] - last_black_pm[1] == 16:
        filenum = 7 - int(last_black_pm[1] % 8)

        # en passant left
        moves = (wp << 1) & black & rank5 & ~fileh & filemask[filenum]  # pawn_capture_right
        for i in range(64):
            if (moves >> i) & 1 == 1:
                moves_list.extend((i - 1, i + 8, "E"))  # store piece field/ and move field 0-63
        # en passant right
        moves = (wp >> 1) & black & rank5 & ~filea & filemask[filenum]  # pawn_capture_left
        for i in range(64):
            if (moves >> i) & 1 == 1:
                moves_list.extend((i + 1, i + 8, "E"))  # store piece field/ and move field 0-63

    # pawn promotion
    # pawn 1 forward
    moves = (wp << 8) & empty & rank8
    for i in range(64):
        if (moves >> i) & 1 == 1:
            moves_list.extend((i - 8, i, "P"))
    # pawn left capture
    moves = (wp << 9) & black & rank8 & ~ fileh
    for i in range(64):
        if (moves >> i) & 1 == 1:
            moves_list.extend((i - 9, i, "P"))

    # pawn right capture
    moves = (wp << 7) & black & rank8 & ~ filea
    for i in range(64):
        if (moves >> i) & 1 == 1:
            moves_list.extend((i - 9, i, "P"))

    print(moves_list)


create_starting_bitboards()

例如在这种情况下,它会正确计算出所有可能的主教移动:

r n b q k b n r
p p p p p p p p
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 B 0 0 0 0 0
0 0 0 0 0 0 0 0
P P P P P P P P
R N B Q K B N R

0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0
1 0 0 0 1 0 0 0
0 1 0 1 0 0 0 0
0 0 0 0 0 0 0 0
0 1 0 1 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0

但是当我将主教移动到另一个方格时,会发生这种情况:

r n b q k b n r
p p p p p p p p
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 B 0 0 0 0 0 0
0 0 0 0 0 0 0 0
P P P P P P P P
R N B Q K B N R

0 0 0 0 0 1 0 0
0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0

当我检查名为 diagonal_antidiagonal_moves() 的函数中的代码时,它找到了所有 diagonal/antidiagonal 步,我开始打印出不同的位板。我注意到一些位板上有“-”符号。例如我拿了: reverse_bits(occupied & antidiagonal[antidiagonalnum]) - 2 * reverse_bits(slider) from

diag2 = (((occupied & antidiagonal[antidiagonalnum]) - 2 * slider) ^ reverse_bits(reverse_bits(occupied & antidiagonal[antidiagonalnum]) - 2 * reverse_bits(slider))) & antidiagonal[antidiagonalnum]

并打印出位板。这是结果:

- 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 0 1 1 1 1
1 1 1 0 0 0 0 0

这就是为什么我认为我在reverse_bits-函数中反转负整数时一定有问题。

有趣的是,函数 vertical_horizontal_moves() 用于查找所有可能的车移动,似乎工作得很好。

我希望有人能告诉我我的代码到底出了什么问题。

正如您所怀疑的,

reverse_bits 确实是错误的。这很容易用一个例子来证明:reverse_bits(-1) returns 值 0x4000000000000000。

reverse_bits 的当前实现已经适用于非负数,因此可以通过屏蔽输入将其变为非负数同时保留与此上下文相关的所有位(最低 64 ):

def reverse_bits(num):
    num = num & 0xffffffffffffffff
    num = '{:064b}'.format(num)[::-1]
    return int(num, 2)