Üç işaretçi! Ama ne tür?


24

Gönderen http://en.wikipedia.org/wiki/Triangle : görüntü tanımını buraya girin


Üç 2d koordinat tuple (Kartezyen) alan ve bu üç noktanın ne şekilde tanımlandığını sınıflandıran bir program yazın.

Neredeyse tüm durumlarda, bu noktalar farklı türlerden bir üçgen tanımlayacaktır. Bazı dejenere durumlarda, noktalar tekil bir noktayı veya düz bir çizgiyi tanımlayacaktır. Program, aşağıdaki etiketlerden hangisinin açıklanan şekle uygulanacağını belirleyecektir:

  • Puan (3 puan ortak olay)
  • Çizgi (3 puan düz bir çizgide uzanır - en fazla 2 puan eşzamanlı olabilir)
  • Eşkenar (3 taraf eşit, 3 açı eşit)
  • İkizkenar (2 taraf eşit, 2 açı eşit)
  • Skalen (0 taraf eşit, 0 açı eşit)
  • Sağ (1 açı tam olarak π / 2 (veya 90 °))
  • Eğik (0 exactly tam olarak π / 2 (veya 90 °)
  • Geniş (1 açı> π / 2 (veya 90 °))
  • Akut (3 açı <π / 2 (veya 90 °))

Açıklanan bazı şekiller için, yukarıdaki etiketlerden birden fazlasının geçerli olacağını unutmayın. Örneğin, herhangi bir dik açılı da ikizkenar veya skalen olacaktır.

Giriş

  • Program, 3 giriş koordinatını STDIN, komut satırı, ortam değişkenleri veya seçtiğiniz dil için uygun olan herhangi bir yöntemden okuyabilir.
  • Bu giriş benim formatlanmamı sağlar ancak seçtiğiniz dil için uygundur. Tüm giriş numaralarının, kullandığınız veri türlerine göre iyi oluşturulduğu varsayılabilir.
  • Giriş koordinatlarının sırası hakkında hiçbir şey kabul edilemez.

Çıktı

  • Program, STDOUT'a, iletişim kutusuna veya seçtiğiniz dil için uygun olan görüntüleme yöntemine uygun olacaktır.
  • Çıkış, giriş koordinatları tarafından açıklanan şekle uygulanabilir tüm etiketleri görüntüler.
  • Etiketler herhangi bir sırayla çıkarılabilir.

Diğer kurallar

  • Dilinizin trigonometrik kitaplıklarına / API'lerine izin verilir, ancak üçgen türlerini özel olarak hesaplayan herhangi bir API yasaktır.
  • Açıların eşitliğini veya kenarların uzunluğunu belirlerken, büyük olasılıkla kayan nokta değerlerini karşılaştırmanız gerekir. Biri diğerinin% 1'inin içindeyse, bu iki değer "eşit" olarak kabul edilir.
  • Artık komik olmayan standart “boşluklar”
  • Bu , yani bayt cinsinden en kısa cevap kazanır.

Örnekler

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
Bu " Üçgen Etiketi " ni almaya başlayacaktım, ancak minimum 15 karakterden azdı.
Digital Trauma

Ya iki nokta aynıysa?
Ypnypn

@Ypnypn Bu durumda bir çizgidir.
Digital Trauma

Triangle Tag
Derek

2
"Akut" tanımında bir sorun mu var? tüm açıların PI / 2'den büyük olması imkansız mı?
Arnaud

Yanıtlar:


10

C (451 bayt)

Sadece kare uzunlukları ve eğimler kullanır.

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 (ve üçlü operatör if / else ile değiştirilir):

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
}

Giriş (stdin'den) Biçim: xyxyxy

ex. 0 0 1 1 2 0 Isosceles Right için


@digitaltrauma ./triangle <<< "1 2 1 2 1 2"tırnak işaretleri ile kullanılmalıdır.
es1024

Evet, elbette, bunun için üzgünüm. Güzel cevap Özellikle dalgalanmalardan kaçınmayı sevdiğinizden ve% 1'lik eşitlik kuralı konusunda endişelenmenize gerek yok. +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");
}

Bir an için boşluktan çıktım. Bu işe yarıyor ama muhtemelen biraz toparlanma ve golf oynayarak da başarabilirdi. @es1024Cevap matematiğe benzer , ancak bir döngü ve diziler kullanır. Giriş formatıx y x y x y

Değişkenler

t[]hem girişi hem de uzunlukların karelerini saklar. Programın sonunda aşağıdaki tabloya benziyor (döngünün yinelemelerinin sayısının artması kare uzunluklarının sınırsız bir şekilde tekrarlanmasına neden olur.) Döngü karelerinin başlangıcında uzunlukları kareler ) gereksiz hücreleri 1,3 ve 5 depolanır, ancak hemen üzerine yazılır scanf.yazılır Yararlı veri z,b,cahd szaman i= 9,11,13 ( t[i]ve t[i-2]erişilir.)

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

g[]şev hesaplaması için gereken dx ve dy değerlerini tutmak için geç eklendi. Kullanılan tek hücreler 6'dan 9'a kadardır (0'dan 5'e kadar güvenilmezdir, çünkü yazıldığında tüm veriler mevcut değildir.) g[6]/g[7]==g[8]/g[9]2 çizginin eğimi eşitse ve üçgen sadece bir çizgi ise (veya bir nokta ise) Denklem bölünmeyi önlemek için programda yeniden düzenlenir.

rkare alma için kullanılan bir ara değerdir

zsıfır uzunluktaki kenar sayısını sayar. +3 dengesine sahiptir çünkü döngü içinde 3 boş hücreyi okur t[].

caynı uzunluktaki tarafların sayısını sayar. Ayrıca +3 ofseti var. A = b, b = c, c = a'yı kontrol edebilmek için bu tarafın iki kez ayazıldığını unutmayın t[].

bBir tarafın en büyük uzunluğu karedir. sher tarafın karelerinin toplamıdır.

Yan uzunlukların A ^ 2 + B ^ 2 + C ^ 2 ile 2 * B ^ 2 ile karşılaştırılmasının A ^ 2 + C ^ 2 ile B ^ 2 ile karşılaştırılması ile aynı olduğuna dikkat edin (yalnızca her iki taraftan B ^ 2'yi çıkarın.) Böylece eğer B ^ 2 = A ^ 2 + C ^ 2 ise dik bir üçgendir. B ^ 2 daha büyükse, geniş, küçük ise akuttur.


Söz konusu şemaya dayanarak, bir eşkenar üçgen de ikizkenar üçgen olarak sınıflandırılmalıdır. (Diğer taraftan, tamsayı koordinatlarına sahip bir eşkenar üçgen oluşturmak mümkün değildir.)
es1024

es1024, üçgen (0,0) (4,7) (8,0), çok yakınlaşmaktadır (kare yan uzunlukları 64,65,65). 60 derecelik açı çizmek (diğer cevaplarımın her birine kar taneleri çizmek, kendi izometrik nokta kağıdınızı yapmak veya saat çizmek için) kullanmak kullanışlı bir yaklaşımdır. Bu kodu revize edersem ve değiştirdiğimde, soruda açıklandığı gibi karşılaştırmaya% 1 tolerans ekleyebilirim.
Seviye River St

2

Golf Betiği (175 bayt)

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

Burada test edebilirsiniz (test seti dahil).

Giriş formatı:

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

Yorumlanan sürüm:

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

NOT:

Kodumun "eşkenar" çıktı içermemesinin nedeni şudur:

  • OP, "Tüm girdi numaraları, kullandığınız veri türlerine göre iyi şekillendirildi" dedi.
  • Golfscript'in kayan nokta sayıları yoktur - doğal olarak
  • Burada kanıtlandığı gibi (2 boyutlu bir şebekede) tamsayı koordinatlarına sahip eşkenar bir üçgenin bulunması imkansızdır .

Notlarınız doğru - bu yüzden% 1 içindeki değerler anlamına gelen "eşitlik" kuralını
Digital Trauma

Yanılmıyorsam, bunu tam sayılar için değil de, kayan nokta için söyledin: “.. muhtemelen kayan nokta değerlerini karşılaştırarak bitirdiniz. ."
Kyle McCormick

0

Mathematica ( 313 307 karakter)

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

Giriş formatı üzerine fonksiyonun çağrıldığı noktaların bir listesidir:

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

Ben bir matematik çayınım. Tercüman / derleyiciyi nereden indirebilir veya çevrimiçi olarak deneyebilirim (ücretsizdir ;-))?
Dijital Travma,

Hiç kullanmadım, ancak Wolfram'ın CDF formatında saklanan Mathematica dosyalarını çalıştırdığını iddia eden, ancak normal not defterleri kullanmadığını iddia eden bir 'CDF Player' tarayıcı uygulaması var. Burada bulundu: wolfram.com/cdf-player Bunun ötesinde, 30 gün boyunca ücretsiz olduğuna inandığım ana program var.
phosgene
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.