Tiga-pointer! Tapi jenis apa?


24

Dari http://en.wikipedia.org/wiki/Triangle : masukkan deskripsi gambar di sini


Tulislah sebuah program yang membutuhkan tiga tupel koordinat 2d (Kartesius), dan klasifikasikan bentuk apa yang dijelaskan ketiga poin ini.

Dalam hampir semua kasus, titik-titik ini akan menggambarkan segitiga dengan berbagai jenis. Dalam beberapa kasus yang merosot, titik-titik tersebut akan menggambarkan titik tunggal atau garis lurus. Program akan menentukan tag mana yang berlaku untuk bentuk yang dijelaskan:

  • Poin (3 poin adalah insiden bersama)
  • Garis (3 poin terletak pada garis lurus - tidak lebih dari 2 poin dapat terjadi bersamaan)
  • Sama sisi (3 sisi sama, 3 sudut sama)
  • Sama kaki (2 sisi sama, 2 sudut sama)
  • Scalene (0 sisi sama, 0 sudut sama)
  • Kanan (1 sudut tepat π / 2 (atau 90 °))
  • Miring (0 sudut persis π / 2 (atau 90 °))
  • Obtuse (1 sudut> π / 2 (atau 90 °))
  • Akut (3 sudut <π / 2 (atau 90 °))

Perhatikan bahwa untuk beberapa bentuk yang dijelaskan, lebih dari satu tag di atas akan berlaku. Sebagai contoh, setiap sudut siku-siku juga akan sama kaki atau sama sisi.

Memasukkan

  • Program ini dapat membaca 3 input koordinat dari STDIN, baris perintah, variabel lingkungan atau metode apa pun yang sesuai untuk bahasa pilihan Anda.
  • Input mengoordinasikan format saya namun nyaman untuk bahasa pilihan Anda. Dapat diasumsikan bahwa semua nomor input terbentuk dengan baik sehubungan dengan tipe data yang akhirnya Anda gunakan.
  • Tidak ada yang dapat diasumsikan tentang pemesanan koordinat input.

Keluaran

  • Program akan menampilkan ke STDOUT, kotak dialog atau metode tampilan apa pun yang sesuai untuk bahasa pilihan Anda.
  • Output akan menampilkan semua tag yang berlaku untuk bentuk yang dijelaskan oleh koordinat input.
  • Tag dapat berupa output dalam urutan apa pun.

Peraturan Lainnya

  • Pustaka / API trigonometri bahasa Anda diizinkan, tetapi API apa pun yang secara spesifik menghitung jenis segitiga dilarang.
  • Saat menentukan persamaan sudut atau panjang sisi, Anda mungkin akan akhirnya membandingkan nilai titik apung. Dua nilai tersebut harus dianggap "sama" jika satu berada dalam 1% dari yang lain.
  • Standar “celah” yang tidak lagi lucu
  • Ini adalah , jadi jawaban tersingkat dalam byte menang.

Contohnya

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
Saya akan memberi judul " Tag Segitiga " ini tetapi kurang dari minimum 15 karakter.
Digital Trauma

Bagaimana jika dua titik itu identik?
Ypnypn

@ Ypnypn Dalam hal ini adalah garis.
Digital Trauma

Triangle Tag
Derek 朕 會 功夫

2
Ada masalah dengan definisi "Akut"? tidak mungkin semua sudut lebih besar dari PI / 2?
Arnaud

Jawaban:


10

C (451 byte)

Hanya menggunakan panjang dan lereng yang persegi.

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

Tidak disatukan (dan operator ternary diganti dengan jika / lain):

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
}

Input (melalui stdin) Format: xyxyxy

ex. 0 0 1 1 2 0 untuk Kanan Sama Kaki


@digitaltrauma ./triangle <<< "1 2 1 2 1 2"harus digunakan, dengan tanda kutip.
es1024

Ya, tentu saja, maaf soal itu. Jawaban bagus. Saya terutama suka bahwa Anda dapat menghindari mengapung, dan dengan demikian tidak perlu khawatir tentang hal aturan kesetaraan dalam 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");
}

Saya meninggalkan ruang putih untuk saat ini. Ini bekerja tetapi mungkin bisa dilakukan dengan beberapa merapikan dan bermain golf. Mirip dengan @es1024jawaban matematika , tetapi menggunakan loop dan array. Masukkan formatx y x y x y

Variabel

t[]menyimpan input dan kuadrat dari panjang. Pada akhir program terlihat seperti tabel di bawah ini (meningkatkan jumlah iterasi dari loop akan menyebabkan repitition tak terbatas dari panjang kuadrat.) Pada awal loop kuadrat dari panjang (sampah karena tidak semua data tersedia ) tidak perlu disimpan dalam sel 1,3 dan 5, tetapi segera ditimpa oleh scanf.data yang berguna ditulis ke z,b,cahd sketika i= 9,11,13 ( t[i]dan t[i-2]diakses.)

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

g[]ditambahkan terlambat untuk menahan nilai dx dan dy yang diperlukan untuk perhitungan kemiringan. Satu-satunya sel yang digunakan adalah 6 hingga 9 (0 hingga 5 tidak dapat diandalkan karena tidak semua data tersedia saat ditulis.) Jika g[6]/g[7]==g[8]/g[9]kemiringan 2 garis sama dan segitiga hanya garis (atau sebuah titik). Persamaannya diatur ulang dalam program untuk menghindari perpecahan.

radalah nilai antara yang digunakan untuk mengkuadratkan

zmenghitung jumlah sisi panjang nol. Ini memiliki offset +3 karena loop membaca 3 sel kosong t[].

cmenghitung jumlah sisi yang panjangnya identik. Ini juga memiliki offset +3. Perhatikan bahwa sisi aditulis t[]dua kali agar dapat memeriksa a = b, b = c, c = a.

badalah panjang sisi terbesar, kuadrat. sadalah jumlah kuadrat dari semua sisi.

Perhatikan bahwa membandingkan panjang sisi A ^ 2 + B ^ 2 + C ^ 2 dengan 2 * B ^ 2 sama dengan membandingkan A ^ 2 + C ^ 2 dengan B ^ 2 (cukup kurangi B ^ 2 dari kedua sisi.) jika B ^ 2 = A ^ 2 + C ^ 2 itu adalah segitiga siku-siku. jika B ^ 2 lebih besar itu tumpul, jika lebih kecil itu akut.


Berdasarkan diagram dalam pertanyaan, segitiga sama sisi juga harus diklasifikasikan sebagai segitiga sama kaki. (Di sisi lain, mustahil untuk membuat segitiga sama sisi dengan koordinat bilangan bulat.)
es1024

@ es1024 segitiga (0,0) (4,7) (8,0) menjadi sangat dekat (panjang sisi kuadrat 64,65,65). Ini adalah perkiraan praktis jika Anda ingin menggambar sudut 60 derajat (menggambar kepingan salju per salah satu jawaban saya yang lain, membuat kertas dot isometrik Anda sendiri, atau menggambar jam.) Mungkin mustahil untuk mendapatkan pasangan yang sempurna dengan pelampung juga. Jika dan ketika saya merevisi kode ini saya dapat menambahkan toleransi 1% untuk perbandingan, seperti yang dijelaskan dalam pertanyaan.
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

Anda dapat mengujinya di sini (set tes disertakan).

Masukkan format:

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

Versi yang dikomentari:

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

CATATAN:

Alasan kode saya tidak mengandung keluaran "sama sekali" adalah karena:

  • OP mengatakan "semua nomor input terbentuk dengan baik sehubungan dengan tipe data yang akhirnya Anda gunakan"
  • Golfscript tidak memiliki angka floating point - tidak inheren pula
  • Tidak mungkin (dalam kisi 2 dimensi) memiliki segitiga sama sisi dengan koordinat bilangan bulat, seperti yang dibuktikan di sini .

Catatan Anda benar - itulah sebabnya saya memasukkan aturan tentang nilai-nilai yang berarti "kesetaraan" dalam 1%
Digital Trauma

Jika saya tidak salah, Anda mengatakan ini untuk float, bukan untuk bilangan bulat: "..you kemungkinan akan berakhir dengan membandingkan nilai floating-point. Dua nilai tersebut dianggap 'sama' jika satu berada dalam 1% dari yang lain . "
Kyle McCormick

0

Mathematica ( 313 307 karakter)

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

Tidak Disatukan:

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 input adalah daftar poin, di mana fungsi dipanggil:

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

Saya seorang pemula matematika. Di mana saya dapat mengunduh juru bahasa / kompiler, atau mencoba ini secara online (gratis, tentu saja ;-))?
Digital Trauma

Saya tidak pernah menggunakannya, tetapi Wolfram memiliki aplikasi browser 'CDF Player' yang mengklaim dapat menjalankan file Mathematica yang disimpan dalam format CDF, tetapi tidak untuk notebook biasa. Ditemukan di sini: wolfram.com/cdf-player Di luar itu, ada program utama, yang saya percaya gratis selama 30 hari.
phosgene
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.