Dreiecke mit Trigonometrie lösen


13

Es ist Zeit, Ihre alten Trigonometrie-Notizen von der High School zu sammeln! Die Herausforderung besteht darin, die unbekannten Seiten und Winkel verschiedener Dreiecke zu lösen. Und wie im Codegolf üblich, gewinnt der kleinste Arbeitscode.

Dies ist kein triviales Problem. Meine Referenzimplementierung in Python ist derzeit auf 838 837 Zeichen beschränkt, aber ich bin sicher, dass Sie in der Lage sind, Lösungen zu entwickeln, die viel kleiner sind.

Wenn Sie nicht weiterkommen, hilft Ihnen dieser Abschnitt auf Wikipedia außerdem weiter: Dreieck: Berechnen der Seiten und Winkel .

Eingang

Das folgende Dreieck zeigt die Namen der Seiten und Winkel, die bei dieser Herausforderung verwendet wurden. Beachten Sie, dass die Seiten in Kleinbuchstaben und die Winkel in Großbuchstaben geschrieben sind.

Dreieck

Die Eingabe erfolgt als sechs durch Leerzeichen getrennte Werte, entweder in stdinoder als Befehlszeilenargumente (Ihre Wahl). Die sechs Werte entsprechen den Seiten a, b, cund den Winkeln A, B, C. Die unbekannten Seiten werden als Fragezeichen ( ?) angegeben. Sowohl der Eingangs- als auch der Ausgangswinkel müssen im Bogenmaß angegeben werden. Sie können davon ausgehen, dass die Eingabewerte korrekt sind (Sie müssen nichts validieren). Sie können auch davon ausgehen, dass das Eingabedreieck nicht entartet ist und dass alle Seiten und Winkel ungleich Null sind.

Das folgende Beispiel Eingabe sagt Ihnen , dass Seite aist 8, Seite bist 12und der Winkel Aist 0.5Radiant:

8 12 ? 0.5 ? ?

Ausgabe

Die Ausgabe erfolgt im gleichen Format wie die Eingabe - sechs durch Leerzeichen getrennte Zahlen an stdout. Die einzige Ausnahme ist, wenn es nicht möglich ist, das Eingabedreieck zu lösen - dann "No solution"muss in die Zeichenfolge geschrieben werden stdout. Wenn zwei Lösungen möglich sind, werden beide mit einem Zeilenumbruch ausgegeben.

Es folgt die Ausgabe für die obige Eingabe:

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

Die Ausgabe muss nicht sehr genau sein, es sind jedoch mindestens einige Dezimalstellen erforderlich.

Regeln

  • Die Eingabe wird aus stdinoder Befehlszeilenargumenten gelesen
  • Die Ausgabe wird in geschrieben stdout
  • Wenn mit der angegebenen Eingabe zwei Lösungen möglich sind, geben Sie beide aus
  • Wenn es zu wenig Informationen gibt, um eine oder zwei eindeutige Lösungen zu erhalten, sollten Sie "No solution"dies in Betracht ziehen
  • Es darf kein eingebauter oder bereits vorhandener Code verwendet werden (Sie können natürlich auch Triggerfunktionen verwenden, jedoch keinen " solveTriangle" oder einen solchen).
  • Kürzester Code gewinnt

Testfälle

Im   3 4 5 ? ? ?

aus 3.0 4.0 5.0 0.643501108793 0.927295218002 1.57079630572


Im   ? 4 ? 0.64 0.92 1.57

aus 3.00248479301 4.0 5.02764025486 0.64 0.92 1.57


Im   ? ? 5 ? 0.92 ?

aus No solution


Im   ? ? 5 ? 0.92 1.57

aus 3.03226857833 3.97800936148 5.0 0.65159265359 0.92 1.57


Im   8 12 ? 0.5 ? ?

Out (zwei Lösungen)

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

Im   8 12 ? ? .5 ?

aus 8.0 12.0 18.3912222133 0.325325285223 0.5 2.31626736837

Viel Glück!


Können wir annehmen, dass das Dreieck nicht entartet ist und alle Längen und Winkel positiv sind (insbesondere ungleich Null)?
Stand

@boothby Ja, das kannst du. Ich werde das OP aktualisieren.

1
Auch ... wenn wir alle Lösungen drucken sollen, müssen Sie mindestens eine Seite bereitstellen. Sonst wisst ihr, unendlich viele Lösungen.
Stand

@boothby, ich war mir hier wohl zu unklar. Was ich damit gemeint habe ist, wenn es zwei Lösungen für die Eingabe gibt, müssen Sie beide ausgeben.

Antworten:


7

Python, 441 Zeichen

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'

Hat dein typischer Trigger die Antwort zu berechnen. Die aktuell möglichen Lösungen werden als Tupel in V gespeichert. Alle unbekannten Werte werden als 0 aufgezeichnet. Eine siebte Variable R ist der Wert a/sin(A)==b/sin(B)==c/sin(C).

Ich benutze einen Trick, bei dem die a / b / c-Werte bei jeder Iteration durchlaufen werden, um viel redundante Logik zu vermeiden. Die innere Schleife muss nur die Werte der A-Seite oder des Winkels berechnen.


Ich benutze einen ähnlichen Trick, um die Variablen zu wechseln, aber Sie schlagen meine Lösung auf jeden Fall. +1, ein paar neue Tricks daraus gelernt :)

Übrigens gibt es ein Problem mit Ihrem Code: Versuchen Sie es 8 12 ? ? .5 ?.

1
Sie können es auf 419 Bytes bringen, wenn Sie den abschließenden Zeilenumbruch entfernen und die beiden innersten Einrückungen durch einen bzw. zwei Tabulatoren ersetzen.
Joey

Hah, das sieht auch meiner Lösung sehr ähnlich, obwohl ich die "Alle Lösungen" erst bemerkt hatte, als Sie dies gepostet haben. Sie können sogar noch mehr sparen , wenn Sie ersetzen if amit if not aund die conditionals auf 1 Ebene zu.
Stand

4

Plain C, 565 555 530 Zeichen

C ist wohl nicht die beste Sprache für Code Golf, also nur zum Spaß.

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

Kompiliert mit cc -o trig trig.c -lm. Liest Eingaben als Befehlszeilenargumente.


Diese Lösung schlägt auch fehl für 8 12 ? ? .5 ?- ich habe sie als zusätzlichen Testfall im OP hinzugefügt.

1
Fest! Die Länge als Nebeneffekt reduziert :)
Alexander Bakulin

1

Perl - 412 Zeichen

Als Perl-Einzeiler, basierend auf Keith Randalls Python-Lösung:

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

Hier in besser lesbarer Form:

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" );
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.