コード例 #1
0
ファイル: evaluate.py プロジェクト: smk762/PyQtChess
    def evaluate_king_shelter(self, position, colour, king_sqr):
        # Gets the bitboard of the back two ranks for the given colour
        shelter_ranks = RANK_1_BB | RANK_2_BB if colour == WHITE else RANK_7_BB | RANK_8_BB
        
        # Gets the bitboard for the rank of the king and the ranks in front of the king
        ranks_in_front = ~forward_ranks[colour ^ 1][king_sqr]

        # Gets the pawns on the rank of the king and the ranks in front of the king
        player_pawns = position.piece_bb[(colour << 3) | PAWN] & ranks_in_front
        enemy_pawns = position.piece_bb[((colour ^ 1) << 3) | PAWN] & ranks_in_front

        # Give a bonus for enemy edge pawns in front of our king
        if pawn_shift[colour ^ 1](enemy_pawns, NORTH) & (A_FILE_BB | H_FILE_BB) & shelter_ranks & (1 << king_sqr):
            safety_score = 374
        else:
            safety_score = 5

        # Get the centre file of the king shelter
        king_file = king_sqr & 7
        if king_file == A_FILE:
            centre = B_FILE
        elif king_file == H_FILE:
            centre = G_FILE
        else:
            centre = king_file

        # Iterate through the centre file and the two adjacent files
        for file_num in range(centre - 1, centre + 2):
            file_bb = A_FILE_BB << file_num

            pawns_on_file = player_pawns & file_bb
            if pawns_on_file:
                if colour == WHITE:
                    backmost_sq = bit_scan1(pawns_on_file)  # Least significant bit
                else:
                    backmost_sq = pawns_on_file.bit_length() - 1  # Most significant bit
                player_rank = (backmost_sq >> 3) ^ (colour * 7)
            else:
                player_rank = RANK_1

            pawns_on_file = enemy_pawns & file_bb
            if pawns_on_file:
                if colour == WHITE:
                    frontmost_sq = pawns_on_file.bit_length() - 1  # Most significant bit
                else:
                    frontmost_sq = bit_scan1(pawns_on_file)  # Least significant bit
                enemy_rank = (frontmost_sq >> 3) ^ (colour * 7)
            else:
                enemy_rank = RANK_1

            opposite_file = file_num ^ H_FILE
            min_file = opposite_file if opposite_file < file_num else file_num
            safety_score += shelter_strength[min_file][player_rank]
            if player_rank and player_rank == enemy_rank - 1:
                if enemy_rank == RANK_3:
                    safety_score -= 66
            else:
                safety_score -= unblocked_storm[min_file][enemy_rank]
        
        return safety_score
コード例 #2
0
    def checkGroup(self, state=None, player=None):
        if state is None:
            st = self.state
        else:
            st = state

        if player is None:
            p = self.currentPlayer
        else:
            p = player

        areGrouped = True

        if gmpy2.popcount(st[p]) == 1:
            areGrouped = True
        else:
            unvisited = st[p]
            checklist = 2**gmpy2.bit_scan1(unvisited)
            unvisited ^= checklist

            while gmpy2.popcount(checklist) > 0:
                current = gmpy2.bit_scan1(checklist)
                checklist ^= 2**current

                currentNeighbours = self.neighbourhood[current] & unvisited
                if currentNeighbours:
                    unvisited ^= currentNeighbours
                    checklist |= currentNeighbours

            if gmpy2.popcount(unvisited) > 0:
                areGrouped = False

        return areGrouped
コード例 #3
0
ファイル: node_advance.py プロジェクト: PhyTeam/ReversiGame
    def get_all_valid_moves(self, player):
        all_candidate_moves = {}
        result = self.getMoves(self.bitboard[player], self.bitboard[-player])
        for m, flipped_square in result:
            x = gmpy2.bit_scan1(m) / 8
            y = gmpy2.bit_scan1(m) % 8
            bstr = self.__gererate_new_board(flipped_square, player)
            new_board = BitBoard(None)
            new_board.bitboard = bstr
            new_board.bitboard[player] |= m
            all_candidate_moves[(x, y)] = new_board
        return all_candidate_moves


        avalible_move = 0
        moves = self.__valid_moves(player)

        for m in moves.values():
            avalible_move |= m

        all_candidate_moves = {}
        idx = gmpy2.bit_scan1(avalible_move, 0)
        while idx is not None:
            mask = 1 << idx
            flipped_square = 0
            for dir in direction.keys():
                if mask & moves[dir] != 0:
                    flipped_square |= self.__generate_flipped_squares(mask, dir, player)
            bstr = self.__gererate_new_board(flipped_square, player)
            new_board = BitBoard(None)
            new_board.bitboard = bstr
            all_candidate_moves[(idx / 8, idx % 8)] = new_board
            idx = gmpy2.bit_scan1(avalible_move, idx + 1)

        return all_candidate_moves
コード例 #4
0
def paintBoard(moving=None):
    screen.fill(BGCOLOUR)

    pygame.draw.rect(screen, BOARDCOLOUR,
                     (XMARGIN, YMARGIN, BOARDWIDTH + BOARDMARGIN * 2,
                      BOARDHEIGHT + BOARDMARGIN * 2))

    # squares
    for i in range(9):
        pygame.draw.line(
            screen, BLACK,
            (XMARGIN + BOARDMARGIN + i * BOXSIZE, YMARGIN + BOARDMARGIN),
            (XMARGIN + BOARDMARGIN + i * BOXSIZE,
             WINDOWHEIGHT - YMARGIN - BOARDMARGIN), 1)
        pygame.draw.line(
            screen, BLACK,
            (XMARGIN + BOARDMARGIN, YMARGIN + BOARDMARGIN + i * BOXSIZE),
            (WINDOWWIDTH - XMARGIN - BOARDMARGIN,
             YMARGIN + BOARDMARGIN + i * BOXSIZE), 1)

    # stones
    pos = gmpy2.bit_scan1(board.state[BLACKVAL])
    while pos is not None:
        x, y = getCoordFromPos(pos)
        pygame.gfxdraw.filled_circle(screen, x, y, STONESIZE, BLACK)
        pygame.gfxdraw.aacircle(screen, x, y, STONESIZE, BLACK)
        pos = gmpy2.bit_scan1(board.state[BLACKVAL], pos + 1)

    pos = gmpy2.bit_scan1(board.state[WHITEVAL])
    while pos is not None:
        x, y = getCoordFromPos(pos)
        pygame.gfxdraw.filled_circle(screen, x, y, STONESIZE, WHITE)
        pygame.gfxdraw.aacircle(screen, x, y, STONESIZE, BLACK)
        pos = gmpy2.bit_scan1(board.state[WHITEVAL], pos + 1)

    if moving:
        pygame.gfxdraw.filled_circle(screen, moving[0], moving[1], STONESIZE,
                                     PCOLOUR[board.currentPlayer])
        pygame.gfxdraw.aacircle(screen, moving[0], moving[1], STONESIZE, BLACK)

    else:
        # fromPos
        if fromPos is not None:
            x, y = getCoordFromPos(fromPos)
            pygame.gfxdraw.filled_circle(screen, x, y, 3, RED)
            pygame.gfxdraw.aacircle(screen, x, y, 3, RED)

            if len(availableMoves) > 0:
                for move in availableMoves:
                    if fromPos == move[0]:
                        x2, y2 = getCoordFromPos(move[1])
                        pygame.gfxdraw.aacircle(screen, x2, y2, 3, RED)

            if toPos is not None and fromPos != toPos:
                x2, y2 = getCoordFromPos(toPos)
                pygame.gfxdraw.line(screen, x, y, x2, y2, RED)
                pygame.gfxdraw.filled_circle(screen, x2, y2, 3, RED)
                pygame.gfxdraw.aacircle(screen, x2, y2, 3, RED)
コード例 #5
0
    def is_legal(self, move):
        colour = self.colour
        enemy_colour = colour ^ 1
        src_index = (move >> 6) & 0x3F
        dst_index = move & 0x3F
        src_bb = 1 << src_index
        dst_bb = 1 << dst_index
        move_type = move & (0x3 << 14)
        king_sqr = bit_scan1(self.piece_bb[((colour << 3) | KING)])
        occ = self.occupancy
        enemy_rooks = self.piece_bb[((enemy_colour << 3) | ROOK)]
        enemy_bishops = self.piece_bb[((enemy_colour << 3) | BISHOP)]
        enemy_queens = self.piece_bb[((enemy_colour << 3) | QUEEN)]

        if self.is_square_attacked(king_sqr):
            return True if move in self.get_check_evasions(colour) else False

        if move_type == EN_PASSANT:
            self.make_move(move)
            in_check = self.is_in_check(colour)
            self.undo_move()
            return False if in_check else True

        if src_index == king_sqr:
            # Castling legality is checked during move generation
            if move_type == CASTLING:
                return True
            if self.is_square_attacked(dst_index, occ ^ (1 << king_sqr)):
                return False
            else:
                return True

        sliders = ((pseudo_attacks[ROOK][king_sqr] &
                    (enemy_rooks | enemy_queens))
                   | (pseudo_attacks[BISHOP][king_sqr] &
                      (enemy_bishops | enemy_queens)))

        while sliders:
            slider_sqr = bit_scan1(sliders)
            sqrs_between = bb_between[king_sqr][slider_sqr]
            blockers = sqrs_between & occ
            if src_bb & sqrs_between:  # If moving blocker piece
                if not blockers ^ src_bb:  # If no other blockers
                    if not dst_bb & (
                            sqrs_between |
                        (1 << slider_sqr)):  # If not staying on the diagonal
                        return False
            sliders &= sliders - 1

        return True
コード例 #6
0
ファイル: 351.py プロジェクト: jkschin/project_euler
	def next(self):
		shift = gmpy2.bit_scan1(self.n)
		if shift==None:
			return -1
		self.global_shift += shift
		self.n = self.n >> shift
		self.n = self.n.bit_flip(0)
		return self.global_shift
コード例 #7
0
    def is_in_check(self, colour=None):
        if colour is None:
            colour = self.colour
        king_index = bit_scan1(self.piece_bb[((colour << 3) | KING)])

        if self.is_square_attacked(king_index, colour=colour ^ 1):
            return True

        return False
コード例 #8
0
    def allAvailableMoves(self, state=None, player=None):
        if state is None:
            st = self.state
        else:
            st = state

        if player is None:
            p = self.currentPlayer
        else:
            p = player

        aav = []

        n = gmpy2.bit_scan1(st[p])
        while n:
            aav += self.availableMoves(n, st, p)
            n = gmpy2.bit_scan1(st[p], n + 1)

        return aav
コード例 #9
0
ファイル: sudokugen.py プロジェクト: Mrpatekful/cydoku
    def decode(grid: numpy.ndarray, n: int) -> numpy.ndarray:
        """Decodes the given 1D binary grid to a regular
        2D numpy array with human readable numbers.

        Args:
            :param grid: Grid to be decoded.
            :param n: Size of the subgrid of the provided grid.

        Returns:
            :return: Converted grid.
        """
        converter = numpy.vectorize(lambda x: bit_scan1(int(x)) + 1
                                    if x != 0 else 0,
                                    otypes=[numpy.ulonglong])

        return converter(grid).reshape(n**2, n**2)
コード例 #10
0
ファイル: e_big.py プロジェクト: ylucki/Secure-Communications
def factor(n, e, d):
    f = e * d - 1
    lsb = gmpy2.bit_scan1(f)
    t = f >> lsb
    a = 2
    while True:
        ap = pow(a, t, n)
        for i in range(1, lsb + 1):
            if ap == 1:
                break
            if ap == n - 1:
                break
            ap2 = pow(ap, 2, n)
            if ap2 == 1:
                p = gmpy2.gcd(ap - 1, n)
                return p, n // p
            ap = ap2
コード例 #11
0
    def see(self, from_sq, target_sq):
        gain = [None] * 32
        depth = 0
        gain[depth] = MATERIAL[self.squares[target_sq] & 7][MIDGAME]
        occ = self.occupancy
        colour = self.colour
        attackers = self.attacks_to(target_sq, colour ^ 1, occ)
        attackers |= self.attacks_to(target_sq, colour, occ)
        from_bb = 1 << from_sq
        slider_blockers = occ ^ (
            self.piece_bb[W_KNIGHT] | self.piece_bb[B_KNIGHT]
            | self.piece_bb[W_KING] | self.piece_bb[B_KING])

        piece = self.squares[from_sq]

        while from_bb:
            depth += 1
            colour ^= 1
            gain[depth] = MATERIAL[piece & 7][MIDGAME] - gain[depth - 1]
            if max(-gain[depth - 1], gain[depth]) < 0:
                break
            attackers ^= from_bb
            occ ^= from_bb
            if from_bb & slider_blockers:
                attackers |= ratk_table[target_sq][
                    occ
                    & rook_masks[target_sq]] & (self.piece_bb[W_ROOK]
                                                | self.piece_bb[B_ROOK]
                                                | self.piece_bb[W_QUEEN]
                                                | self.piece_bb[B_QUEEN]) & occ
                attackers |= batk_table[target_sq][
                    occ & bishop_masks[target_sq]] & (
                        self.piece_bb[W_BISHOP]
                        | self.piece_bb[B_BISHOP]
                        | self.piece_bb[W_QUEEN]
                        | self.piece_bb[B_QUEEN]) & occ
            from_bb = self.get_least_valuable_piece(attackers, colour)
            if from_bb:
                piece = self.squares[bit_scan1(from_bb)]

        depth -= 1
        while depth:
            gain[depth - 1] = -max(-gain[depth - 1], gain[depth])
            depth -= 1

        return gain[0]
コード例 #12
0
ファイル: evaluate.py プロジェクト: smk762/PyQtChess
    def get_king_safety(self, position, colour):
        king_sqr = bit_scan1(position.piece_bb[(colour << 3) | KING])

        # If king square and castling rights have not changed, use the previously saved score
        if self.prev_king_square[colour] == king_sqr:
            if self.prev_castling_rights[colour] == position.castling_rights & (0x3 << (colour * 2)):
                return self.king_safety[colour]

        player_pawns = position.piece_bb[(colour << 3) | PAWN]

        # Calculate the distance between the king and the closest pawn of its colour
        king_pawn_distance = 0
        if player_pawns:
            king_pawn_distance += 1
            while not distance_ring[king_sqr][king_pawn_distance] & player_pawns:
                king_pawn_distance += 1

        # Evaluate the shelter for the king square
        score = self.evaluate_king_shelter(position, colour, king_sqr)

        # If castling kingside is possible, evaluate the shelter for the kingside castled square
        # Use the castled score if greater than the original score
        if position.castling_rights & (KINGSIDE << colour):
            castled_score = self.evaluate_king_shelter(position, colour, 6 ^ (colour * 56))
            if castled_score > score:
                score = castled_score
                
        # If castling queenside is possible, evaluate the shelter for the queenside castled square
        # Use the castled score if greater than the original score
        if position.castling_rights & (QUEENSIDE << colour):
            castled_score = self.evaluate_king_shelter(position, colour, 2 ^ (colour * 56))
            if castled_score > score:
                score = castled_score
                
        # Save the king safety information for the current position
        self.prev_king_square[colour] = king_sqr
        self.prev_castling_rights[colour] = position.castling_rights & (0x3 << (colour * 2))
        self.king_safety[colour] = (score, -16 * king_pawn_distance)

        return score, -16 * king_pawn_distance
コード例 #13
0
def gen_bitboard_indices(bb):
    while bb:
        yield bit_scan1(bb)
        bb &= bb - 1
コード例 #14
0
ファイル: 351.py プロジェクト: jkschin/project_euler
	def updateUnseen(self):
		shift = gmpy2.bit_scan1(self.unseen)
		self.unseen = self.unseen>>shift
		self.prime = self.prime + shift
		self.global_shift+=shift
コード例 #15
0
    def evaluate(self, state=None, player=None, move=None):
        if state is None:
            st = self.state
        else:
            st = state

        if player is None:
            p = self.currentPlayer
        else:
            p = player

        # the player
        n = gmpy2.popcount(st[p])
        if n == 1:
            return 50

        nn = gmpy2.popcount(st[-p])
        if nn == 1:
            return -50

        x = gmpy2.bit_scan1(st[p])

        # centre of mass
        rr, cc = 0, 0
        pieces = []

        f2p = 0
        f7p = 0

        left = right = 7 - x % 8
        top = bottom = 7 - x // 8
        while x is not None:
            r, c = 7 - x // 8, 7 - x % 8
            if r < top:
                top = r
            elif r > bottom:
                bottom = r
            if c < left:
                left = c
            elif c > right:
                right = c

            pieces.append((r, c))
            rr += r
            cc += c

            for i in range(5):
                if 2**x & self.board_cat[i]:
                    f2p += i - 2
                    break

            f7p += gmpy2.popcount(self.neighbourhood[x] & st[p])

            x = gmpy2.bit_scan1(st[p], x + 1)
        rr /= n
        rr = round(rr)
        cc /= n
        cc = round(cc)
        comp = (rr, cc)

        # sum of distances
        dist = 0
        for r, c in pieces:
            dist += max(abs(r - rr), abs(c - cc))

        # surplus of distances
        surplus = dist - self.min_sum_dist[n]

        f1p = 1 / (surplus + 1)

        f2p /= n * 2

        pos = (7 - rr) * 8 + 7 - cc
        for i in range(4, -1, -1):
            if 2**pos & self.board_cat[i]:
                f3p = 1 / (1 + i)
                break

        f4p = 0
        for q in self.quads[comp]:
            if gmpy2.popcount(q & st[p]) == 3:
                f4p += 1
            elif gmpy2.popcount(q & st[p]) == 4:
                f4p += 2
        f4p /= len(self.quads[comp])

        f5p = 0
        if move:
            f5p = .5
            if self.stoneTaken:
                f5p *= 2
            if 2**move[1] & (self.board_cat[0] | self.board_cat[1]):
                f5p /= 2
                if 2**move[0] & (self.board_cat[0] | self.board_cat[1]):
                    f5p /= 2

        f7p /= n

        f8p = 1 / ((right - left + 1) * (bottom - top + 1))

        # the other

        x = gmpy2.bit_scan1(st[-p])

        # centre of mass
        rr, cc = 0, 0
        pieces = []

        f2o = 0
        f7o = 0

        left = right = 7 - x % 8
        top = bottom = 7 - x // 8
        while x is not None:
            r, c = 7 - x // 8, 7 - x % 8
            if r < top:
                top = r
            elif r > bottom:
                bottom = r
            if c < left:
                left = c
            elif c > right:
                right = c

            pieces.append((r, c))
            rr += r
            cc += c

            for i in range(5):
                if 2**x & self.board_cat[i]:
                    f2o += i - 2
                    break

            f7o += gmpy2.popcount(self.neighbourhood[x] & st[-p])

            x = gmpy2.bit_scan1(st[-p], x + 1)
        rr /= nn
        rr = round(rr)
        cc /= nn
        cc = round(cc)
        como = (rr, cc)

        # sum of distances
        dist = 0
        for r, c in pieces:
            dist += max(abs(r - rr), abs(c - cc))

        # surplus of distances
        surplus = dist - self.min_sum_dist[nn]

        f1o = 1 / (surplus + 1)

        f2o /= nn * 2

        pos = (7 - rr) * 8 + 7 - cc
        for i in range(4, -1, -1):
            if 2**pos & self.board_cat[i]:
                f3o = 1 / (1 + i)
                break

        f4o = 0
        for q in self.quads[como]:
            if gmpy2.popcount(q & st[-p]) == 3:
                f4o += 1
            elif gmpy2.popcount(q & st[-p]) == 4:
                f4o += 2
        f4o /= len(self.quads[como])

        f7o /= nn
        f8o = 1 / ((right - left + 1) * (bottom - top + 1))

        val = f1p - f1o + f2p - f2o + f3p - f3o + f4p - f4o + f5p + f7p - f7o + f8p - f8o

        # f9. player to move bonus
        if p == self.currentPlayer:
            val += .2

        return val
コード例 #16
0
    def update(self, grid, candidate_values, candidate_nums, value, state,
               filled, found):
        def bits(x, f, u):
            return ''.join([f if int(x) & 1 << n else u for n in range(9)])

        def nums(x):
            return ''.join(
                [str(n + 1) if int(x) & 1 << n else '-' for n in range(9)])

        if self.counter > Printer.max_state:
            return

        self.file.write(''.join(['#'] * 97))
        self.file.write('\n#{} STEP {} {}#\n'.format(
            ''.join(['='] * ((88 - len(str(self.counter))) // 2)),
            self.counter,
            ''.join(['='] * int(math.ceil(
                (88 - len(str(self.counter))) / 2)))))
        self.file.write(
            '\nFILLED:\t\t{}\nSTATE:\t\t{}\nFOUND:\t\t{} / {}\n\n'.format(
                filled, state, found, self.max))

        sep = ''.join(['-'] * 31)
        self.file.write('GRID:\n')
        for i in range(self.n**2):
            if i % self.n == 0:
                self.file.write('+{}+{}+{}+\n'.format(sep, sep, sep))

            self.file.write('| {} {} {} | {} {} {} | {} {} {} |\n'.format(*[
                '   ({})   '.format(
                    int(gmpy2.bit_scan1(grid[i * self.n**2 + j])) +
                    1 if int(grid[i * self.n**2 + j]) != 0 else '?')
                for j in range(self.n**2)
            ]))

            self.file.write('| {} {} {} | {} {} {} | {} {} {} |\n'.format(*[
                bits(grid[i * self.n**2 +
                          j], '#', '.') if grid[i * self.n**2 +
                                                j] != 0 else ''.join([' '] * 9)
                for j in range(self.n**2)
            ]))

        self.file.write('+{}+{}+{}+\n'.format(sep, sep, sep))
        self.file.write('\nCANDIDATES:\n')
        for i in range(self.n**2):
            if i % self.n == 0:
                self.file.write('+{}+{}+{}+\n'.format(sep, sep, sep))

            self.file.write('| {} {} {} | {} {} {} | {} {} {} |\n'.format(*[
                '   ({})   '.format(candidate_nums[i * self.n**2 + j])
                for j in range(self.n**2)
            ]))

            self.file.write('| {} {} {} | {} {} {} | {} {} {} |\n'.format(*[
                nums(candidate_values[i * self.n**2 +
                                      j]) if grid[i * self.n**2 +
                                                  j] == 0 else ''.join([' '] *
                                                                       9)
                for j in range(self.n**2)
            ]))

        self.file.write('+{}+{}+{}+\n\n'.format(sep, sep, sep))

        self.counter += 1
コード例 #17
0
def rho(j):
    assert j != 0, "rho is inf"
    return gmpy2.bit_scan1(j)
コード例 #18
0
    def get_check_evasions(self, colour):
        move_list = deque()

        occ = self.occupancy
        king_sqr = bit_scan1(self.piece_bb[((colour << 3) | KING)])

        # Try moving king
        moves = pseudo_attacks[KING][king_sqr] & ~self.player_occ[colour]
        for sq in gen_bitboard_indices(moves):
            if not self.is_square_attacked(sq, occ ^ (1 << king_sqr)):
                move_list.append((king_sqr << 6) + sq)

        attackers = self.attacks_to(king_sqr, colour ^ 1, occ)

        # If in double check, only evasions are through king moves
        if attackers & (attackers - 1):
            return move_list

        enemy_colour = colour ^ 1
        enemy_rooks = self.piece_bb[((enemy_colour << 3) | ROOK)]
        enemy_bishops = self.piece_bb[((enemy_colour << 3) | BISHOP)]
        enemy_queens = self.piece_bb[((enemy_colour << 3) | QUEEN)]

        sliders = ((pseudo_attacks[ROOK][king_sqr] &
                    (enemy_rooks | enemy_queens))
                   | (pseudo_attacks[BISHOP][king_sqr] &
                      (enemy_bishops | enemy_queens)))

        pinned = 0
        while sliders:
            slider_sqr = bit_scan1(sliders)
            sqrs_between = bb_between[king_sqr][slider_sqr]
            blockers = sqrs_between & occ
            if not blockers & (blockers - 1):
                pinned |= blockers
            sliders &= sliders - 1

        attacker_sqr = bit_scan1(attackers)
        attacker_piece = self.squares[attacker_sqr] & 7
        colour_mask = colour << 3

        pawns = self.piece_bb[colour_mask | PAWN]
        knights = self.piece_bb[colour_mask | KNIGHT]
        bishops = self.piece_bb[colour_mask | BISHOP]
        rooks = self.piece_bb[colour_mask | ROOK]
        queens = self.piece_bb[colour_mask | QUEEN]

        # Try capturing attacker piece
        defenders = pawn_attacks[colour ^ 1][attacker_sqr] & pawns
        defenders |= pseudo_attacks[KNIGHT][attacker_sqr] & knights
        defenders |= ratk_table[attacker_sqr][
            occ & rook_masks[attacker_sqr]] & (rooks | queens)
        defenders |= batk_table[attacker_sqr][
            occ & bishop_masks[attacker_sqr]] & (bishops | queens)
        defenders &= ~pinned

        for defender_sq in gen_bitboard_indices(defenders):
            if self.squares[defender_sq] & 7 == PAWN and attacker_sqr >> 3 == (
                    RANK_8 if colour == WHITE else RANK_1):
                generate_promotions(defender_sq, attacker_sqr, move_list)
            else:
                move_list.append((defender_sq << 6) + attacker_sqr)

        # Try blocking attack by slider piece
        if attacker_piece == BISHOP or attacker_piece == ROOK or attacker_piece == QUEEN:
            sqrs_between = bb_between[king_sqr][attacker_sqr]

            for sq in gen_bitboard_indices(sqrs_between):
                one_step = pawn_shift[colour ^ 1](1 << sq, NORTH)
                blockers = one_step & pawns
                blockers |= ((RANK_2_BB if colour == WHITE else RANK_7_BB)
                             & pawn_shift[colour ^ 1](one_step & ~occ, NORTH)
                             & pawns)
                blockers |= pseudo_attacks[KNIGHT][sq] & knights
                blockers |= ratk_table[sq][occ & rook_masks[sq]] & (rooks
                                                                    | queens)
                blockers |= batk_table[sq][occ & bishop_masks[sq]] & (bishops
                                                                      | queens)
                blockers &= ~pinned

                for blocker_sq in gen_bitboard_indices(blockers):
                    if self.squares[
                            blocker_sq] & 7 == PAWN and attacker_sqr >> 3 == (
                                RANK_8 if colour == WHITE else RANK_1):
                        generate_promotions(blocker_sq, sq, move_list)
                    else:
                        move_list.append((blocker_sq << 6) + sq)

        if self.ep_square:
            ep_attackers = pawn_attacks[colour ^ 1][self.ep_square] & pawns
            if ep_attackers:
                for sq in gen_bitboard_indices(ep_attackers):
                    ep_move = EN_PASSANT + (sq << 6) + self.ep_square
                    self.make_move(ep_move)
                    in_check = self.is_in_check(colour)
                    self.undo_move()
                    if not in_check:
                        move_list.append(ep_move)

        return move_list