Beispiel #1
0
    def get_pseudo_legal_moves(self, gen_type=ALL):
        move_list = deque()

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

        self.get_moves_for_piece[PAWN](player_pawns, self.colour, gen_type,
                                       self.occupancy, self.player_occ,
                                       move_list)

        occ_without_pawns = self.player_occ[self.colour] & ~player_pawns

        for sq in gen_bitboard_indices(occ_without_pawns):
            piece = self.squares[sq]
            piece_type = piece & 7

            self.get_moves_for_piece[piece_type](sq, self.colour, gen_type,
                                                 self.occupancy,
                                                 self.player_occ, move_list)

        if self.ep_square:
            ep_attackers = pawn_attacks[self.colour
                                        ^ 1][self.ep_square] & player_pawns
            if ep_attackers:
                for sq in gen_bitboard_indices(ep_attackers):
                    move_list.append(EN_PASSANT + (sq << 6) + self.ep_square)

        if gen_type != CAPTURES:
            self.generate_castling(self.colour, move_list)

        return move_list
Beispiel #2
0
    def evaluate_material(self, position):
        score_mg = 0
        score_eg = 0
        
        material_table_index = position.material_key & 0xFFFF
        material_entry = self.material_table[material_table_index]
        if material_entry and material_entry.key == position.material_key:
            score_mg += material_entry.imbalance
            score_eg += material_entry.imbalance

            score_mg += material_entry.material_score[MIDGAME]
            score_eg += material_entry.material_score[ENDGAME]
        else:           
            imbalance_score = (self.imbalance(position, WHITE) - self.imbalance(position, BLACK)) // 16
            score_mg += imbalance_score
            score_eg += imbalance_score

            material_score = [0, 0]
            for sq in gen_bitboard_indices(position.occupancy):
                piece = position.squares[sq]
                if piece >> 3 == WHITE:
                    material_score[MIDGAME] += MATERIAL[piece & 7][MIDGAME]
                    material_score[ENDGAME] += MATERIAL[piece & 7][ENDGAME]
                else:
                    material_score[MIDGAME] -= MATERIAL[piece & 7][MIDGAME]
                    material_score[ENDGAME] -= MATERIAL[piece & 7][ENDGAME]
            score_mg += material_score[MIDGAME]
            score_eg += material_score[ENDGAME]
            
            self.material_table[material_table_index] = MaterialEntry(position.material_key, material_score, imbalance_score)

        return score_mg, score_eg
Beispiel #3
0
    def evaluate_mobility(self, position, mobility_bb):
        mobility_area = [0, 0]
        mobility_score_mg = [0, 0]
        mobility_score_eg = [0, 0]
        
        mobility_area[WHITE] = self.get_mobility_area(position, WHITE)
        mobility_area[BLACK] = self.get_mobility_area(position, BLACK)

        for sq in gen_bitboard_indices(mobility_bb):
            piece = position.squares[sq]
            piece_type = piece & 7
            piece_colour = piece >> 3
            
            if piece_type == KNIGHT:
                moves = pseudo_attacks[KNIGHT][sq]
            elif piece_type == BISHOP:
                moves = batk_table[sq][(position.occupancy ^ position.piece_bb[(piece_colour << 3) | QUEEN]) & bishop_masks[sq]]
            elif piece_type == ROOK:
                moves = ratk_table[sq][(position.occupancy ^ position.piece_bb[(piece_colour << 3) | ROOK]
                                        ^ position.piece_bb[(piece_colour << 3) | QUEEN]) & rook_masks[sq]]
            elif piece_type == QUEEN:
                moves = ratk_table[sq][position.occupancy & rook_masks[sq]] | batk_table[sq][position.occupancy & bishop_masks[sq]]

            moves &= mobility_area[piece_colour]
            
            move_count = popcount(moves)
            mobility_score_mg[piece_colour] += mobility[piece_type][move_count][MIDGAME]
            mobility_score_eg[piece_colour] += mobility[piece_type][move_count][ENDGAME]

        score_mg = mobility_score_mg[WHITE] - mobility_score_mg[BLACK]
        score_eg = mobility_score_eg[WHITE] - mobility_score_eg[BLACK]

        return score_mg, score_eg
Beispiel #4
0
    def attacks_by(self, piece_type, colour):
        if piece_type == ALL_PIECES:
            piece_bb = self.player_occ[colour]
        else:
            piece_bb = self.piece_bb[(colour << 3) | piece_type]

        attacked = 0
        for sq in gen_bitboard_indices(piece_bb):
            attacked |= self.attacks_from(sq, piece_type, colour,
                                          self.occupancy)

        return attacked
Beispiel #5
0
    def evaluate_pawns(self, position):
        pawn_table_index = position.pawn_key & 0xFFFF
        pawn_entry = self.pawn_table[pawn_table_index]
        if pawn_entry and pawn_entry.key == position.pawn_key:
            return pawn_entry.score_mg, pawn_entry.score_eg

        king_sqr = None
        
        score_mg = [0, 0]
        score_eg = [0, 0]

        for colour in COLOURS:
            player_pawns = position.piece_bb[(colour << 3) | PAWN]
            enemy_pawns = position.piece_bb[((colour ^ 1) << 3) | PAWN]
            enemy_pawn_attacks = (pawn_shift[colour ^ 1](enemy_pawns, NORTHEAST)
                                  | pawn_shift[colour ^ 1](enemy_pawns, NORTHWEST))

            for sq in gen_bitboard_indices(player_pawns):
                pawn_bb = 1 << sq
                adjacent_squares = adjacent_files[sq] & rank_of[sq] 
                adjacent_pawns = adjacent_files[sq] & player_pawns
                aligned = True if adjacent_squares & player_pawns else False
                defenders = adjacent_pawns & pawn_shift[colour ^ 1](rank_of[sq], NORTH)
                opposed = True if forward_fill[colour](pawn_bb) & enemy_pawns else False

                # Doubled pawn
                if (player_pawns & pawn_shift[colour ^ 1](pawn_bb, NORTH)) and not defenders:
                    score_mg[colour] -= DOUBLED[MIDGAME]
                    score_eg[colour] -= DOUBLED[ENDGAME]

                # Connected pawn
                if aligned or defenders:
                    score_mg[colour] += connected_bonus[opposed][aligned][popcount(defenders)][(sq >> 3) ^ (colour * 7)][MIDGAME]
                    score_eg[colour] += connected_bonus[opposed][aligned][popcount(defenders)][(sq >> 3) ^ (colour * 7)][ENDGAME]
                
                # Isolated pawn
                elif not adjacent_pawns:
                    score_mg[colour] -= ISOLATED[MIDGAME]
                    score_eg[colour] -= ISOLATED[ENDGAME]
                    
                # Backward pawn
                elif (pawn_shift[colour](pawn_bb, NORTH) & (enemy_pawns | enemy_pawn_attacks)
                      and not forward_fill[colour ^ 1](adjacent_squares) & player_pawns):
                    score_mg[colour] -= BACKWARD[MIDGAME]
                    score_eg[colour] -= BACKWARD[ENDGAME]

        score_mg = score_mg[WHITE] - score_mg[BLACK]
        score_eg = score_eg[WHITE] - score_eg[BLACK]

        self.pawn_table[pawn_table_index] = PawnEntry(position.pawn_key, score_mg, score_eg)

        return score_mg, score_eg
Beispiel #6
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