Memecahkan segitiga dengan trigonometri

13

Saatnya untuk menggali catatan trigonometri lama Anda dari sekolah menengah! Tantangannya adalah untuk menyelesaikan sisi dan sudut segitiga yang tidak diketahui. Dan seperti kebiasaan dalam golf kode, kode kerja terkecil menang.

Ini bukan masalah sepele; implementasi referensi saya di python saat ini turun ke 838 837 karakter, tapi saya yakin Anda akan dapat solusi golf yang jauh lebih kecil.

Selain itu, jika Anda buntu, bagian Wikipedia ini akan membantu Anda: Segitiga: Menghitung sisi dan sudutnya .

Memasukkan

Segitiga berikut menunjukkan nama sisi dan sudut yang digunakan dalam tantangan ini. Perhatikan bahwa sisi adalah huruf kecil dan sudut adalah huruf besar.

Segi tiga

Input diberikan sebagai enam nilai yang dipisahkan ruang, baik pada stdinargumen baris perintah atau (pilihan Anda). Enam nilai sesuai dengan sisia, b, c dan sudut A, B, C. Sisi yang tidak dikenal diberikan sebagai tanda tanya ( ?). Baik sudut input dan output harus dalam radian. Anda dapat mengasumsikan bahwa nilai input benar (Anda tidak perlu memvalidasi apa pun). Anda juga dapat mengasumsikan bahwa segitiga input adalah non-merosot, dan bahwa semua sisi dan sudut adalah nol.

Input contoh berikut memberi tahu Anda bahwa sisi aadalah 8, sisi badalah 12dan sudut Aadalah 0.5radian:

8 12 ? 0.5 ? ?

Keluaran

Output diberikan dalam format yang sama dengan input - enam angka yang dipisahkan spasi stdout. Satu-satunya pengecualian adalah ketika tidak dimungkinkan untuk menyelesaikan segitiga input - maka string "No solution"harus ditulis stdout. Jika dua solusi mungkin, keduanya dihasilkan dengan garis baru di antara mereka.

Berikut ini adalah output untuk input di atas:

8.0 12.0 16.0899264342 0.5 0.802561439714 1.83903121388
8.0 12.0 4.97205505116 0.5 2.33903121388 0.302561439714

Output tidak harus memiliki banyak presisi, tetapi setidaknya beberapa desimal diperlukan.

Aturan

  • Input dibaca dari stdinatau argumen baris perintah
  • Output ditulis untuk stdout
  • Jika dua solusi dimungkinkan dengan input yang diberikan, output keduanya
  • Jika terlalu sedikit informasi untuk mendapatkan satu atau dua solusi yang jelas, anggap itu sebagai "No solution"kasus
  • Tidak ada kode bawaan atau yang sudah ada sebelumnya yang dapat digunakan (tentu saja Anda dapat menggunakan fungsi trigonometri, tetapi tidak "solveTriangle " atau semacamnya)
  • Kode terpendek menang

Uji kasus

Di   3 4 5 ? ? ?

Di luar 3.0 4.0 5.0 0.643501108793 0.927295218002 1.57079630572


Di   ? 4 ? 0.64 0.92 1.57

Di luar 3.00248479301 4.0 5.02764025486 0.64 0.92 1.57


Di   ? ? 5 ? 0.92 ?

Di luar No solution


Di   ? ? 5 ? 0.92 1.57

Di luar 3.03226857833 3.97800936148 5.0 0.65159265359 0.92 1.57


Di   8 12 ? 0.5 ? ?

Keluar (dua solusi)

8.0 12.0 16.0899264342 0.5 0.802561439714 1.83903121388
8.0 12.0 4.97205505116 0.5 2.33903121388 0.302561439714

Di   8 12 ? ? .5 ?

Di luar 8.0 12.0 18.3912222133 0.325325285223 0.5 2.31626736837

Semoga berhasil!

Masyarakat
sumber
Bisakah kita mengasumsikan bahwa segitiga itu non-merosot, dengan semua panjang dan sudutnya positif (khususnya, nol)?
Stanby
@ bbyby Ya, Anda bisa. Saya akan memperbarui OP.
1
Juga ... jika Anda ingin kami mencetak semua solusi, Anda harus menyediakan setidaknya satu sisi. Kalau tidak, Anda tahu, solusi tak terbatas.
Stanby
@ Bromby, saya mungkin terlalu jelas di sini. Yang saya maksud adalah, jika ada dua solusi untuk input, Anda harus mengeluarkan keduanya.

Jawaban:

7

Python, 441 karakter

from math import*
V=[map(float,raw_input().replace('?','0').split())+[0]]
for i in' '*9:
 W=[]
 for a,b,c,A,B,C,R in V:
  if B and C:A=A or pi-B-C
  if a:
   if A:R=R or a/sin(A)
   else:
    if b and c:A=acos((b*b+c*c-a*a)/2/b/c)
    elif R:N=asin(a/R);W+=[(b,c,a,B,C,N,R)];A=pi-N
  else:a=R*sin(A)
  W+=[(b,c,a,B,C,A,R)]
 V=W
V=[T for T in V if all(t>0 for t in T)]
if V:
 for T in V:print' '.join(map(str,T[:-1]))
else:print'No solution'

Apakah pemicu khas Anda untuk menghitung jawabannya. Solusi saat ini yang mungkin disimpan sebagai tupel dalam V. Setiap nilai yang tidak diketahui dicatat sebagai 0. Variabel ketujuh R adalah nilainya a/sin(A)==b/sin(B)==c/sin(C).

Saya menggunakan trik di mana nilai a / b / c didaur ulang setiap iterasi untuk menghindari banyak logika yang berlebihan. Lingkaran dalam hanya perlu menghitung nilai sisi atau sudut A.

Keith Randall
sumber
Saya menggunakan trik yang sama untuk bersepeda variabel, tetapi Anda yakin mengalahkan solusi saya. +1, pelajari beberapa trik baru dari ini :)
Omong-omong, ada masalah dengan kode Anda: coba 8 12 ? ? .5 ?.
1
Anda bisa mendapatkannya hingga 419 byte jika Anda mencukur garis putus trailing dan mengganti dua lekukan paling dalam dengan masing-masing satu dan dua tab.
Joey
Hah, ini terlihat sangat mirip dengan solusi saya, walaupun saya belum memperhatikan "semua solusi" sampai setelah Anda memposting ini. Anda dapat menyimpan lebih banyak lagi jika Anda mengganti if adengan if not adan meratakan kondisional ke level 1.
stan
4

Biasa C, 565 555 530 karakter

C bukan bahasa terbaik untuk Code Golf, saya kira, jadi itu hanya untuk bersenang-senang.

float t[6],u[6],P=3.1415;x,w,j,k,D,E;
#define y(V) for(V=0;V<6;++V)
#define Y if(p[j]&&p[k]&&
#define A(o,s,a,b,c,A,B,C) z(float*p){y(D)y(E)if(j=D%3,k=E%3,j-k){Y c)w=C=acos((a*a+b*b-c*c)/2/a/b);if(A&&B)w=C=P-A-B;Y C)w=c=sqrt(a*a+b*b-2*a*b*cos(C));if(A&&B&&a)w=b=s(B)*a/s(A);Y A&&!B&&!C)w=B=(x=A<P/2&&a<b&&p==u,1-2*x)*(asin(b*s(A)/a)-x*P);}y(j)k=w&&(p==t||x>0)&&o("%f ",a);o("\n");}main(int l,char*q[]){y(j)sscanf(*++q,"%f",t+j),u[j]=t[j];z(t);z(u);j=w||o("No solution\n");}
A(printf,sin,p[j],p[k],p[3-j-k],p[j+3],p[k+3],p[6-j-k])

Disusun dengan cc -o trig trig.c -lm. Membaca input sebagai argumen baris perintah.

Alexander Bakulin
sumber
Solusi ini juga gagal untuk 8 12 ? ? .5 ?- Saya menambahkannya sebagai test case tambahan di OP.
1
Tetap! Panjangnya berkurang sebagai efek samping :)
Alexander Bakulin
1

Perl - 412 karakter

Sebagai perl one-liner, berdasarkan dari Solusi Python Keith Randall:

use Math::Trig;@V=((map{tr/?/0/;$_}@ARGV),0);map{my@W;while(($a,$b,$c,$A,$B,$C,$R)=splice@V,0,7){$A||=pi-$B-$C if($B*$C);if($a){if($A){$R||=$a/sin$A;}else{if($b*$c){$A=acos(($b*$b+$c*$c-$a*$a)/2/$b/$c);}elsif($R){$N=asin($a/$R);push@W,$b,$c,$a,$B,$C,$N,$R;$A=pi-$N;}}}else{$a=$R*sin$A;}push@W,$b,$c,$a,$B,$C,$A,$R if($a*$b*$c>=0);}@V=@W;}(1..9);print($V[0]?join' ',map{(((6-$i++)%7)?$_:"\n")}@V:"No solution\n");

Di sini dalam bentuk yang lebih mudah dibaca:

use Math::Trig;
@V = ( ( map { tr/?/0/; $_ } @ARGV ), 0 );
map {
    my @W;
    while ( ( $a, $b, $c, $A, $B, $C, $R ) = splice @V, 0, 7 ) {
        $A ||= pi- $B - $C
             if ( $B * $C );
        if ($a) {
            if ($A) { $R ||= $a / sin $A; }
            else {
                if ( $b * $c ) {
                    $A = acos(
                        ( $b * $b + $c * $c - $a * $a ) / 2 / $b / $c );
                } elsif ($R) {
                    $N = asin( $a / $R );
                    push @W, $b, $c, $a, $B, $C, $N, $R;
                    $A = pi- $N;
                }
            }
        } else {
            $a = $R * sin $A;
        }
        push @W, $b, $c, $a, $B, $C, $A, $R
            if ( $a * $b * $c >= 0 );
    }
    @V = @W;
} ( 1 .. 9 );

print( $V[0]
         ? join ' ', map { ( ( ( 6 - $i++ ) % 7 ) ? $_ : "\n" ) } @V
         : "No solution\n" );
xxfelixxx
sumber