Este desafío se basa en la detección de colisión real que tuve que escribir para un juego simple recientemente.
Escriba un programa o función que, dados dos objetos, devuelva un valor verdadero o falso dependiendo de si los dos objetos están en colisión (es decir, se cruzan) o no.
Debe admitir tres tipos de objetos:
- Segmentos de línea : representados por 4 flotantes, que indican los dos puntos finales, es decir (x 1 , y 1 ) y (x 2 , y 2 ) . Puede suponer que los puntos finales no son idénticos (por lo que el segmento de línea no está degenerado).
- Discos : es decir, círculos rellenos, representados por 3 flotadores, dos para el centro (x, y) y uno (positivo) para el radio r .
- Cavidades : son el complemento de un disco. Es decir, una cavidad llena todo el espacio 2D, excepto una región circular, especificada por un centro y radio.
Su programa o función recibirá dos de estos objetos en forma de un número entero de identificación (de su elección) y sus 3 o 4 flotantes. Puede tomar la entrada a través de STDIN, ARGV o argumento de función. Puede representar la entrada en cualquier forma conveniente que no esté preprocesada, por ejemplo, de 8 a 10 números individuales, dos listas de valores separados por comas o dos listas. El resultado puede ser devuelto o escrito en STDOUT.
Puede suponer que los objetos están separados por al menos 10-10 unidades de longitud o que se cruzan entre sí, por lo que no debe preocuparse por las limitaciones de los tipos de punto flotante.
Este es el código de golf, por lo que gana la respuesta más corta (en bytes).
Casos de prueba
Representando segmentos de línea con 0
, discos con 1
y cavidades con 2
, usando un formato de entrada basado en listas, lo siguiente debería producir una salida verdadera:
[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
mientras que lo siguiente debería resultar en una salida falsa
[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
fuente
[0,[-2,0],[-1,0]], [0,[1,0],[2,0]]
Respuestas:
APL,
279208206203Los saltos de línea en la función
f
son para mayor claridad. Deben reemplazarse con el separador de instrucciones⋄
Ha pasado mucho tiempo desde la última vez que hice un programa APL tan complejo. Creo que la última vez fue esta, pero ni siquiera estoy seguro de que fuera tan complejo.
Formato de entrada
Básicamente igual que el OP, excepto que se usa
0
para cavidad,1
para disco y2
para segmento de línea.Actualización importante
Logré jugar muchos caracteres usando un algoritmo diferente. No más
g
toros ** t !!La función principal
f
se divide en casos:2 2≡x
: Segmento-segmentoEn este caso, calcule el vector a partir de los puntos finales de cada línea y resuelva un sistema de ecuaciones lineales para verificar si la intersección está contenida dentro de los vectores.
Advertencias:
Ejemplos: (Tenga en cuenta la advertencia 1 en acción en la figura de la derecha)
2≡2⌷x
: Segmento-otroEn este caso, el otro objeto es circular. Verifique si los puntos finales del segmento están dentro del círculo utilizando la verificación de distancia.
En el caso del disco, también construya un segmento lineal del diámetro perpendicular al segmento dado. Compruebe si los segmentos chocan por recursividad.
En el caso de la cavidad, colóquese un "multiplicado por 0" en la construcción de dicho segmento para que se degenere. (¿Ves por qué lo uso
0
para cavidad y1
para disco ahora?) Como el segmento dado no está degenerado, la detección de colisión segmento-segmento siempre devuelve falso.Finalmente, combine los resultados de las comprobaciones de distancia y la detección de colisiones. Para el caso de la cavidad, niegue primero los resultados de las comprobaciones de distancia. Luego (en ambos casos) O los 3 resultados juntos.
Con respecto a las advertencias segmento-segmento, se abordan los números 3 (y se explotan). El número 2 no es un problema ya que estamos intersectando segmentos perpendiculares aquí, que nunca son paralelos si no están degenerados. El número 1 solo tiene efecto en la caja del disco, cuando uno de los puntos finales dados está en el diámetro construido. Si el punto final está bien dentro del círculo, las comprobaciones de distancia lo habrían solucionado. Si el punto final está en el círculo, dado que el diámetro construido es paralelo al segmento dado, este último debe ser tangente al círculo con solo un punto tocando el disco, que no es una entrada válida.
Ejemplos:
Caso predeterminado: Otro-otro
Calcule la distancia entre los centros. La colisión disco-disco ocurre si y solo si la distancia es menor que la suma de los radios. La colisión de la cavidad del disco ocurre si y solo si la distancia es mayor que la diferencia en radios.
Para cuidar el caso cavidad-cavidad, niegue el resultado de la verificación de distancia, Y con cada uno de los enteros identificadores y luego O juntos. Usando algo de lógica, se puede mostrar que este proceso devuelve verdadero si y solo si ambos enteros identificadores son falsos (caso de cavidad-cavidad), o si la verificación de distancia devuelve verdadero
fuente
Javascript - 393 bytes
Minified:
Expandido:
Notas:
F
que acepta los argumentos requeridos y devuelve el valor requeridoF( 0,[[0,0],[2,2]], 0,[[1,0],[2,4]] )
oF( 1,[[3,0],1], 2,[[0,0],1] )
.fuente
Pitón, 284
Estoy usando un algoritmo de basura bonito en comparación con todos estos trucos geométricos, pero obtiene las respuestas correctas a pesar de que lleva más de un minuto superar los casos de prueba. La gran ventaja es que solo tengo que escribir las tres funciones de puntuación, y la escalada se ocupa de todos los casos extremos.
Golfizado:
Sin golf:
Y finalmente, un script de prueba en caso de que alguien más quiera probar esto en python:
fuente