Trzy wskazówki! Ale jaki?

24

From http://en.wikipedia.org/wiki/Triangle : wprowadź opis zdjęcia tutaj


Napisz program, który pobiera trzy krotki współrzędnych 2d (kartezjański) i klasyfikuje, jaki kształt opisują te trzy punkty.

W prawie wszystkich przypadkach punkty te opisują trójkąt różnych typów. W niektórych zdegenerowanych przypadkach punkty będą opisywać pojedynczy punkt lub linię prostą. Program określi, które z następujących znaczników dotyczą opisanego kształtu:

  • Punkt (3 punkty to incydent)
  • Linia (3 punkty leżą na linii prostej - nie więcej niż 2 punkty mogą być współwystępujące)
  • Równoległe (3 strony równe, 3 kąty równe)
  • Równoramienne (2 strony równe, 2 kąty równe)
  • Skalen (0 boków równych, 0 kątów równych)
  • W prawo (1 kąt dokładnie π / 2 (lub 90 °))
  • Ukośne (0 kątów dokładnie π / 2 (lub 90 °))
  • Tępy (1 kąt> π / 2 (lub 90 °))
  • Ostre (3 kąty <π / 2 (lub 90 °))

Pamiętaj, że w przypadku niektórych opisanych kształtów zastosowanie będzie mieć więcej niż jeden z powyższych znaczników. Na przykład każdy kąt prosty będzie albo równoramienny, albo skalenowy.

Wkład

  • Program może odczytać 3 współrzędne wejściowe ze STDIN, wiersza poleceń, zmiennych środowiskowych lub dowolnej innej metody dogodnej dla wybranego języka.
  • Współrzędne wejściowe mogą być sformatowane, ale jest to wygodne dla wybranego języka. Można założyć, że wszystkie liczby wejściowe są dobrze uformowane w odniesieniu do typów danych, z których ostatecznie korzystasz.
  • Nic nie można założyć o uporządkowaniu współrzędnych wejściowych.

Wydajność

  • Program wyświetli STDOUT, okno dialogowe lub dowolną metodę wyświetlania dogodną dla wybranego języka.
  • Wyjście wyświetli wszystkie znaczniki mające zastosowanie do kształtu opisanego przez współrzędne wejściowe.
  • Tagi mogą być wyprowadzane w dowolnej kolejności.

Inne zasady

  • Dopuszczalne są trygonometryczne biblioteki / interfejsy API w Twoim języku, ale wszelkie interfejsy API, które specjalnie obliczają typy trójkątów, są zakazane.
  • Przy określaniu równości kątów lub długości boków prawdopodobnie skończysz na porównywaniu wartości zmiennoprzecinkowych. Dwie takie wartości należy uznać za „równe”, jeśli jedna mieści się w granicach 1% drugiej.
  • Standardowe „luki”, które nie są już śmieszne
  • To jest , więc wygrywa najkrótsza odpowiedź w bajtach.

Przykłady

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
Cyfrowa trauma
źródło
4
Miałem zamiar nadać temu „ Triangle Tag ”, ale nie było to minimum 15 znaków.
Digital Trauma
Co jeśli dwa punkty są identyczne?
Ypnypn
@Ypnypn W takim przypadku jest to linia.
Digital Trauma
Triangle Tag
Derek 功夫 會 功夫
2
Wystąpił problem z definicją „ostrej”? to niemożliwe, żeby wszystkie kąty były większe niż PI / 2?
Arnaud,

Odpowiedzi:

10

C (451 bajtów)

Używa tylko kwadratowych długości i nachyleń.

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

Niegolfowany (i operator trójskładnikowy zastąpiony przez 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 wejściowy (poprzez standardowe wejście): xyxyxy

dawny. 0 0 1 1 2 0 dla Isosceles Right

es1024
źródło
./triangle <<< "1 2 1 2 1 2"Należy używać @digitaltrauma , wraz z cytatami.
es1024
Tak, oczywiście, przepraszam za to. Niezła odpowiedź. Szczególnie podoba mi się to, że udało ci się uniknąć spławików, a zatem nie musisz się martwić o zasadę równości 1%. +1
Cyfrowa 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");
}

Na chwilę zostawiłem spację. To działa, ale prawdopodobnie przydałoby się trochę porządkowania i gry w golfa. Podobna matematyka do @es1024odpowiedzi, ale wykorzystuje pętlę i tablice. Format wejściowyx y x y x y

Zmienne

t[]przechowuje zarówno dane wejściowe, jak i kwadraty długości. Pod koniec programu wygląda to tak, jak w poniższej tabeli (zwiększenie liczby iteracji pętli doprowadziłoby do nieokreślonego powtarzania kwadratowych długości). Na początku pętli kwadraty długości (śmieci, ponieważ nie wszystkie dane są dostępne ) niepotrzebnie przechowywane w komórkach 1,3 i 5, ale są szybko zastępowane przez scanf.wartościowe dane są zapisywane do z,b,cAHD sgdy i= 9,11,13 ( t[i]i t[i-2]są dostępne).

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

g[]dodano późno, aby zachować wartości dx i dy potrzebne do obliczenia nachylenia. Jedyne użyte komórki to 6 do 9 (0 do 5 są niewiarygodne, ponieważ nie wszystkie dane są dostępne, gdy są zapisane). Jeśli g[6]/g[7]==g[8]/g[9]nachylenia 2 linii są równe, a trójkąt jest tylko linią (lub punktem). Równanie jest zmieniany w programie, aby uniknąć podziału.

rjest wartością pośrednią stosowaną do kwadratu

zzlicza liczbę boków o długości zero. Ma przesunięcie +3, ponieważ pętla odczytuje 3 puste komórki t[].

cliczy liczbę boków o identycznej długości. Ma również przesunięcie +3. Zauważ, że strona ajest napisana t[]dwa razy, aby móc sprawdzić a = b, b = c, c = a.

bto największa długość boku, kwadrat. sjest sumą kwadratów wszystkich stron.

Zauważ, że porównanie długości boku A ^ 2 + B ^ 2 + C ^ 2 z 2 * B ^ 2 jest takie samo jak porównanie A ^ 2 + C ^ 2 z B ^ 2 (wystarczy odjąć B ^ 2 z obu stron.) jeśli B ^ 2 = A ^ 2 + C ^ 2, jest to trójkąt prostokątny. jeśli B ^ 2 jest większy, jest tępy, jeśli mniejszy, jest ostry.

Level River St
źródło
Na podstawie diagramu w pytaniu trójkąt równoboczny należy również zaklasyfikować jako trójkąt równoramienny. (Z drugiej strony nie można utworzyć trójkąta równobocznego o współrzędnych całkowitych.)
es1024
@ es1024 trójkąt (0,0) (4,7) (8,0) zbliża się tak bardzo (kwadraty długości boku 64 645,65). Jest to przydatne przybliżenie, jeśli chcesz narysować kąty 60 stopni (rysowanie płatków śniegu na jedną z moich innych odpowiedzi, tworzenie własnego papieru z kropkami izometrycznymi lub rysowanie zegarów.) Prawdopodobnie niemożliwe jest uzyskanie idealnego dopasowania z pływakami. Jeśli i kiedy zmienię ten kod, mogę dodać 1% tolerancji do porównania, jak opisano w pytaniu.
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

Możesz to przetestować tutaj (zestaw testowy w zestawie).

Format wejściowy:

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

Skomentowana wersja:

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

UWAGA:

Mój kod nie zawiera danych wyjściowych „równoważnych”, ponieważ:

  • OP powiedział: „wszystkie liczby wejściowe są dobrze sformułowane w odniesieniu do typów danych, których używasz”
  • Golfscript nie ma liczb zmiennoprzecinkowych - i tak nie jest z natury związany
  • Nie jest możliwe (w siatce dwuwymiarowej) posiadanie trójkąta równobocznego o współrzędnych całkowitych, jak tu udowodniono .
Kyle McCormick
źródło
Twoje notatki są poprawne - dlatego zawarłem zasadę „równości”, co oznacza wartości w granicach 1%
Cyfrowa trauma
Jeśli się nie mylę, powiedziałeś to o liczbach zmiennoprzecinkowych, a nie liczbach całkowitych: „... prawdopodobnie skończysz porównywanie wartości zmiennoprzecinkowych. Dwie takie wartości należy uznać za„ równe ”, jeśli jedna z nich mieści się w granicach 1% drugiej . ”
Kyle McCormick
0

Mathematica ( 313 307 znaków)

Gra w golfa:

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

Nie golfowany:

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

Format wejściowy to lista punktów, w których wywoływana jest funkcja:

points = {{x1,y1},{x2,y2},{x3,y3}};
f@points
fosgen
źródło
Jestem debiutantem matematyki. Gdzie mogę pobrać tłumacza / kompilatora lub wypróbować go online (oczywiście za darmo ;-))?
Cyfrowa trauma
Nigdy go nie używałem, ale Wolfram ma aplikację przeglądarki „CDF Player”, która twierdzi, że uruchamia pliki Mathematica przechowywane w formacie CDF, ale nie zwykłe zeszyty. Znaleziony tutaj: wolfram.com/cdf-player Poza tym istnieje program główny, który moim zdaniem jest bezpłatny przez 30 dni.
fosgen