Алгоритм прост: используется массив для сохранения "состояний" границ клеток доски. Значение "состояния" границы зависит от количества примыкающих к ней невырезанных клеток (НК):

- НК с обеих сторон (начальное состояние);

- НК с одной стороны (плюс к периметру);

- вырезанные клетки с обеих сторон, (внутри фигуры, минус из периметра).
Идея понятна и даже симпатична, но реализована неполноценно и потому работать не будет. Если говорить о границе не оставшейся фигуры, а вырезанной части доски, то она состоит из отрезков, находящихся или внутри доски, или по её краям. Так вот, Вы по ходу второго цикла прибавляете и те, и другие. Между тем как на самом деле внешние отрезки надо, наоборот,
вычитать. Для этого достаточно немножко дополнить первый двойной (инициализирующий) цикл.
Кроме того, я не вполне уверен, что там всё в порядке с границами. Во всяком случае, в строчке
int vert[9][8], hor[9][8];одну из пар 9 и 8 надо явно переставить. Хотя я в детали не вникал.
Да, кстати, насчёт оптимизации. Основное время у Вас занимает (если клеток вырезано немного) инициализация. Не знаю, как в Сях, но в Паскале есть процедура
FillChar, позволяющая этот процесс существенно ускорить. Типа
FillChar(vert, SizeOf(vert), #3).