# White Constants W_KIN, W_QUE, W_BIS, W_NHT, W_ROO, W_PAW = range(6) # Black Constans B_KIN, B_QUE, B_BIS, B_NHT, B_ROO, B_PAW = range(6,12) # Turn Constants WHITE, BLACK = 0, 1 # Piece Constants KIN, QUE, BIS, NHT, ROO, PAW = range(6) NO_PIECE = 15 # 0 = Normaler Zug (Quiet Move) QUIET = 0 # 1 = Doppelschritt Bauer (wichtig für En Passant im nächsten Zug) DOUBLE_PAWN_PUSH = 1 # 2 & 3 = Rochaden KING_CASTLE = 2 QUEEN_CASTLE = 3 # 4 = Normaler Schlagzug (Capture) # Manche Engines codieren Captures extra, manche schauen einfach aufs Brett. # Für den Anfang reicht es, Captures einfach als Flag 4 zu markieren. CAPTURE = 4 # 5 = En Passant Schlag EP_CAPTURE = 5 # 8-15 = Umwandlungen (Promotion) # Struktur: 8 + Figur (Springer=0, Läufer=1, Turm=2, Dame=3) PROMO_KNIGHT = 8 PROMO_BISHOP = 9 PROMO_ROOK = 10 PROMO_QUEEN = 11 # Umwandlung mit Schlagen (optional, spart Zeit beim Checken) PROMO_N_CAPTURE = 12 PROMO_B_CAPTURE = 13 PROMO_R_CAPTURE = 14 PROMO_Q_CAPTURE = 15 # Square Constants A8, B8, C8, D8, E8, F8, G8, H8 = range(56, 64) A7, B7, C7, D7, E7, F7, G7, H7 = range(48, 56) A6, B6, C6, D6, E6, F6, G6, H6 = range(40, 48) A5, B5, C5, D5, E5, F5, G5, H5 = range(32, 40) A4, B4, C4, D4, E4, F4, G4, H4 = range(24, 32) A3, B3, C3, D3, E3, F3, G3, H3 = range(16, 24) A2, B2, C2, D2, E2, F2, G2, H2 = range(8, 16) A1, B1, C1, D1, E1, F1, G1, H1 = range(8) NOT_A = 0xfefefefefefefefe NOT_H = 0x7f7f7f7f7f7f7f7f NOT_AB = 0xfcfcfcfcfcfcfcfc NOT_GH = 0x3f3f3f3f3f3f3f3f FULL_MASK = 0xffffffffffffffff class Bitboard(): def __init__(self) -> None: # WHITE 0:King, 1:Queen, 2:Bishop, 3:Knight, 4:Rook, 5:Pawn # BLACK 6:King, 7:Queen, 8:Bishop, 9:Knight, 10:Rook, 11:Pawn self.bitboards = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] self.side_to_move = WHITE self.bitboards[W_KIN] = 1 << E1 self.bitboards[W_QUE] = 1 << D1 self.bitboards[W_BIS] = (1 << C1) | (1 << F1) self.bitboards[W_NHT] = (1 << B1) | (1 << G1) self.bitboards[W_ROO] = (1 << A1) | (1 << H1) self.bitboards[W_PAW] = 0xFF << 8 self.bitboards[B_KIN] = 1 << E8 self.bitboards[B_QUE] = 1 << D8 self.bitboards[B_BIS] = (1 << C8) | (1 << F8) self.bitboards[B_NHT] = (1 << B8) | (1 << G8) self.bitboards[B_ROO] = (1 << A8) | (1 << H8) self.bitboards[B_PAW] = 0xFF << 48 self.all_pieces = [] self.all_pieces[0] = self.bitboards[W_KIN] | self.bitboards[W_QUE] | self.bitboards[W_BIS] | self.bitboards[W_NHT] | self.bitboards[W_ROO] | self.bitboards[W_PAW] self.all_pieces[1] = self.bitboards[W_KIN] | self.bitboards[W_QUE] | self.bitboards[W_BIS] | self.bitboards[W_NHT] | self.bitboards[W_ROO] | self.bitboards[W_PAW] self.move_list = [] def get_all_moves(self): turn_offset = self.side_to_move * 6 opponent_pcs = self.all_pieces[not self.side_to_move] friendly_pcs = self.all_pieces[self.side_to_move] move_list = [] # King Moves kin_sq = self.bitboards[KIN + turn_offset].bit_length() - 1 kin_moves = KIN_ATTACKS[kin_sq] kin_moves &= ~friendly_pcs while kin_moves: flag = 0 to_sq = (kin_moves & -kin_moves).bit_length() - 1 move_list.append(to_sq | (kin_sq << 6) | flag << 12) def make_move(self, move): # Setup # Bit 0-5: Target (6 Bit, Index: 0-63) # Bit 6-11: Source (6 Bit, Index: 0-63) # Bit 12-15: Piece moved (4 Bit) 0-11: W_KIN-B_PAW # Bit 16-19: Piece Captured (4 Bit) 0-11: W_KIN-B_PAW, 15: Nothing # # Bit 20-23: Flags (4 Bit) # 0000: 0 Quiet 0100: 4 Capture 1000: 8 Promo NHT # 0001: 1 Double Pawn Push 0101: 5 En Passant 1001: 9 Promo BIS # 0010: 2 King Castle 0110: 1010: 10 Promo ROO # 0011: 3 Queen Castle 0111: 1011: 11 Promo QUE pass def encode_move(start_sq, end_sq, flag): move = 0 move |= end_sq move |= start_sq << 6 move |= flag << 12 return move # move_constants.py KIN_ATTACKS = [0] * 64 NHT_ATTACKS = [0] * 64 PAW_ATTACKS = [0] * 128 # 0-63 für Weiße Bauern, 64-127 für Schwarze Bauern RAYS_N = [0] * 64 RAYS_NE = [0] * 64 RAYS_E = [0] * 64 RAYS_SE = [0] * 64 RAYS_S = [0] * 64 RAYS_SW = [0] * 64 RAYS_W = [0] * 64 RAYS_NW = [0] * 64 def initialize(): ''' Calculate all Attack patterns and Rays ''' for sq in range(64): bit = 1 << sq # --- Pieces --- # King kin_attacks = (bit & NOT_A) << 7 | bit << 8 | (bit & NOT_H) << 9 | (bit & NOT_H) << 1 | \ (bit & NOT_H) >> 7 | bit >> 8 | (bit & NOT_A) >> 9 | (bit & NOT_A) >> 1 KIN_ATTACKS[sq] = kin_attacks & FULL_MASK # Knight nht_attacks = (bit & NOT_AB) << 6 | (bit & NOT_A) << 15 | (bit & NOT_H) << 17 | (bit & NOT_GH) << 10 | \ (bit & NOT_GH) >> 6 | (bit & NOT_H) >> 15 | (bit & NOT_A) >> 17 | (bit & NOT_AB) >> 10 NHT_ATTACKS[sq] = nht_attacks & FULL_MASK # Pawns w_attacks = (bit & NOT_A) << 7 | (bit & NOT_H) << 9 PAW_ATTACKS[sq] = w_attacks & FULL_MASK b_attacks = (bit & NOT_A) >> 9 | (bit & NOT_H) >> 7 PAW_ATTACKS[sq + 64] = b_attacks & FULL_MASK # --- Rays --- r, f = sq // 8, sq % 8 # North (r+) RAYS_N[sq] = 0 for i in range(r + 1, 8): RAYS_N[sq] |= (1 << (i * 8 + f)) # South (r-) RAYS_S[sq] = 0 for i in range(r - 1, -1, -1): RAYS_S[sq] |= (1 << (i * 8 + f)) # East (f+) RAYS_E[sq] = 0 for i in range(f + 1, 8): RAYS_E[sq] |= (1 << (r * 8 + i)) # West (f-) RAYS_W[sq] = 0 for i in range(f - 1, -1, -1): RAYS_W[sq] |= (1 << (r * 8 + i)) # North-East (r+, f+) RAYS_NE[sq] = 0 i, j = r + 1, f + 1 while i < 8 and j < 8: RAYS_NE[sq] |= (1 << (i * 8 + j)) i += 1; j += 1 # North-West (r+, f-) RAYS_NW[sq] = 0 i, j = r + 1, f - 1 while i < 8 and j >= 0: RAYS_NW[sq] |= (1 << (i * 8 + j)) i += 1; j -= 1 # South-East (r-, f+) RAYS_SE[sq] = 0 i, j = r - 1, f + 1 while i >= 0 and j < 8: RAYS_SE[sq] |= (1 << (i * 8 + j)) i -= 1; j += 1 # South-West (r-, f-) RAYS_SW[sq] = 0 i, j = r - 1, f - 1 while i >= 0 and j >= 0: RAYS_SW[sq] |= (1 << (i * 8 + j)) i -= 1; j -= 1 ''' Board Index: a b c d e f g h 8 [56] [57] [58] [59] [60] [61] [62] [63] 7 [48] [49] [50] [51] [52] [53] [54] [55] 6 [40] [41] [42] [43] [44] [45] [46] [47] 5 [32] [33] [34] [35] [36] [37] [38] [39] 4 [24] [25] [26] [27] [28] [29] [30] [31] 3 [16] [17] [18] [19] [20] [21] [22] [23] 2 [08] [09] [10] [11] [12] [13] [14] [15] 1 [00] [01] [02] [03] [03] [05] [06] [07] '''