Resolver triángulos con trigonometría

13

¡Es hora de desenterrar tus viejas notas de trigonometría de la escuela secundaria! El desafío es resolver los lados y ángulos desconocidos de diferentes triángulos. Y como es habitual en el código de golf, gana el código de trabajo más pequeño.

Este no es un problema trivial; mi implementación de referencia en python actualmente se reduce a 838 837 caracteres, pero estoy seguro de que podrás encontrar soluciones de golf mucho más pequeñas.

Además, si está atascado, esta sección en Wikipedia debería ayudarlo: Triángulo: Calcular los lados y los ángulos .

Entrada

El siguiente triángulo muestra los nombres de los lados y ángulos utilizados en este desafío. Tenga en cuenta que los lados son minúsculas y los ángulos son mayúsculas.

Triángulo

La entrada se proporciona como seis valores separados por espacios, ya sea en stdino como argumentos de línea de comandos (a elección). Los seis valores corresponden a los lados a, b, cy los ángulos A, B, C. Los lados desconocidos se dan como signos de interrogación ( ?). Los ángulos de entrada y salida deben estar en radianes. Puede suponer que los valores de entrada son correctos (no tiene que validar nada). También puede suponer que el triángulo de entrada no está degenerado y que todos los lados y ángulos son distintos de cero.

La siguiente entrada de ejemplo le dice que lado aes 8, lado bes 12y ángulo Aes 0.5radianes:

8 12 ? 0.5 ? ?

Salida

La salida se da en el mismo formato que la entrada: seis números separados por espacios stdout. La única excepción es cuando no es posible resolver el triángulo de entrada, entonces se "No solution"debe escribir en la cadena stdout. Si son posibles dos soluciones, ambas salen con una nueva línea entre ellas.

A continuación se muestra la salida para la entrada anterior:

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

No se requiere que la salida tenga mucha precisión, pero se requieren al menos un par de decimales.

Reglas

  • La entrada se lee desde stdino argumentos de línea de comandos
  • La salida se escribe en stdout
  • Si son posibles dos soluciones con la entrada dada, envíe ambas
  • Si hay muy poca información para obtener una o dos soluciones claras, considérelo un "No solution"caso
  • No se puede usar código incorporado o preexistente (por supuesto, puede usar funciones trigonométricas, pero no " solveTriangle" o tal)
  • El código más corto gana

Casos de prueba

En   3 4 5 ? ? ?

Fuera 3.0 4.0 5.0 0.643501108793 0.927295218002 1.57079630572


En   ? 4 ? 0.64 0.92 1.57

Fuera 3.00248479301 4.0 5.02764025486 0.64 0.92 1.57


En   ? ? 5 ? 0.92 ?

Fuera No solution


En   ? ? 5 ? 0.92 1.57

Fuera 3.03226857833 3.97800936148 5.0 0.65159265359 0.92 1.57


En   8 12 ? 0.5 ? ?

Fuera (dos soluciones)

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

En   8 12 ? ? .5 ?

Fuera 8.0 12.0 18.3912222133 0.325325285223 0.5 2.31626736837

¡Buena suerte!

Comunidad
fuente
¿Podemos suponer que el triángulo no es degenerado, con todas las longitudes y ángulos positivos (en particular, distintos de cero)?
stand el
@boothby Sí, puedes. Actualizaré el OP.
1
Además ... si desea que imprimamos todas las soluciones, debe proporcionar al menos un lado. De lo contrario, ya sabes, infinitas soluciones.
stand
@ Boothby, probablemente no estaba muy claro aquí. Lo que quise decir es que, si hay dos soluciones para la entrada, debe generar ambas.

Respuestas:

7

Python, 441 caracteres

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'

¿Tu trigonometría típica para calcular la respuesta? Las posibles soluciones actuales se almacenan como tuplas en V. Cualquier valor desconocido se registra como 0. Una séptima variable R es el valor a/sin(A)==b/sin(B)==c/sin(C).

Utilizo un truco donde los valores de a / b / c se reciclan cada iteración para evitar mucha lógica redundante. El bucle interno solo necesita calcular valores del lado o ángulo A.

Keith Randall
fuente
Utilizo un truco similar de ciclar las variables, pero seguro superaste mi solución. +1, aprendí un par de trucos nuevos de esto :)
Por cierto, hay un problema con su código: intente 8 12 ? ? .5 ?.
1
Puede llevarlo a 419 bytes si elimina el salto de línea final y reemplaza las dos hendiduras más internas con una y dos pestañas, respectivamente.
Joey
Ja, esto también se parece mucho a mi solución, aunque no había notado "todas las soluciones" hasta justo después de que publicaste esto. Usted puede ahorrar aún más si se reemplaza if acon if not ay aplanar por las condicionales a 1 nivel.
stand
4

Llano C, 565 555 530 caracteres

C no es el mejor lenguaje para Code Golf, supongo, así que es solo por diversión.

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

Compilado con cc -o trig trig.c -lm. Lee la entrada como argumentos de línea de comando.

Alexander Bakulin
fuente
Esta solución también falla 8 12 ? ? .5 ?: la agregué como un caso de prueba adicional en el OP.
1
¡Fijo! La duración se redujo como un efecto secundario :)
Alexander Bakulin
1

Perl - 412 caracteres

Como un perl one-liner, basado en la solución 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");

Aquí en una forma más legible:

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
fuente