En este desafío, se le dará una lista de puntos. Estos puntos se encuentran en el perímetro de un cuadrado imaginario . Tu objetivo es:
- Si es posible, imprima la rotación del cuadrado, que será un valor de [0, 90) donde 0 representa un cuadrado con líneas verticales y horizontales. La rotación se debe dar en grados contados en sentido antihorario.
- Si la rotación del cuadrado es ambigua (como que solo se le otorgan 2 puntos), imprima "Desconocido"
- Si es imposible crear un cuadrado dados los puntos, imprima "Imposible"
Los puntos que se le otorgan están garantizados para ser únicos, y no están en un orden particular. Puede usar cualquier formato que desee ingresar a la lista, pero para mis ejemplos, mis puntos estarán en el formato x,y
y separados por espacios. Los números son números de coma flotante, y puede suponer que están dentro de un rango que su idioma puede manejar. Su salida debe tener una precisión de al menos 3 decimales, y asumir que su idioma maneja números de coma flotante con perfecta precisión.
Aquí hay algunos casos de prueba (he hecho la mayoría de estos utilizando números enteros para facilitar la visualización, pero su programa debe manejar puntos flotantes):
Desconocido:
0,0
0,0 1,0
0,0 1,0 0,1
0,0 1,0 0,1 1,1
0,1 0,2 1,0 1,3 2,0 2,3 3,1 3,2
Imposible:
0,0 1,0 2,0 3,1 4,2
0,0 1,0 2,0 1,1
0,1 0,2 1,0 1,3 2,0 2,3 3,1 3,2 2,2
2,0 0,1 2,2 0,3
0,0 2,1 0,2 2,2 -1,1
Posible (si no se designa, debe devolver 0):
0,0 1,0 2,0
0,0 0.3,0.3 0.6,0.6 (should return 45)
0,0 0.1,0.2 0.2,0.4 (should return appx 63.435 (the real value is arctan(2)))
0,0 0,1 2,1 2,2
0,1 0,2 1,0 1,4 2,0 2,4 4,1 4,3
Puede que me haya perdido algunos casos de prueba interesantes. Si es así, comente para agregarlos.
Este es el código de golf, por lo que gana el código más corto.
Respuestas:
Rev 1: Ruby, 354 bytes
más golf gracias al blutorange.
Rubí, 392 bytes.
El algoritmo es como sigue:
-Seleccione un punto arbitrario (el primero) y muévalo al origen (reste las coordenadas de este punto de todos los puntos de la lista).
-Probar todas las rotaciones del cuadrado sobre el origen en incrementos de 0.001 grados, hasta 360 grados.
-Para una rotación dada, si todos los puntos están por encima del eje y, dibuje el cuadrado más pequeño posible alrededor de todos los puntos, incorporando el punto más bajo y el más a la izquierda.
-Compruebe si todos los puntos están en el borde. Esto se hace con un cálculo suave que toma cada punto, encuentra las distancias al cuadrado de todos los bordes y los multiplica. Esto da un buen ajuste en lugar de una respuesta sí / no. Se interpreta que se encuentra una solución si este producto dividido por la longitud lateral ^ 8 es menor que 1E-9. En la práctica, esto es menos de un grado de tolerancia.
-El mejor ajuste se toma mod 90 grados y se informa como el ángulo correcto.
Actualmente, el código devuelve un valor ambiguo si se encuentran más de 100 soluciones (con una resolución de 0,001 grados. Eso es 0,1 grados de tolerancia).
primera función completamente funcional, en programa de prueba
Dejé la resolución en 1/10 de la resolución requerida para que la velocidad fuera razonable. Hay un error de 0.01 degress en el último caso de prueba.
La versión de golf, resolución que cumple con las especificaciones, toma aproximadamente un minuto por llamada, en el programa de prueba.
Todavía hay un error molesto de 0.001 grados en el último caso de prueba. Incrementar aún más la resolución probablemente lo eliminaría.
Tenga en cuenta que para aproximadamente un 30% más de código, este algoritmo podría adaptarse para trabajar rápido: es obvio que en casos con un número finito de soluciones, uno de los bordes se encuentra plano a lo largo de un cubo, por lo que todo lo que realmente tenemos que probar es esos ángulos que corresponden a cada par de vértices. También sería necesario mover un poco para comprobar que no hay infinitas soluciones.
fuente
0,0 1,0 2,0 1,2
todavía es posible para un cuadrado de diagonal 0,0 ... 2,2. He intentado eso, y también0,0 1,0 2,0 1,1
(lo último es realmente imposible). Otro punto: ¿considera aceptable o inaceptable que mi código devuelva imposible en lugar de desconocido cuando solo se da un único punto? Agradecería una respuesta antes de comenzar a jugar al golf.1,1
. No estoy seguro de cómo1,2
llegó allí. No es aceptableif..end
correos electrónicos porque tengo problemas terribles con los operadores ternarios anidados en Ruby. Veo que lo superaste usando&&
.Perl
Hola, aquí está mi humilde alma. Los casos de prueba se colocan en la secuencia de DATOS en la parte inferior del archivo. El algoritmo ha crecido mediante un enfoque de prueba-error.
Admito que es un enfoque ampliamente heurístico, pero es realmente rápido: resuelve todos los casos al instante .
Soy consciente de que habrá algunos errores, pero hasta ahora da respuestas correctas a todos los casos de prueba.
También soy consciente de que gana el código más corto , pero estoy seguro de que este es uno de los más cortos en el sentido más rápido del término.
Aquí está el algoritmo
examinar puntos y para cada segmento entre dos puntos registrar pendiente, longitud, intersección x, intersección y
encuentre líneas rectas (es decir, tres puntos o dos segmentos adyacentes) y distintas pendientes posibles (por ejemplo, rotaciones). Mantenga un registro del segmento más largo disponible en cada línea.
encuentre todas las distancias entre un segmento y un tercer punto (esto debería usarse para señalar el punto 4). Mantenga un registro de la distancia mínima que no sea cero.
para cualquier cuatro puntos (un rectángulo áspero) encuentre puntos internos
Mostrar soluciones:
A. Diga "Imposible" si hay uno o más puntos internos.
B. Una línea:
En el caso de la mayoría de los puntos en una sola línea sin puntos internos, diga "Posible"
En caso de puntos demasiado cerca de la línea, diga "Imposible"
C. Dos líneas:
Diga "Posible" cuando solo hay una rotación posible
Diga "imposible" cuando hay más de una rotación
D. Sin líneas: encuentre la rotación que se ajuste a su segmento de rotación de 90 °
Diga "Posible" si solo cabe uno o tantos puntos como quepan.
Diga "Imposible" si cabe más de uno y no tantos como puntos
Diga "Desconocido" si caben tantos como la rotación.
Aquí está el código (se resuelven todos los errores conocidos)
Y aquí está su salida
Saludos.
Matteo
fuente