¡Tres punteros! ¿Pero de qué tipo?

24

De http://en.wikipedia.org/wiki/Triangle : ingrese la descripción de la imagen aquí


Escriba un programa que tome tres tuplas de coordenadas 2d (cartesianas) y clasifique qué forma describen estos tres puntos.

En casi todos los casos, estos puntos describirán un triángulo de diferentes tipos. En algunos casos degenerados, los puntos describirán un punto singular o una línea recta. El programa determinará cuáles de las siguientes etiquetas se aplican a la forma descrita:

  • Punto (3 puntos son coincidentes)
  • Línea (3 puntos se encuentran en una línea recta; no más de 2 puntos pueden ser coincidentes)
  • Equilátero (3 lados iguales, 3 ángulos iguales)
  • Isósceles (2 lados iguales, 2 ángulos iguales)
  • Escaleno (0 lados iguales, 0 ángulos iguales)
  • Recto (1 ángulo exactamente π / 2 (o 90 °))
  • Oblicuo (0 ángulos exactamente π / 2 (o 90 °))
  • Obtuso (1 ángulo> π / 2 (o 90 °))
  • Agudo (3 ángulos <π / 2 (o 90 °))

Tenga en cuenta que para algunas formas descritas, se aplicará más de una de las etiquetas anteriores. Por ejemplo, cualquier ángulo recto también será isósceles o escaleno.

Entrada

  • El programa puede leer las 3 coordenadas de entrada de STDIN, línea de comandos, variables de entorno o cualquier método que sea conveniente para el idioma que elija.
  • El formato de entrada puede ser formateado, sin embargo, es conveniente para su idioma de elección. Se puede suponer que todos los números de entrada están bien formados con respecto a los tipos de datos que termina utilizando.
  • No se puede suponer nada sobre el orden de las coordenadas de entrada.

Salida

  • El programa saldrá a STDOUT, cuadro de diálogo o cualquier método de visualización que sea conveniente para el idioma que elija.
  • La salida mostrará todas las etiquetas aplicables a la forma descrita por las coordenadas de entrada.
  • Las etiquetas pueden salir en cualquier orden.

Otras reglas

  • Las bibliotecas / API trigonométricas de su idioma están permitidas, pero cualquier API que calcule específicamente los tipos de triángulos está prohibida.
  • Al determinar la igualdad de ángulos o longitudes de lados, probablemente terminará comparando valores de punto flotante. Dos de estos valores deben considerarse "iguales" si uno está dentro del 1% del otro.
  • "Lagunas" estándar que ya no son divertidas
  • Este es el , por lo que gana la respuesta más corta en bytes.

Ejemplos

Input                   Output
(1,2) (1,2) (1,2)       Point
(1,2) (3,4) (5,6)       Line
(0,0) (1,1) (2,0)       Isosceles Right
(0,0) (2,1) (10,1)      Scalene Oblique Obtuse
Trauma digital
fuente
44
Iba a titular esta " etiqueta triangular " pero no alcanzaba el mínimo de 15 caracteres.
Trauma digital
¿Qué pasa si dos puntos son idénticos?
Ypnypn
@Ypnypn En ese caso, es una línea.
Trauma digital
Triangle Tag
Derek 朕 會 功夫
2
¿Hay algún problema con la definición "aguda"? ¿Es imposible que todos los ángulos sean mayores que PI / 2?
Arnaud

Respuestas:

10

C (451 bytes)

Utiliza solo longitudes cuadradas y pendientes.

p[2],q[2],r[2];z(c){char*y[]={"Line","Point","Isosceles ","Equilateral ","Scalene ","Right","Oblique ","Acute","Obtuse"};printf(y[c]);}d(int*a,int*b){int c=*a++-*b++,e=*a-*b;return c*c+e*e;}main(){scanf("%d%d%d%d%d%d",p,p+1,q,q+1,r,r+1);int a=d(p,q),b=d(q,r),c=d(r,p),e=!a+!b+!c,f=(a==b)+(b==c)+(c==a),g=a>b&&b>c?a:b>c?b:c,h=g^a?g^b?a+b:c+a:b+c;e?z(e/2):(1[q]-1[p])*(*r-*q)^(1[r]-1[q])*(*q-*p)?f?z(2+f/2),f-1&&z(2):z(4),h^g?z(6),z(7+(h<g)):z(5):z(0);}

Sin golf (y el operador ternario reemplazado con if / else):

int p[2],q[2],r[2];

void print(c){
    char *y[]={"Line","Point","Isosceles ","Equilateral ","Scalene ","Right","Oblique ","Acute","Obtuse"};
    printf(y[c]);
}
squared_distance(int *a,int *b){
    int c = *a++ - *b++, e = *a - *b;
    return c*c+e*e;
}
main(){
    scanf("%d%d%d%d%d%d",p,p+1,q,q+1,r,r+1); // read in coordinates
    int a = squared_distance(p,q),b = squared_distance(q,r),c = squared_distance(r,p),
    e=!a+!b+!c, // number of sides of length 0
    f=(a==b)+(b==c)+(c==a), // number of equal-length pairs
    g = a > b && b > c ? a : (b > c ? b : c), // longest side
    h = g != a ? g != b ? a + b : c + a : b + c; // sum of squares of length of other two sides
    if(e)
        print(e/2); // 1 side of len 0: line, 3 sides: point
    // comparing slopes PQ and QR
    else if((q[1]-p[1])*(*r-*q) != (r[1]-q[1])*(*q-*p)){ // not line
        if(f){
            print(2+f/2); // 1 pair of equal length sides: isosceles, 3: equilateral
            if(f-1) print(2); // equilateral therefore also isosceles
        }else print(4); // 0: scalene
        if(h!=g){ // a^2+b^2!=c^2: not right
            print(6); // oblique
            print(7+(h<g)); // a^2+b^2<c^2:obtuse, acute otherwise 
        }else print(5); // right
    }else
        print(0); // line
}

Formato de entrada (a través de stdin): xyxyxy

ex. 0 0 1 1 2 0 para Isósceles Derecha

es1024
fuente
@digitaltrauma ./triangle <<< "1 2 1 2 1 2"debe usarse con las comillas.
es1024
Sí, por supuesto, perdón por eso. Buena respuesta. En particular, me gusta que pudieras evitar las carrozas y, por lo tanto, no tengas que preocuparte por la regla de igualdad del 1%. +1
Trauma digital
3

C, 333

z,c,r,b,s,i,t[14],g[14];
main(){ 
  for(;i<14;i++){
    g[i]=r=t[(i+2)%6]-t[i%6];r*=r;t[i|1]+=r;
    i<6&&scanf("%d",t+i);
    i>7&&(b<t[i]&&(b=t[i]),s+=t[i],z+=!t[i],c+=t[i]==t[i-2]);  
  }

  if(g[6]*g[9]==g[8]*g[7])puts(z==6?"point":"line");else
    printf(b*2==s?"right ":"oblique %s",b*2>s?"obtuse ":"acute "),puts(c>3?c>5?"equilateral":"isosceles":"scalene");
}

Dejé el espacio en blanco por el momento. Esto funciona, pero probablemente podría funcionar con un poco de limpieza y golf. Matemáticas similares a @es1024las de la respuesta, pero usa un bucle y matrices. Formato de entradax y x y x y

Variables

t[]almacena tanto la entrada como los cuadrados de las longitudes. Al final del programa, se parece a la tabla a continuación (aumentar el número de iteraciones del bucle conduciría a una repetición indefinida de las longitudes al cuadrado). Al comienzo del bucle cuadrados de longitudes (basura ya que no todos los datos están disponibles ) se almacenan innecesariamente en las celdas 1,3 y 5, pero los scanf.datos útiles se sobrescriben de inmediato y se escriben en z,b,cahd scuando i= 9,11,13 ( t[i]y t[i-2]se accede a ellos).

01 23 45 67 89 1011 1213
aa bb cc  a  b    c    a
xy xy xy  L  L    L    L

g[]se agregó tarde para mantener los valores dx y dy necesarios para el cálculo de la pendiente. Las únicas celdas utilizadas son del 6 al 9 (del 0 al 5 no son confiables ya que no todos los datos están disponibles cuando se escriben). Si g[6]/g[7]==g[8]/g[9]las pendientes de 2 líneas son iguales y el triángulo es solo una línea (o un punto). La ecuación se reorganiza en el programa para evitar la división.

res un valor intermedio utilizado para cuadrar

zcuenta el número de lados de longitud cero. Tiene un desplazamiento de +3 porque el ciclo lee 3 celdas en blanco t[].

ccuenta el número de lados que tienen la misma longitud. También tiene un desplazamiento de +3. Tenga en cuenta que el lado ase escribe t[]dos veces para poder verificar a = b, b = c, c = a.

bes la mayor longitud de un lado, al cuadrado. ses la suma de los cuadrados de todos los lados.

Tenga en cuenta que comparar las longitudes de los lados A ^ 2 + B ^ 2 + C ^ 2 con 2 * B ^ 2 es lo mismo que comparar A ^ 2 + C ^ 2 con B ^ 2 (solo reste B ^ 2 de ambos lados). si B ^ 2 = A ^ 2 + C ^ 2 es un triángulo rectángulo. si B ^ 2 es mayor es obtuso, si es menor es agudo.

Level River St
fuente
Según el diagrama de la pregunta, un triángulo equilátero también debe clasificarse como un triángulo isósceles. (Por otro lado, es imposible crear un triángulo equilátero con coordenadas enteras).
es1024
@ es1024 el triángulo (0,0) (4,7) (8,0) se acerca tanto (longitudes de los cuadrados al cuadrado 64,65,65). Es una aproximación útil si desea dibujar ángulos de 60 grados (dibujar copos de nieve según una de mis otras respuestas, hacer su propio papel de punto isométrico o dibujar relojes). Probablemente también sea imposible obtener una combinación perfecta con flotadores. Si y cuando reviso este código, puedo agregar una tolerancia del 1% a la comparación, como se describe en la pregunta.
Level River St
2

Golfscript (175 bytes)

~..|,({.)2$([\;\]@(;]{{~}/@- 2?@@- 2?+}%$.{2-1??100*}/-+abs 1<{;"Line"}{.[]|,((["Isosceles ""Scalene "]=\~-+.!["Oblique ""Right "]=\.!\0>-)["Acute ""Obtuse "]=}if}{;"Point "}if

Puede probarlo aquí (conjunto de prueba incluido).

Formato de entrada:

"[x y][x y][x y]"

Versión comentada:

~                       # evaluates input string          
..|,(                   # pushes the number of unique coords - 1
{
  .)2$([\;\]@(;]        # makes all 3 possible pairings of coords
  {{~}/@- 2?@@- 2?+}%$  # gets all squares of side lengths 
  .{2-1??100*}/-+abs 1< # 0 if triangle, 1 if line
  {;"Line"}
  {
     .[]|,((["Isosceles ""Scalene "]=\   # removes duplicate side-squares,
                                         #   and use the count to determine
                                         #   if isosceles or scalene (no
                                         #   equilaterals will exist)
     ~-+.!["Oblique ""Right "]=\         # compute a^2 + b^2 - c^2. Use to
                                         #   determine if oblique or right.
                                         #   c = max side length 
     .!\0>-)["Acute ""Obtuse "]=         # use same value to determine if
                                         #   acute, obtuse, or right
  }
  if
}
{;"Point "}
if

NOTA:

La razón por la que mi código no contiene resultados "equiláteros" es porque:

  • OP dijo "todos los números de entrada están bien formados con respecto a los tipos de datos que terminas usando"
  • Golfscript no tiene números de coma flotante, no inherentemente de todos modos
  • Es imposible (en una cuadrícula bidimensional) tener un triángulo equilátero con coordenadas enteras, como se demuestra aquí .
Kyle McCormick
fuente
Sus notas son correctas, es por eso que incluí la regla sobre "igualdad" que significa valores dentro del 1%
Digital Trauma
Si no me equivoco, dijiste esto para flotantes, no para enteros: "... probablemente terminarás comparando valores de coma flotante. Dos de estos valores deben considerarse 'iguales' si uno está dentro del 1% del otro ".
Kyle McCormick
0

Mathematica ( 313 307 caracteres)

Golfizado:

f@p_:=(P=Print;R=RotateLeft;L=Length;U=Union;If[L@U@p==1,P@"Point",If[Det[Join[#,{1}]&/@p]==0,P@"Line",v=p-R@p;a=MapThread[VectorAngle[#,#2]&,{-v,R@v}];u=L@U[Norm/@v];If[u==1,P@"Equilateral",If[u==2,P@"Isosceles",P@"Scalene"]];If[MemberQ[a,Pi/2],P@"Right",P@"Oblique";If[Max@a>Pi/2,P@"Obtuse",P@"Acute"]]]])

Sin golf:

f@p_ := (
  P = Print;    (* make aliases for functions used more than once *)
  R = RotateLeft;
  L = Length;
  U = Union;
  If[L@U@p == 1,    (* if all points identical *)
   P@"Point",
   If[Det[Join[#, {1}] & /@ p] == 0,    (* if area is zero *)
    P@"Line",
    v = p - R@p;    (* cyclic vectors *)
    a = MapThread[VectorAngle[#, #2] &, {-v, R@v}];    (* interior angles *)
    u = L@U[Norm /@ v];    (* number of unique side lengths *)
    If[u == 1,
     P@"Equilateral",
     If[u == 2,
      P@"Isosceles",
      P@"Scalene"
      ]
     ];
    If[MemberQ[a, Pi/2],
     P@"Right",
     P@"Oblique";
     If[Max@a > Pi/2,
      P@"Obtuse",
      P@"Acute"
      ]
     ]
    ]
   ]
  )

El formato de entrada es una lista de puntos, sobre los cuales se llama la función:

points = {{x1,y1},{x2,y2},{x3,y3}};
f@points
fosgeno
fuente
Soy un novato en matemáticas. ¿Dónde puedo descargar un intérprete / compilador, o probarlo en línea (gratis, por supuesto ;-))?
Trauma digital
Nunca lo he usado, pero Wolfram tiene una aplicación de navegador 'CDF Player' que afirma ejecutar archivos de Mathematica almacenados en el formato CDF, pero no portátiles normales. Encontrado aquí: wolfram.com/cdf-player Más allá de eso, está el programa principal, que creo que es gratuito durante 30 días.
phosgene