Résolution de triangles avec trigonométrie

13

Il est temps de déterrer vos vieilles notes de trigonométrie du lycée! Le défi consiste à résoudre les côtés et les angles inconnus de différents triangles. Et comme d'habitude dans le golf de code, le plus petit code de travail gagne.

Ce n'est pas un problème trivial; mon implémentation de référence en python est actuellement réduite à 838 837 caractères, mais je suis sûr que vous pourrez jouer à des solutions beaucoup plus petites.

De plus, si vous êtes coincé, cette section sur Wikipédia devrait vous aider: Triangle: calcul des côtés et des angles .

Contribution

Le triangle suivant montre les noms des côtés et des angles utilisés dans ce défi. Notez que les côtés sont en minuscules et les angles en majuscules.

Triangle

L'entrée est donnée sous la forme de six valeurs séparées par des espaces, sur stdinou sous forme d'arguments de ligne de commande (votre choix). Les six valeurs correspondent aux côtés a, b, cet aux angles A, B, C. Les côtés inconnus sont indiqués comme des points d'interrogation ( ?). Les angles d'entrée et de sortie doivent être exprimés en radians. Vous pouvez supposer que les valeurs d'entrée sont correctes (vous n'avez rien à valider). Vous pouvez également supposer que le triangle d'entrée n'est pas dégénéré et que tous les côtés et angles ne sont pas nuls.

L'exemple d'entrée suivant vous indique que côté aest 8, côté best 12et angle Aest 0.5radians:

8 12 ? 0.5 ? ?

Production

La sortie est donnée dans le même format que l'entrée - six nombres séparés par des espaces sont activés stdout. La seule exception est quand il n'est pas possible de résoudre le triangle d'entrée - alors la chaîne "No solution"doit être écrite stdout. Si deux solutions sont possibles, elles sont toutes deux émises avec une nouvelle ligne entre elles.

Voici la sortie pour l'entrée ci-dessus:

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

La sortie n'est pas requise pour avoir beaucoup de précision, mais au moins quelques décimales sont nécessaires.

Règles

  • L'entrée est lue à partir des stdinarguments de la ligne de commande
  • La sortie est écrite dans stdout
  • Si deux solutions sont possibles avec l'entrée donnée, sortez les deux
  • S'il y a trop peu d'informations pour obtenir une ou deux solutions claires, considérez-le comme un "No solution"cas
  • Aucun code intégré ou préexistant ne peut être utilisé (bien sûr, vous pouvez utiliser les fonctions trig, mais pas " solveTriangle" ou autre)
  • Victoires de code les plus courtes

Cas de test

Dans   3 4 5 ? ? ?

En dehors 3.0 4.0 5.0 0.643501108793 0.927295218002 1.57079630572


Dans   ? 4 ? 0.64 0.92 1.57

En dehors 3.00248479301 4.0 5.02764025486 0.64 0.92 1.57


Dans   ? ? 5 ? 0.92 ?

En dehors No solution


Dans   ? ? 5 ? 0.92 1.57

En dehors 3.03226857833 3.97800936148 5.0 0.65159265359 0.92 1.57


Dans   8 12 ? 0.5 ? ?

Out (deux solutions)

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

Dans   8 12 ? ? .5 ?

En dehors 8.0 12.0 18.3912222133 0.325325285223 0.5 2.31626736837

Bonne chance!

Communauté
la source
Peut-on supposer que le triangle est non dégénéré, avec toutes les longueurs et angles positifs (en particulier, non nul)?
stand le
@boothby Oui, vous le pouvez. Je mettrai à jour l'OP.
1
Aussi ... si vous souhaitez que nous imprimions toutes les solutions, vous devez fournir au moins un côté. Sinon, vous savez, des solutions infinies.
stand le
@boothby, j'étais probablement trop peu clair ici. Ce que je voulais dire, c'est que s'il y a deux solutions à l'entrée, vous devez sortir les deux.

Réponses:

7

Python, 441 caractères

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'

Fait votre trig typique pour calculer la réponse. Les solutions possibles actuelles sont stockées sous forme de tuples en V. Toutes les valeurs inconnues sont enregistrées comme 0. Une septième variable R est la valeur a/sin(A)==b/sin(B)==c/sin(C).

J'utilise une astuce où les valeurs a / b / c sont cyclées à chaque itération pour éviter beaucoup de logique redondante. La boucle intérieure n'a besoin que de calculer les valeurs du côté ou de l'angle A.

Keith Randall
la source
J'utilise une astuce similaire pour faire défiler les variables, mais vous avez certainement battu ma solution. +1, a appris quelques nouvelles astuces de cela :)
Au fait, il y a un problème avec votre code: essayez 8 12 ? ? .5 ?.
1
Vous pouvez l'obtenir à 419 octets si vous vous rasez de la rupture de la ligne de fin et remplacez les deux indentations les plus profondes par un et deux onglets, respectivement.
Joey
Hah, cela ressemble aussi beaucoup à ma solution, même si je n'avais remarqué "toutes les solutions" qu'après avoir posté cela. Vous pouvez économiser encore plus si vous remplacez if aavec if not aet aplatir les conditionals à 1 niveau.
boothby
4

Ordinaire C, 565 555 530 caractères

C n'est pas le meilleur langage pour Code Golf, je suppose, donc c'est juste pour le plaisir.

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

Compilé avec cc -o trig trig.c -lm. Lit l'entrée sous forme d'arguments de ligne de commande.

Alexander Bakulin
la source
Cette solution échoue également pour 8 12 ? ? .5 ?- je l'ai ajoutée comme cas de test supplémentaire dans l'OP.
1
Fixé! La longueur réduite comme effet secondaire :)
Alexander Bakulin
1

Perl - 412 caractères

En tant que Perl one-liner, basé sur la solution Python de 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");

Ici sous une forme plus lisible:

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
la source