为主教生成带有对角线移动的位板

时间:2019-02-17 18:09:01

标签: python chess bitboard

我正在为国际象棋编程。尝试计算主教的所有可能对角线移动时遇到问题。我认为问题出在函数内部: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

当我检查函数中对角线(对角线/反对角线的移动)时,发现对角线/反对角线的所有代码时,我开始打印出不同的位板。我注意到某些位板在其上带有“-”号。例如,我采取了以下方法:reverse_bits(已占用和antidiagonal [antidiagonalnum])-2 *来自* p的reverse_bits(slider)

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_horizo​​ntal_moves()似乎工作正常。

我希望有人能给我一个思路,以了解我的代码到底出了什么问题。

1 个答案:

答案 0 :(得分:0)

reverse_bits is indeed wrong, as you suspect. This is easy to prove with an example: reverse_bits(-1) returns the value 0x4000000000000000.

The current implementation of reverse_bits already works for non-negative numbers, so it can be repaired by masking the input to turn it non-negative while retaining all the bits relevant in this context (the lowest 64):

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