def undo_update(self, board): self.undo(board) color = self.color other = next_color(color) dest = self._destination origin = self._origin piece = self.piece flags = self.flags captured = self.captured en_passant_square = dest + (N if color == BLACK else S) # castling if piece == KING: if flags & KINGSIDE: castling_origin = dest + E castling_dest = dest + W board.values[castling_dest] = 0 board.values[castling_origin] = board.piece_value( ROOK, color, castling_origin) elif flags & QUEENSIDE: castling_origin = dest + W + W castling_dest = dest + E board.values[castling_dest] = 0 board.values[castling_origin] = board.piece_value( ROOK, color, castling_origin) board.values[origin] = board.piece_value(piece, color, dest) if captured: if flags & EN_PASSANT: board.values[en_passant_square] = board.piece_value( PAWN, other, en_passant_square) else: board.values[dest] = board.piece_value(captured, other, dest) else: board.values[dest] = 0
def undo(self, board): current = self.color dest = self._destination origin = self._origin piece = self.piece flags = self.flags captured = self.captured en_passant_square = dest + (N if current == BLACK else S) board.current_color = current other = next_color(current) if current == BLACK: board.moves -= 1 board.half_moves = self.half_moves board.en_passant_square = self.previous_en_passant board.castling[WHITE] = self.white_castling board.castling[BLACK] = self.black_castling if piece == KING: board.kings[current] = origin if flags & KINGSIDE: castling_origin = dest + E castling_dest = dest + W rook_piece = board.pieces[castling_dest] board.remove(castling_dest) board.add(rook_piece, current, castling_origin) elif flags & QUEENSIDE: castling_origin = dest + W + W castling_dest = dest + E rook_piece = board.pieces[castling_dest] board.remove(castling_dest) board.add(rook_piece, current, castling_origin) board.remove(dest) board.add(piece, current, origin) if captured: if flags & EN_PASSANT: board.add(PAWN, other, en_passant_square) else: board.add(captured, other, dest) board.hash = self.previous_hash
def do(self, board): current = self.color other = next_color(current) piece = board.pieces[self._origin] color = board.colors[self._origin] other_piece = board.pieces[self._destination] origin = self._origin dest = self._destination flags = self.flags en_passant_square = dest + (N if current == BLACK else S) board.remove(origin) board.remove(dest) board.add(piece, color, dest) # En passant if flags & EN_PASSANT: board.remove(dest + (N if current == BLACK else S)) # Promotion if flags & PROMOTION: board.remove(dest) board.add(self.promotion, color, dest) if piece == KING: board.kings[current] = dest # Castling if flags & KINGSIDE: castling_origin = dest + E castling_dest = dest + W piece = board.pieces[castling_origin] board.remove(castling_origin) board.add(piece, color, castling_dest) elif flags & QUEENSIDE: castling_origin = dest + W + W castling_dest = dest + E piece = board.pieces[castling_origin] board.remove(castling_origin) board.add(piece, color, castling_dest) board.castling[current] = 0 # if move rook, disable castling: if board.castling[current] and piece == ROOK: if current == WHITE: if board.castling[WHITE] & KINGSIDE and origin == H1: board.castling[WHITE] ^= KINGSIDE elif board.castling[WHITE] & QUEENSIDE and origin == A1: board.castling[WHITE] ^= KINGSIDE if current == BLACK: if board.castling[BLACK] & KINGSIDE and origin == H7: board.castling[BLACK] ^= KINGSIDE elif board.castling[BLACK] & QUEENSIDE and origin == A7: board.castling[BLACK] ^= KINGSIDE # if capture rook, disable castling if board.castling[other] and other_piece == ROOK: if current == WHITE: if board.castling[BLACK] & KINGSIDE and dest == H1: board.castling[BLACK] ^= KINGSIDE elif board.castling[BLACK] & QUEENSIDE and dest == A1: board.castling[BLACK] ^= KINGSIDE if current == BLACK: if board.castling[WHITE] & KINGSIDE and dest == H7: board.castling[WHITE] ^= KINGSIDE elif board.castling[WHITE] & QUEENSIDE and dest == A7: board.castling[WHITE] ^= KINGSIDE board.hash ^= zobrist_castling[self.castle()] board.hash ^= zobrist_castling[board.castle()] # big pawn if board.en_passant_square != EMPTY: board.hash ^= zobrist_en_passant[board.en_passant_square] if flags & BIG_PAWN: board.en_passant_square = en_passant_square board.hash ^= zobrist_en_passant[board.en_passant_square] else: board.en_passant_square = EMPTY # Update half move counter if piece == PAWN or (flags & (CAPTURE | EN_PASSANT)): board.half_moves = 0 else: board.half_moves += 1 if current == BLACK: board.moves += 1 board.current_color = next_color(current) board.hash ^= zobrist_color
def in_check(self, color): if color == COLOR_EMPTY: color = self.current_color if self.kings[color] == EMPTY: return False return self.attacked(self.kings[color], next_color(color))
def generate_moves(self, legal, square, color): moves = [] current = color first = A8 last = H1 single = 0 if current == COLOR_EMPTY: current = self.current_color other = next_color(current) if is_square(square): first = square last = square single = 1 for i in range(first, last + 1): if is_not_square(i): i = i + 7 continue if self.colors[i] != current: continue piece = self.pieces[i] if piece == PAWN: # 1 step forward square = i + PAWN_OFFSETS[current][0] if not self.pieces[square]: moves.append(Move(self, current, i, square, NORMAL)) # 2 steps forward square = i + PAWN_OFFSETS[current][1] if (rank(i) == SECOND_RANK[current] and not self.pieces[square]): moves.append(Move(self, current, i, square, BIG_PAWN)) # Captures for j in range(2, 4): square = i + PAWN_OFFSETS[current][j] if is_not_square(square): continue if self.pieces[square] and self.colors[square] == other: moves.append(Move(self, current, i, square, CAPTURE)) elif square == self.en_passant_square: moves.append( Move(self, current, i, square, EN_PASSANT)) else: for j in range(0, PIECE_OFFSET_SIZE[piece]): offset = PIECE_OFFSET[piece][j] square = i while True: square += offset if is_not_square(square): break if not self.pieces[square]: moves.append( Move(self, current, i, square, NORMAL)) else: if self.colors[square] == current: break moves.append( Move(self, current, i, square, CAPTURE)) break # Stop after first for king and knight if (piece == KING or piece == KNIGHT): break # Castling if ((not single or last == self.kings[current]) and self.kings[current] != EMPTY): if self.castling[current] & KINGSIDE: origin = self.kings[current] dest = origin + E + E if (not self.pieces[origin + E] and not self.pieces[dest] and not self.attacked(origin, other) and not self.attacked(origin + E, other) and not self.attacked(dest, other)): moves.append(Move(self, current, origin, dest, KINGSIDE)) if self.castling[current] & QUEENSIDE: origin = self.kings[current] dest = origin + W + W if (not self.pieces[origin + W] and not self.pieces[origin + W + W] and not self.pieces[origin + W + W + W] and not self.pieces[dest] and not self.attacked(origin, other) and not self.attacked(origin + W, other) and not self.attacked(dest, other)): moves.append(Move(self, current, origin, dest, QUEENSIDE)) if not legal: return moves legal_moves = [] for move in moves: move.do(self) if not self.in_check(current): legal_moves.append(move) #else: # self.display() move.undo(self) return legal_moves