Risolvere i triangoli con la trigonometria


13

È ora di scavare le tue vecchie note di trigonometria dal liceo! La sfida è risolvere i lati e gli angoli sconosciuti di diversi triangoli. E come è consuetudine nel golf del codice, vince il codice di lavoro più piccolo.

Questo non è un problema banale; la mia implementazione di riferimento in python è attualmente di 838 837 caratteri, ma sono sicuro che sarai in grado di golf soluzioni molto più piccole.

Inoltre, se sei bloccato, questa sezione su Wikipedia dovrebbe farti andare avanti: Triangolo: calcolo dei lati e degli angoli .

Ingresso

Il triangolo seguente mostra i nomi dei lati e degli angoli utilizzati in questa sfida. Nota che i lati sono in minuscolo e gli angoli in maiuscolo.

Triangolo

L'input viene fornito come sei valori separati da spazio, sia su stdinche come argomenti della riga di comando (a scelta). I sei valori corrispondono ai lati a, b, ce agli angoli A, B, C. I lati sconosciuti sono indicati come punti interrogativi ( ?). Entrambi gli angoli di ingresso e uscita devono essere in radianti. Si può presumere che i valori di input siano corretti (non è necessario convalidare nulla). Si può anche supporre che il triangolo di input sia non degenerato e che tutti i lati e gli angoli siano diversi da zero.

Il seguente esempio di input indica che lato aè 8, lato bè 12e angolo Aè 0.5radianti:

8 12 ? 0.5 ? ?

Produzione

L'output viene fornito nello stesso formato dell'input: sei numeri separati da spazi su stdout. L'unica eccezione è quando non è possibile risolvere il triangolo di input, quindi è "No solution"necessario scrivere la stringa stdout. Se sono possibili due soluzioni, vengono entrambe emesse con una nuova linea tra di loro.

Di seguito è riportato l'output per l'input sopra:

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

L'output non è richiesto per avere molta precisione, ma è necessario almeno un paio di decimali.

Regole

  • L'input viene letto dagli stdinargomenti della riga di comando
  • L'output viene scritto in stdout
  • Se sono possibili due soluzioni con l'input dato, emettere entrambi
  • Se ci sono troppo poche informazioni per ottenere una o due soluzioni chiare, consideralo un "No solution"caso
  • Non è possibile utilizzare alcun codice incorporato o preesistente (ovviamente è possibile utilizzare le funzioni trig, ma non " solveTriangle" o simili)
  • Il codice più corto vince

Casi test

Nel   3 4 5 ? ? ?

Su 3.0 4.0 5.0 0.643501108793 0.927295218002 1.57079630572


Nel   ? 4 ? 0.64 0.92 1.57

Su 3.00248479301 4.0 5.02764025486 0.64 0.92 1.57


Nel   ? ? 5 ? 0.92 ?

Su No solution


Nel   ? ? 5 ? 0.92 1.57

Su 3.03226857833 3.97800936148 5.0 0.65159265359 0.92 1.57


Nel   8 12 ? 0.5 ? ?

Out (due soluzioni)

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

Nel   8 12 ? ? .5 ?

Su 8.0 12.0 18.3912222133 0.325325285223 0.5 2.31626736837

In bocca al lupo!


Possiamo supporre che il triangolo sia non degenerato, con tutte le lunghezze e gli angoli positivi (in particolare, diversi da zero)?
stand dal

@boothby Sì, puoi. Aggiornerò l'OP.

1
Inoltre ... se vuoi che stampiamo tutte le soluzioni, devi fornire almeno un lato. Altrimenti, sai, infinite soluzioni.
stand dal

@boothby, probabilmente non ero molto chiaro qui. Quello che volevo dire è che se ci sono due soluzioni per l'input, devi produrre entrambi.

Risposte:


7

Python, 441 caratteri

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'

Fa il tuo tipico trigger per calcolare la risposta. Le attuali soluzioni possibili sono memorizzate come tuple in V. Qualsiasi valore sconosciuto viene registrato come 0. Una settima variabile R è il valore a/sin(A)==b/sin(B)==c/sin(C).

Uso un trucco in cui i valori a / b / c vengono ciclicati ogni iterazione per evitare molta logica ridondante. L'anello interno deve solo calcolare i valori del lato o dell'angolo A.


Uso un trucco simile per ciclare le variabili, ma sicuramente hai battuto la mia soluzione. +1,

A proposito, c'è un problema con il tuo codice: prova 8 12 ? ? .5 ?.

1
Puoi ottenerlo a 419 byte se ti radi dell'interruzione della riga finale e sostituisci le due rientranze più interne con una e due schede, rispettivamente.
Joey,

Ah, anche questo sembra molto simile alla mia soluzione, anche se non avevo notato "tutte le soluzioni" fino a quando non hai pubblicato questo. Puoi risparmiare ancora di più se lo sostituisci if acon if not ae appiattisci i condizionali a 1 livello.
stand dal

4

Plain C, 565 555 530 caratteri

C non è la lingua migliore per Code Golf, immagino, quindi è solo per divertimento.

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

Compilato con cc -o trig trig.c -lm. Legge l'input come argomenti della riga di comando.


Anche questa soluzione fallisce 8 12 ? ? .5 ?: l'ho aggiunta come ulteriore test nel PO.

1
Fisso! La lunghezza ridotta come effetto collaterale :)
Alexander Bakulin

1

Perl - 412 caratteri

Come un one-liner perl, basato sulla soluzione Python di 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");

Qui in una forma più leggibile:

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" );
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.