'Check if moving at action results in a ladder escape, defined as being next
to a current player\'s group with one liberty, with no ladder captures
afterward.  Going from 1 to >= 3 liberties is counted as escape, or a
move giving two liberties without a subsequent ladder capture.
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
escape for any adjacent group, this move is a ladder escape.
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_escape(self, action, prey=None, remaining_attempts=80):

    if (not self.is_legal(action)):
        return False
    if (remaining_attempts <= 0):
        return False
    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] == 1))]
    else:
        potential_prey = [prey]
    for (prey_x, prey_y) in potential_prey:
        tmp = self.copy()
        tmp.do_move(action)
        if (tmp.liberty_counts[prey_x][prey_y] >= 3):
            return True
        if (tmp.liberty_counts[prey_x][prey_y] == 1):
            continue
        if any((tmp.is_ladder_capture(possible_capture, prey=(prey_x, prey_y), remaining_attempts=(remaining_attempts - 1)) for possible_capture in tmp.liberty_sets[prey_x][prey_y])):
            continue
        return True
    return False
