Эта задача основана на фактическом обнаружении столкновений, которое мне недавно пришлось написать для простой игры.
Напишите программу или функцию, которая, учитывая два объекта, возвращает истинное или ложное значение в зависимости от того, находятся ли два объекта в столкновении (то есть пересекаются) или нет.
Вам необходимо поддерживать три типа объектов:
- Сегменты линии : представлены 4 числами с плавающей запятой, указывающими две конечные точки, т.е. (x 1 , y 1 ) и (x 2 , y 2 ) . Вы можете предположить, что конечные точки не идентичны (поэтому отрезок не является вырожденным).
- Диски : т.е. заполненные круги, представленные 3-мя поплавками, два для центра (x, y) и один (положительный) для радиуса r .
- Полости : это дополнение диска. Таким образом, полость заполняет все пространство 2D, кроме круглой области, определенной центром и радиусом.
Ваша программа или функция получит два таких объекта в виде идентифицирующего целого числа (по вашему выбору) и их 3 или 4 числа с плавающей точкой. Вы можете получить ввод через STDIN, ARGV или аргумент функции. Вы можете представить ввод в любой удобной форме, которая не была предварительно обработана, например, от 8 до 10 отдельных чисел, два списка значений через запятую или два списка. Результат может быть возвращен или записан в STDOUT.
Вы можете предположить, что объекты находятся на расстоянии не менее 10 -10 единиц или слишком сильно пересекаются, поэтому вам не нужно беспокоиться об ограничениях типов с плавающей запятой.
Это код гольф, поэтому самый короткий ответ (в байтах) выигрывает.
Тестовые случаи
Представляя линейные сегменты с 0
дисками и с 1
полостями 2
, используя формат ввода на основе списка, все следующее должно давать достоверный вывод:
[0,[0,0],[2,2]], [0,[1,0],[2,4]] # Crossing line segments
[0,[0.5,0],[-0.5,0]], [1,[0,0],1] # Line contained in a disc
[0,[0.5,0],[1.5,0]], [1,[0,0],1] # Line partially within disc
[0,[-1.5,0.5],[1.5,0.5]], [1,[0,0],1] # Line cutting through disc
[0,[0.5,2],[-0.5,2]], [2,[0,0],1] # Line outside cavity
[0,[0.5,0],[1.5,0]], [2,[0,0],1] # Line partially outside cavity
[0,[-1.5,0.5],[1.5,0.5]], [2,[0,0],1] # Line cutting through cavity
[1,[0,0],1], [1,[0,0],2] # Disc contained within another
[1,[0,0],1.1], [1,[2,0],1.1] # Intersecting discs
[1,[3,0],1], [2,[0,0],1] # Disc outside cavity
[1,[1,0],0.1], [2,[0,0],1] # Disc partially outside cavity
[1,[0,0],2], [2,[0,0],1] # Disc encircling cavity
[2,[0,0],1], [2,[0,0],1] # Any two cavities intersect
[2,[-1,0],1], [2,[1,0],1] # Any two cavities intersect
в то время как следующее должно привести к ложному выводу
[0,[0,0],[1,0]], [0,[0,1],[1,1]] # Parallel lines
[0,[-2,0],[-1,0]], [0,[1,0],[2,0]] # Collinear non-overlapping lines
[0,[0,0],[2,0]], [0,[1,1],[1,2]] # Intersection outside one segment
[0,[0,0],[1,0]], [0,[2,1],[2,3]] # Intersection outside both segments
[0,[-1,2],[1,2]], [1,[0,0],1] # Line passes outside disc
[0,[2,0],[3,0]], [1,[0,0],1] # Circle lies outside segment
[0,[-0.5,0.5],[0.5,-0.5]], [2,[0,0],1] # Line inside cavity
[1,[-1,0],1], [1,[1,1],0.5] # Non-intersecting circles
[1,[0.5,0],0.1], [2,[0,0],1] # Circle contained within cavity
источник
[0,[-2,0],[-1,0]], [0,[1,0],[2,0]]
Ответы:
APL,
279208206203Разрывы строк в функции
f
приведены для ясности. Они должны быть заменены разделителем операторов⋄
Прошло так много времени с тех пор, как я последний раз делал такую сложную программу APL. Я думаю, что в прошлый раз было это, но я даже не уверен, что это было так сложно.
Формат ввода
В основном такой же, как у OP, за исключением использования
0
для полости,1
для диска и2
для линейного сегмента.Основное обновление
Мне удалось сыграть много символов, используя другой алгоритм. Нет больше
g
быков ** т!Основная функция
f
делится на случаи:2 2≡x
: Сегмент-сегментВ этом случае рассчитайте вектор из конечных точек каждой линии и решите систему линейных уравнений, чтобы проверить, содержится ли пересечение в векторах.
Предостережения:
Примеры: (Обратите внимание на предостережение 1 в действии на рисунке справа)
2≡2⌷x
: Сегмент-другойВ этом случае другой объект является круглым. Проверьте, находятся ли конечные точки сегмента внутри круга, используя проверку расстояния.
В случае с диском также строят отрезок линии диаметром, перпендикулярным данному отрезку. Проверьте, сталкиваются ли сегменты по рекурсии.
В случае с полостью крадитесь в «0 раз» в конструкции указанного сегмента, чтобы сделать его вырожденным. (Смотрите, почему я сейчас использую
0
для резонатора и1
для диска?) Поскольку данный сегмент не вырожден, обнаружение столкновений сегментов и сегментов всегда возвращает false.Наконец, объедините результаты проверки расстояния и обнаружения столкновений. Для случая с полостью сначала отмените результаты проверки расстояния. Затем (в обоих случаях) ИЛИ 3 результата вместе.
Что касается предостережений сегмента-сегмента, номера 3 адресованы (и эксплуатируются). Число 2 не является проблемой, поскольку мы пересекаем здесь перпендикулярные отрезки, которые никогда не параллельны, если они не вырождены. Номер 1 вступает в силу только в случае диска, когда одна из заданных конечных точек находится на расчетном диаметре. Если конечная точка находится в пределах круга, проверки расстояния позаботятся об этом. Если конечная точка находится на окружности, так как построенный диаметр параллелен данному сегменту, последний должен касаться окружности только с одной точкой, касающейся диска, что не является допустимым вводом.
Примеры:
Случай по умолчанию: Другое-Другое
Рассчитайте расстояние между центрами. Столкновение диска с диском происходит тогда и только тогда, когда расстояние меньше суммы радиусов. Столкновение диска с полостью происходит тогда и только тогда, когда расстояние больше, чем разница в радиусах.
Чтобы позаботиться о случае полость-полость, отмените результат проверки расстояния И с каждым из идентифицирующих целых чисел, а затем ИЛИ их вместе. Используя некоторую логику, можно показать, что этот процесс возвращает истину тогда и только тогда, когда оба идентифицирующих целых числа являются ложными (случай с полостью резонатора) или если проверка расстояния вернула истину
источник
Javascript - 393 байта
уменьшенная:
Expanded:
Заметки:
F
которая принимает требуемые аргументы и возвращает требуемое значениеF( 0,[[0,0],[2,2]], 0,[[1,0],[2,4]] )
илиF( 1,[[3,0],1], 2,[[0,0],1] )
.источник
Питон, 284
Я использую симпатичный алгоритм мусора по сравнению со всеми этими геометрическими уловками, но он получает правильные ответы, хотя и проходит более минуты, чтобы пройти тестовые случаи. Большим преимуществом является то, что мне нужно написать только три функции подсчета очков, а Hillclimbing заботится обо всех крайних случаях.
Golfed:
Ungolfed:
И, наконец, тестовый скрипт на тот случай, если кто-то захочет попробовать это на python:
источник