Подсчитайте количество сторон на многоугольнике
Робот подсчета сторон многоугольника решил путешествовать по миру, не сообщая об этом никому ранее, но крайне важно, чтобы процесс подсчета многоугольников не останавливался слишком долго. Итак, перед вами стоит следующая задача: учитывая черно-белое изображение многоугольника, ваша программа / функция должна возвращать количество сторон.
Программа будет передаваться на старый компьютер с перфокартами, и поскольку перфокарты очень дороги в настоящее время, лучше постарайтесь сделать свою программу максимально короткой.
Края имеют длину не менее 10 пикселей, а углы, образованные двумя примыкающими краями, составляют не менее 10 °, но не более 170 ° (или снова больше 190 °). Многоугольник полностью содержится в изображении, и многоугольник, а также это дополнение связано (там нет изолированных островов) , так что этот вход будет не действителен:
счет
Это codegolf, это означает, что выигрывает самое короткое представление в байтах, ваше представление должно найти правильное количество ребер для каждого теста. (И представление должно работать и для других случаев, оптимизация только для этих тестовых случаев не допускается.)
Если вы хотите отправить решение, которое не находит правильный номер каждый раз, вы можете отправить его тоже, но оно будет ранжироваться после всех представлений, которые работают лучше.
Пожалуйста, укажите общее количество в заголовке вашего предложения. (Общая ошибка - сумма абсолютных разностей между действительным числом сторон и каждым выходом).
Ответы:
Python 2 + PIL, без ошибок,
313307 байтПринимает имя файла изображения в командной строке и печатает результат в STDOUT.
Дает правильный результат для всех тестов, и n = 28 для круга.
объяснение
Алгоритм работает путем обхода периметра многоугольника и подсчета количества встреченных вершин (определяется как изменение направления). Мы начинаем с пикселя, самого дальнего от начала координат,
o
который гарантированно будет вершиной и, следовательно, будет смежным с ребром (то есть границей между пикселем переднего плана и фоновым пикселем). Мы отслеживаем нашу позицию,p
самую последнюю вершинуv
и самую последнюю «контрольную точку»q
, все из которых изначально равныo
. Мы также отслеживаем направление краяd
относительно текущего пикселя;d
изначально указывает на восток, что является безопасным направлением, поскольку мы знаем, что к востоку отo
иначе он не был бы самым дальним от источника. Мы движемся вдоль края в направлении, перпендикулярномd
такому, котороеd
указывает на нашу левую сторону, то есть в направлении по часовой стрелке. Всякий раз, когда мы «падаем с края», т. Е. В любой ситуации, гдеp
находится за пределами многоугольника или когда пиксель слева от нас (то есть в направленииd
) находится внутри многоугольника, мы корректируемсяp
иd
соответственно перед возобновлением.Каждый раз, когда расстояние между
p
и до последней контрольной точки,q
становится больше 5, мы пытаемся определить, прошли ли мы через вершину междуq
иp
: Мы сравниваем угол междуvq
(т. Е. Вектором отv
доq
), который является общим направлением сторона многоугольника, по которой мы шли, когда мы достигли последней контрольной точки, иqp
смещение между последней контрольной точкой и текущей позицией. Если угол больше примерно 10 °, мы заключаем, что идем по другой стороне многоугольника, увеличиваем количество вершин и устанавливаемv
текущую вершину равнойp
. На каждой контрольной точке, независимо от того, обнаружили ли мы вершину или нет, мы обновляемq
последнюю контрольную точку доp
, Мы продолжим в том же духе, пока не вернемся вo
начальную точку и не вернем количество найденных вершин (обратите внимание, что число вершин изначально равно 1, поскольку начальная точкаo
сама является вершиной.)Изображения ниже показывают обнаруженные вершины. Обратите внимание
p
, что текущая позиция в каждой контрольной точке, как и позиция новой вершины, не является оптимальной, поскольку реальная вершина, вероятно, находится где-то между последней контрольной точкойq
иp
по периметру. Как видите, все вершины, кроме первой (как правило, нижняя правая вершина), немного не совпадают. Исправление этого стоило бы больше байтов, но это, кажется, работает достаточно хорошо, как есть. При этом немного сложно не надеть только четыре контрольных примера.источник
o
, разве другой конец не будет еще дальше от источника?o
это самый дальний пиксель переднего плана от начала координат, поэтому пиксель к востоку должен быть фоновым пикселем, поэтому мы говорим, что к востоку от него есть крайo
.