0

我正在编写一个国际象棋引擎,并试图让它尽可能快,所以我使用位板来表示每种类型的棋子。我正在打印每个层的不同板状态的数量(层 = 1 人移动),而在第 4 层上它得到了错误的数字。

有没有办法在不筛选所有 200k 4 层位置的情况下找出问题所在?

另外,请注意,我还没有实施易位、检查、过路、典当提升或任何平局规则,因为它们在第 4 次之前都不会产生任何影响。

维基百科链接给出了每层板状态的数量,与我的相比:20、400、8902、197742)

import json

with open('White_Pawn.json', 'r') as f:
    white_pawn_table = json.load(f)
    white_pawn_table = {int(q):w for q, w in white_pawn_table.items()}

with open('White_Pawn_Captures.json', 'r') as f:
    white_pawn_captures_table = json.load(f)
    white_pawn_captures_table = {int(q):w for q, w in white_pawn_captures_table.items()}

with open('Black_Pawn.json', 'r') as f:
    black_pawn_table = json.load(f)
    black_pawn_table = {int(q):w for q, w in black_pawn_table.items()}

with open('Black_Pawn_Captures.json', 'r') as f:
    black_pawn_captures_table = json.load(f)
    black_pawn_captures_table = {int(q):w for q, w in black_pawn_captures_table.items()}

with open('Knight.json', 'r') as f:
    knight_table = json.load(f)
    knight_table = {int(q):w for q, w in knight_table.items()}

with open('Bishop.json', 'r') as f:
    bishop_table = json.load(f)
    bishop_table = {int(q):w for q, w in bishop_table.items()}

with open('Rook.json', 'r') as f:
    rook_table = json.load(f)
    rook_table = {int(q):w for q, w in rook_table.items()}

string_to_int = lambda x:int(x, 2)
int_to_string = lambda x:'0' * (66 - len(bin(x))) + bin(x)[2:]
x_in_y = lambda x, y:(x & y) != 0

def show(x):
    for q in range(8):
        print(' '.join([w for w in x[(q * 8):((q + 1) * 8)]]))
    print()

class Board:
    def __init__(self, args = False):
        if args:
            self.maps, self.turn = args
        else:
            self.maps, self.turn = {'White Pawns':65280, 'White Knights':66, 'White Bishops':36, 'White Rooks':129, 'White Queens':16, 'White Kings':8, 'Black Pawns':71776119061217280, 'Black Knights':4755801206503243776, 'Black Bishops':2594073385365405696, 'Black Rooks':9295429630892703744, 'Black Queens':1152921504606846976, 'Black Kings':576460752303423488}, 1

    def move(self, colour, not_colour, piece, move):
        board = Board(args = (self.maps.copy(), not self.turn))

        board.maps[f'{colour} {piece}s'] ^= move[0]
        board.maps[f'{colour} {piece}s'] |= move[1]

        for q in board.maps:
            if not_colour in q:
                board.maps[q] &= ~move[1]

        return board

    def moves(self):
        # Get Pieces and Colours
        colour, not_colour = ['White', 'Black'][::self.turn if self.turn else -1]
        pieces, not_pieces = 0, 0
        for q, w in self.maps.items():
            if colour in q:
                pieces |= w
            else:
                not_pieces |= w

        # Pawn
        if colour == 'White':
            move_table, capture_table = white_pawn_table, white_pawn_captures_table
        else:
            move_table, capture_table = black_pawn_table, black_pawn_captures_table

        temp_pawns = self.maps[f'{colour} Pawns']
        while temp_pawns:
            pawn = temp_pawns & -temp_pawns
            temp_pawns ^= pawn

            for next_pawn in move_table[pawn]:
                if x_in_y(next_pawn, pieces | not_pieces):
                    break
                else:
                    yield self.move(colour, not_colour, 'Pawn', (pawn, next_pawn))
            
            for next_pawn in capture_table[pawn]:
                if x_in_y(next_pawn, not_pieces):
                    yield self.move(colour, not_colour, 'Pawn', (pawn, next_pawn))

        # Knight
        temp_knights = self.maps[f'{colour} Knights']
        while temp_knights:
            knight = temp_knights & -temp_knights
            temp_knights ^= knight

            for next_knight in knight_table[knight]:
                if not x_in_y(next_knight, pieces):
                    yield self.move(colour, not_colour, 'Knight', (knight, next_knight))
        
        # Bishop
        temp_bishops = self.maps[f'{colour} Bishops']
        while temp_bishops:
            bishop = temp_bishops & -temp_bishops
            temp_bishops ^= bishop

            for direction in bishop_table[bishop]:
                for next_bishop in direction:
                    if x_in_y(next_bishop, pieces): break

                    yield self.move(colour, not_colour, 'Bishop', (bishop, next_bishop))

                    if x_in_y(next_bishop, not_pieces): break

        # Rook
        temp_rooks = self.maps[f'{colour} Rooks']
        while temp_rooks:
            rook = temp_rooks & -temp_rooks
            temp_rooks ^= rook

            for direction in rook_table[rook]:
                for next_rook in direction:
                    if x_in_y(next_rook, pieces): break

                    yield self.move(colour, not_colour, 'Rook', (rook, next_rook))

                    if x_in_y(next_rook, not_pieces): break
        
        # Queen
        temp_queens = self.maps[f'{colour} Queens']
        while temp_queens:
            queen = temp_queens & -temp_queens
            temp_queens ^= queen

            for direction in rook_table[queen]:
                for next_queen in direction:
                    if x_in_y(next_queen, pieces): break

                    yield self.move(colour, not_colour, 'Queen', (queen, next_queen))

                    if x_in_y(next_queen, not_pieces): break

            for direction in bishop_table[queen]:
                for next_queen in direction:
                    if x_in_y(next_queen, pieces): break

                    yield self.move(colour, not_colour, 'Queen', (queen, next_queen))

                    if x_in_y(next_queen, not_pieces): break

        # King
        king = self.maps[f'{colour} Kings']
        for direction in rook_table[king]:
            next_king = direction[0]
            if not x_in_y(next_king, pieces):
                yield self.move(colour, not_colour, 'King', (king , next_king))

        for direction in bishop_table[king]:
            next_king = direction[0]
            if not x_in_y(next_king, pieces):
                yield self.move(colour, not_colour, 'King', (king, next_king))

    def next_states(self):
        for q in self.moves():
            yield q

    def __str__(self):
        find = {'Black Kings':'♔ ', 'Black Queens':'♕ ', 'Black Rooks':'♖ ', 'Black Bishops':'♗ ', 'Black Knights':'♘ ', 'Black Pawns':'♙ ', 'White Pawns':'♟ ', 'White Knights':'♞ ', 'White Bishops':'♝ ', 'White Rooks':'♜ ', 'White Queens':'♛ ', 'White Kings':'♚ '}
        map = lambda y:([q for q in self.maps if self.maps[q] & (2**y)] + [False])[0]
        output = '    A    B    C    D    E    F    G    H\n  ╔════╤════╤════╤════╤════╤════╤════╤════╗\n'
        for q in range(8):
            if q % 2 == 0:
                output += '%i ║ %s │░%s░│ %s │░%s░│ %s │░%s░│ %s │░%s░║ %i\n  ╟────┼────┼────┼────┼────┼────┼────┼────╢\n' % tuple([8 - q] + [find[map(q * 8 + w)] if map(q * 8 + w) else '  ' if w % 2 == 0 else '░░' for w in range(8)] + [8 - q])
            else:
                output += '%i ║░%s░│ %s │░%s░│ %s │░%s░│ %s │░%s░│ %s ║ %i\n  ╟────┼────┼────┼────┼────┼────┼────┼────╢\n' % tuple([8 - q] + [find[map(q * 8 + w)] if map(q * 8 + w) else '░░' if w % 2 == 0 else '  ' for w in range(8)] + [8 - q])

        output += '\x1b[1A\x1b[2K' + '  ╚════╧════╧════╧════╧════╧════╧════╧════╝\n    A    B    C    D    E    F    G    H'
        return output

chess = Board()

next_states = [chess]
while True:
    current_states, next_states = next_states, []

    for state in current_states:
        for next_state in state.next_states():
            next_states.append(next_state)

    print(len(next_states))

json 文件太大,无法放在这里,但您可以假设它们是正确的。每个文件都有一个带有键 2^0-2^63 的字典,每个键代表文件命名的片段的可能位置。这些值是他们可以从那里去的不同位置。

4

2 回答 2

3
1.  e2-e3
2.  d7-d6
3. Bf1-b5 +

黑王现在被控制住了,所以第四层的步数更加有限。您需要实施检查规则才能获得正确的号码。

于 2022-02-06T19:02:47.923 回答
0
1. e2-e4 f7-f5
2. Bf1-b5

d7 处的 Pawn 被固定,无法移动。

于 2022-02-06T19:12:42.547 回答