Tre punti! Ma che tipo?


24

Da http://en.wikipedia.org/wiki/Triangle : inserisci qui la descrizione dell'immagine


Scrivi un programma che prende tre tuple di coordinate 2d (cartesiane) e classifica la forma descritta da questi tre punti.

In quasi tutti i casi questi punti descriveranno un triangolo di vari tipi. In alcuni casi degeneri, i punti descriveranno un punto singolare o una linea retta. Il programma determinerà quale dei seguenti tag si applica alla forma descritta:

  • Punto (3 punti sono coincidenti)
  • Linea (3 punti si trovano su una linea retta - non più di 2 punti possono essere coincidenti)
  • Equilatero (3 lati uguali, 3 angoli uguali)
  • Isoscele (2 lati uguali, 2 angoli uguali)
  • Scalene (0 lati uguali, 0 angoli uguali)
  • Destra (1 angolo esattamente π / 2 (o 90 °))
  • Obliquo (0 angoli esattamente π / 2 (o 90 °))
  • Ottuso (1 angolo> π / 2 (o 90 °))
  • Acuto (3 angoli <π / 2 (o 90 °))

Si noti che per alcune forme descritte, verrà applicato più di uno dei tag sopra. Ad esempio, qualsiasi angolo retto sarà anche isoscele o scalene.

Ingresso

  • Il programma può leggere le 3 coordinate di input da STDIN, dalla riga di comando, dalle variabili di ambiente o da qualunque metodo sia conveniente per la tua lingua preferita.
  • L'input coordina il mio essere formattato, tuttavia è conveniente per la tua lingua preferita. Si può presumere che tutti i numeri di input siano ben formati rispetto ai tipi di dati che si utilizzano.
  • Non si può presumere nulla sull'ordinamento delle coordinate di input.

Produzione

  • Il programma verrà trasmesso su STDOUT, finestra di dialogo o qualsiasi altro metodo di visualizzazione sia conveniente per la tua lingua preferita.
  • L'output visualizzerà tutti i tag applicabili alla forma descritta dalle coordinate di input.
  • I tag possono essere emessi in qualsiasi ordine.

Altre regole

  • Le librerie / API trigonometriche della tua lingua sono consentite, ma tutte le API che calcolano specificamente i tipi di triangolo sono vietate.
  • Quando si determina l'uguaglianza di angoli o lunghezze dei lati, si finirà probabilmente per confrontare i valori in virgola mobile. Due di questi valori devono essere considerati "uguali" se uno si trova entro l'1% dell'altro.
  • "Scappatoie" standard che non sono più divertenti
  • Questo è , quindi vince la risposta più breve in byte.

Esempi

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

4
Stavo per dare il diritto a questo " Triangle Tag ", ma era al di sotto del minimo di 15 caratteri.
Trauma digitale

Cosa succede se due punti sono identici?
Ypnypn,

@Ypnypn In quel caso è una linea.
Trauma digitale

Triangle Tag
Derek 朕 會 功夫

2
C'è un problema con la definizione "Acuta"? è impossibile che tutti gli angoli siano maggiori di PI / 2?
Arnaud,

Risposte:


10

C (451 byte)

Utilizza solo lunghezze e pendenze quadrate.

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);}

Ungolfed (e operatore ternario sostituito 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 di input (tramite stdin): xxyxy

ex. 0 0 1 1 2 0 per Isoscele a destra


@digitaltrauma ./triangle <<< "1 2 1 2 1 2"dovrebbe essere usato, tra virgolette.
es1024,

Sì, certo, mi dispiace per quello. Bella risposta. Mi piace particolarmente che tu sia riuscito a evitare i float e quindi non devi preoccuparti della regola dell'uguaglianza dell'1%. +1
Trauma digitale il

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");
}

Ho lasciato lo spazio bianco per il momento. Funziona, ma probabilmente potrebbe fare con qualche riordino e golf. Matematica simile alla @es1024risposta, ma utilizza un loop e array. Formato di inputx y x y x y

variabili

t[]memorizza sia l'input che i quadrati delle lunghezze. Alla fine del programma sembra che la tabella seguente (aumentando il numero di iterazioni del ciclo porterebbe a una ripetizione indefinita delle lunghezze quadrate.) All'inizio del ciclo quadrati di lunghezze (immondizia poiché non tutti i dati sono disponibili ) sono inutilmente immagazzinato nelle cellule 1,3 e 5, ma sono prontamente sovrascritti da scanf.dati utili vengono scritti z,b,cahd squando i= 9,11,13 ( t[i]e t[i-2]sono accessibili.)

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

g[]è stato aggiunto in ritardo per contenere i valori dx e dy necessari per il calcolo della pendenza. Le uniche celle utilizzate sono da 6 a 9 (da 0 a 5 non sono affidabili in quanto non tutti i dati sono disponibili quando sono scritti.) Se g[6]/g[7]==g[8]/g[9]le pendenze di 2 linee sono uguali e il triangolo è solo una linea (o un punto). L'equazione viene riorganizzato nel programma per evitare la divisione.

rè un valore intermedio utilizzato per la quadratura

zconta il numero di lati della lunghezza zero. Ha un offset di +3 perché il ciclo legge 3 celle vuote in t[].

cconta il numero di lati di lunghezza identica. Ha anche un offset di +3. Nota che il lato aè scritto t[]due volte per poter controllare a = b, b = c, c = a.

bè la lunghezza maggiore di un lato, quadrata. sè la somma dei quadrati di tutti i lati.

Si noti che confrontare le lunghezze dei lati A ^ 2 + B ^ 2 + C ^ 2 con 2 * B ^ 2 equivale a confrontare A ^ 2 + C ^ 2 con B ^ 2 (sottrarre B ^ 2 da entrambi i lati). se B ^ 2 = A ^ 2 + C ^ 2 è un triangolo rettangolo. se B ^ 2 è maggiore è ottuso, se più piccolo è acuto.


Sulla base del diagramma nella domanda, un triangolo equilatero dovrebbe anche essere classificato come un triangolo isoscele. (D'altra parte, è impossibile creare un triangolo equilatero con coordinate intere.)
es1024

@ es1024 il triangolo (0,0) (4,7) (8,0) si avvicina (lunghezze laterali quadrate 64,65,65). È un'utile approssimazione se vuoi disegnare angoli di 60 gradi (disegnando fiocchi di neve per una delle mie altre risposte, creando la tua carta isometrica a punti o disegnando orologi.) È probabilmente impossibile trovare una corrispondenza perfetta anche con i galleggianti. Se e quando rivedo questo codice, posso aggiungere una tolleranza dell'1% al confronto, come descritto nella domanda.
Level River St

2

Golfscript (175 byte)

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

Puoi provarlo qui (set di test incluso).

Formato di input:

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

Versione commentata:

~                       # 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:

Il motivo per cui il mio codice non contiene output "equilatero" è perché:

  • OP ha detto "tutti i numeri di input sono ben formati rispetto ai tipi di dati che si utilizzano"
  • Golfscript non ha numeri in virgola mobile - non intrinsecamente comunque
  • È impossibile (in una griglia bidimensionale) avere un triangolo equilatero con coordinate intere, come dimostrato qui .

Le tue note sono corrette - ecco perché ho incluso la regola di "uguaglianza" che significa valori compresi nell'1%
Digital Trauma,

Se non sbaglio, lo hai detto per i float, non per i numeri interi: "... probabilmente finirai per confrontare i valori in virgola mobile. Due di questi valori devono essere considerati" uguali "se uno si trova all'interno dell'1% dell'altro ".
Kyle McCormick,

0

Mathematica ( 313 307 caratteri)

golfed:

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"]]]])

Ungolfed:

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"
      ]
     ]
    ]
   ]
  )

Il formato di input è un elenco di punti su cui viene chiamata la funzione:

points = {{x1,y1},{x2,y2},{x3,y3}};
f@points

Sono un novellino matematico. Dove posso scaricare un interprete / compilatore o provarlo online (gratuitamente, ovviamente ;-))?
Digital Trauma,

Non l'ho mai usato, ma Wolfram ha un'applicazione browser "CDF Player" che afferma di eseguire i file Mathematica memorizzati nel formato CDF, ma non i normali notebook. Trovato qui: wolfram.com/cdf-player Oltre a questo, c'è il programma principale, che credo sia gratuito per 30 giorni.
fosgene,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.