'Check if moving at action results in a ladder capture, defined as being next
to an enemy group with two liberties, and with no ladder_escape move afterward
for the other player.
If prey is None, check all adjacent groups, otherwise only the prey
group is checked.  In the (prey is None) case, if this move is a ladder
capture for any adjance group, it\'s considered a ladder capture.
Recursion depth between is_ladder_capture() and is_ladder_escape() is
controlled by the remaining_attempts argument.  If it reaches 0, the
move is assumed not to be a ladder capture.'

def is_ladder_capture(self, action, prey=None, remaining_attempts=80):

    if (not self.is_legal(action)):
        return False
    if (remaining_attempts <= 0):
        return True
    hunter_player = self.current_player
    prey_player = (- self.current_player)
    if (prey is None):
        neighbor_groups_stones = [next(iter(group)) for group in self.get_groups_around(action)]
        potential_prey = [(nx, ny) for (nx, ny) in neighbor_groups_stones if ((self.board[nx][ny] == prey_player) and (self.liberty_counts[nx][ny] == 2))]
    else:
        potential_prey = [prey]
    for (prey_x, prey_y) in potential_prey:
        tmp = self.copy()
        tmp.do_move(action)
        possible_escapes = tmp.liberty_sets[prey_x][prey_y].copy()
        for prey_stone in tmp.group_sets[prey_x][prey_y]:
            for (nx, ny) in tmp._neighbors(prey_stone):
                if ((tmp.board[nx][ny] == hunter_player) and (tmp.liberty_counts[nx][ny] == 1)):
                    possible_escapes |= tmp.liberty_sets[nx][ny]
        if (not any((tmp.is_ladder_escape((escape_x, escape_y), prey=(prey_x, prey_y), remaining_attempts=(remaining_attempts - 1)) for (escape_x, escape_y) in possible_escapes))):
            return True
    return False
