Trois points! Mais quel genre?

24

Depuis http://en.wikipedia.org/wiki/Triangle : entrez la description de l'image ici


Écrivez un programme qui prend trois tuples de coordonnées 2D (cartésiennes) et classe la forme décrite par ces trois points.

Dans presque tous les cas, ces points décrivent un triangle de types différents. Dans certains cas dégénérés, les points décrivent soit un point singulier, soit une ligne droite. Le programme déterminera laquelle des balises suivantes s'applique à la forme décrite:

  • Point (3 points coïncident)
  • Ligne (3 points se situent sur une ligne droite - pas plus de 2 points peuvent être co-incidents)
  • Equilatéral (3 côtés égaux, 3 angles égaux)
  • Isocèle (2 côtés égaux, 2 angles égaux)
  • Scalène (0 côtés égaux, 0 angles égaux)
  • Droite (1 angle exactement π / 2 (ou 90 °))
  • Oblique (0 angle exactement π / 2 (ou 90 °))
  • Obtuse (1 angle> π / 2 (ou 90 °))
  • Aigu (3 angles <π / 2 (ou 90 °))

Notez que pour certaines formes décrites, plusieurs des balises ci-dessus s'appliqueront. Par exemple, tout angle droit sera également isocèle ou scalène.

Contribution

  • Le programme peut lire les 3 coordonnées d'entrée de STDIN, de la ligne de commande, des variables d'environnement ou de la méthode qui convient à la langue de votre choix.
  • L'entrée coordonnée peut être formatée mais convient à la langue de votre choix. On peut supposer que tous les numéros d'entrée sont bien formés par rapport aux types de données que vous finissez par utiliser.
  • Rien ne peut être supposé sur l'ordre des coordonnées d'entrée.

Sortie

  • Le programme sortira sur STDOUT, une boîte de dialogue ou toute autre méthode d'affichage convenant à la langue de votre choix.
  • La sortie affichera toutes les balises applicables à la forme décrite par les coordonnées d'entrée.
  • Les balises peuvent être sorties dans n'importe quel ordre.

Autres règles

  • Les bibliothèques / API trigonométriques de votre langue sont autorisées, mais toutes les API qui calculent spécifiquement les types de triangle sont interdites.
  • Lors de la détermination de l'égalité des angles ou des longueurs des côtés, vous finirez probablement par comparer des valeurs à virgule flottante. Deux de ces valeurs doivent être considérées comme «égales» si l'une est à moins de 1% de l'autre.
  • Des «failles» standard qui ne sont plus drôles
  • Il s'agit de , donc la réponse la plus courte en octets l'emporte.

Exemples

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
Traumatisme numérique
la source
4
J'allais intituler ce " Triangle Tag " mais il était en deçà du minimum de 15 caractères.
Digital Trauma
Et si deux points sont identiques?
Ypnypn
@Ypnypn Dans ce cas, c'est une ligne.
Digital Trauma
Triangle Tag
Derek 朕 會 功夫
2
Il y a un problème avec la définition "aiguë"? il est impossible que tous les angles soient supérieurs à PI / 2?
Arnaud

Réponses:

10

C (451 octets)

Utilise uniquement des longueurs et des pentes carrées.

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

Non golfé (et opérateur ternaire remplacé par 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
}

Format d'entrée (via stdin): xyxyxy

ex. 0 0 1 1 2 0 pour Isocèle Droite

es1024
la source
@digitaltrauma ./triangle <<< "1 2 1 2 1 2"doit être utilisé, avec les guillemets.
es1024
Oui, bien sûr, désolé. Bonne réponse. J'aime particulièrement le fait que vous ayez pu éviter les flotteurs, et donc ne pas avoir à vous soucier de la règle de l'égalité à 1% près. +1
Digital Trauma
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");
}

J'ai laissé l'espace vide pour le moment. Cela fonctionne mais pourrait probablement faire avec du rangement et du golf. Mathématiques similaires à @es1024la réponse, mais utilise une boucle et des tableaux. Format d'entréex y x y x y

Variables

t[]stocke à la fois l'entrée et les carrés des longueurs. À la fin du programme, il ressemble au tableau ci-dessous (l'augmentation du nombre d'itérations de la boucle conduirait à une répétition indéfinie des longueurs au carré.) Au début de la boucle, des carrés de longueurs (ordures car toutes les données ne sont pas disponibles ) sont stockés inutilement dans les cellules 1,3 et 5, mais sont rapidement remplacés par Les scanf.données utiles sont écrites dans z,b,cahd slorsque i= 9,11,13 ( t[i]et t[i-2]sont accessibles.)

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

g[]a été ajouté tard pour conserver les valeurs dx et dy nécessaires au calcul de la pente. Les seules cellules utilisées sont de 6 à 9 (0 à 5 ne sont pas fiables car toutes les données ne sont pas disponibles lorsqu'elles sont écrites.) Si g[6]/g[7]==g[8]/g[9]les pentes de 2 lignes sont égales et que le triangle n'est qu'une ligne (ou un point). L'équation est réorganisé dans le programme pour éviter la division.

rest une valeur intermédiaire utilisée pour la quadrature

zcompte le nombre de côtés de longueur zéro. Il a un décalage de +3 car la boucle lit 3 cellules vides t[].

ccompte le nombre de côtés de longueur identique. Il a également un décalage de +3. Notez que le côté aest écrit t[]deux fois afin de pouvoir vérifier a = b, b = c, c = a.

best la plus grande longueur d'un côté, au carré. sest la somme des carrés de tous les côtés.

Notez que la comparaison des longueurs des côtés A ^ 2 + B ^ 2 + C ^ 2 avec 2 * B ^ 2 revient à comparer A ^ 2 + C ^ 2 avec B ^ 2 (il suffit de soustraire B ^ 2 des deux côtés). si B ^ 2 = A ^ 2 + C ^ 2 c'est un triangle rectangle. si B ^ 2 est supérieur, il est obtus, s'il est plus petit, il est aigu.

Level River St
la source
Sur la base du diagramme de la question, un triangle équilatéral devrait également être classé comme un triangle isocèle. (D'un autre côté, il est impossible de créer un triangle équilatéral avec des coordonnées entières.)
es1024
@ es1024 le triangle (0,0) (4,7) (8,0) devient si proche (longueurs des côtés carrés 64,65,65). C'est une approximation pratique si vous voulez dessiner des angles de 60 degrés (dessiner des flocons de neige pour l'une de mes autres réponses, faire votre propre papier à points isométrique ou dessiner des horloges.) Il est probablement impossible d'obtenir une correspondance parfaite avec les flotteurs aussi. Si et quand je révise ce code, je peux ajouter une tolérance de 1% à la comparaison, comme décrit dans la question.
Level River St
2

Golfscript (175 octets)

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

Vous pouvez le tester ici (set de test inclus).

Format d'entrée:

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

Version commentée:

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

REMARQUE:

La raison pour laquelle mon code ne contient aucune sortie "équilatérale" est la suivante:

  • OP a déclaré que "tous les numéros d'entrée sont bien formés par rapport aux types de données que vous finissez par utiliser"
  • Golfscript n'a pas de nombres à virgule flottante - pas intrinsèquement de toute façon
  • Il est impossible (dans une grille à 2 dimensions) d'avoir un triangle équilatéral avec des coordonnées entières, comme prouvé ici .
Kyle McCormick
la source
Vos notes sont correctes - c'est pourquoi j'ai inclus la règle sur "l'égalité" signifiant des valeurs à 1%
Digital Trauma
Si je ne me trompe pas, vous avez dit ceci pour les flottants, pas pour les entiers: ".. vous finirez probablement par comparer des valeurs à virgule flottante. Deux de ces valeurs doivent être considérées comme" égales "si l'une est à moins de 1% de l'autre . "
Kyle McCormick
0

Mathematica ( 313 307 caractères)

Golfé:

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

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

Le format d'entrée est une liste de points sur lesquels la fonction est appelée:

points = {{x1,y1},{x2,y2},{x3,y3}};
f@points
phosgène
la source
Je suis une recrue mathématique. Où puis-je télécharger un interprète / compilateur, ou l'essayer en ligne (gratuitement, bien sûr ;-))?
Digital Trauma
Je ne l'ai jamais utilisé, mais Wolfram a une application de navigation «Lecteur CDF» qui prétend exécuter des fichiers Mathematica stockés au format CDF, mais pas des cahiers ordinaires. Trouvé ici: wolfram.com/cdf-player Au-delà de cela, il y a le programme principal, qui je crois est gratuit pendant 30 jours.
phosgene