Colisión de bolas de billar

24

Dadas las posiciones bidimensionales y las velocidades de un par de bolas de billar justo antes del impacto, calcule sus velocidades después de una colisión perfectamente elástica . Se supone que las bolas son esferas ideales (o equivalente: círculos) con el mismo radio, la misma masa, densidad uniforme y sin fricción.

La entrada consta de 8 números: p0x,p0y,v0x,v0y,p1x,p1y,v1x,v1ydónde p0x,p0yestá el centro de la primera bola, v0x,v0ysu velocidad y de manera similar p1x,p1y,v1x,v1ypara la segunda bola. Puede aceptar entradas en cualquier orden y estructuradas de cualquier manera conveniente, por ejemplo, como una matriz de 2x2x2, o tal vez una matriz de 2x2 para py dos matrices de longitud 2 para v0y v1. También está bien tomar números complejos (si su idioma los admite) en lugar de pares xy. Sin embargo, no debe tomar datos en un sistema de coordenadas que no sea cartesiano, es decir, no se permite polar.

Tenga en cuenta que el radio de una bola de billar es la mitad de la distancia entre p0x,p0yy p1x,p1y, por lo que no se proporciona como una parte explícita de la entrada.

Escriba un programa o función que genere o devuelva 4 números en cualquier representación cartesiana conveniente: los valores posteriores a la colisión de v0x,v0y,v1x,v1y.

diagrama de colisión

Un posible algoritmo es:

  • encuentra la línea normal que pasa por ambos centros

  • encuentre la línea tangente que pasa por el punto medio entre los dos centros y es perpendicular a la línea normal

  • cambiar el sistema de coordenadas y descomponer v0x,v0yy v1x,v1yen sus componentes tangenciales y normales v0t,v0nyv1t,v1n

  • intercambiar los componentes normales de v0y v1, preservando sus componentes tangenciales

  • cambiar de nuevo al sistema de coordenadas original

Pruebas (resultados redondeados a 5 decimales):

   p0x   p0y   v0x   v0y   p1x   p1y   v1x   v1y ->      v0x'       v0y'       v1x'       v1y'
[-34.5,-81.8, 34.7,-76.1, 96.2,-25.2, 59.2,-93.3] [  49.05873, -69.88191,  44.84127, -99.51809]
[ 36.9, 77.7,-13.6,-80.8, -7.4, 34.4, 15.1,-71.8] [   5.57641, -62.05647,  -4.07641, -90.54353]
[-51.0, 17.6, 46.1,-80.1, 68.6, 54.0,-35.1,-73.9] [ -26.48927,-102.19239,  37.48927, -51.80761]
[-21.1,-52.6,-77.7, 91.5, 46.0, 94.1, 83.8, 93.7] [ -48.92598, 154.40834,  55.02598,  30.79166]
[ 91.3, -5.3, 72.6, 89.0, 97.8, 50.5, 36.2, 85.7] [  71.73343,  81.56080,  37.06657,  93.13920]
[-79.9, 54.9, 92.5,-40.7,-20.8,-46.9,-16.4, -0.9] [  47.76727,  36.35232,  28.33273, -77.95232]
[ 29.1, 80.7, 76.9,-85.1,-29.3,-49.5,-29.0,-13.0] [  86.08581, -64.62067, -38.18581, -33.47933]
[ 97.7,-89.0, 72.5, 12.4, 77.8,-88.2, 31.5,-34.0] [  33.42847,  13.97071,  70.57153, -35.57071]
[-22.2, 22.6,-61.3, 87.1, 67.0, 57.6,-15.3,-23.1] [ -58.90816,  88.03850, -17.69184, -24.03850]
[-95.4, 15.0,  5.3, 39.5,-54.7,-28.5, -0.7,  0.8] [  21.80656,  21.85786, -17.20656,  18.44214]
[ 84.0,-26.8,-98.6,-85.6,-90.1, 30.9,-48.1, 37.2] [ -89.76828, -88.52700, -56.93172,  40.12700]
[ 57.8, 90.4, 53.2,-74.1, 76.4,-94.4,-68.1,-69.3] [  51.50525, -57.26181, -66.40525, -86.13819]
[ 92.9, 69.8,-31.3, 72.6,-49.1,-78.8,-62.3,-81.6] [-123.11680, -23.48435,  29.51680,  14.48435]
[-10.3,-84.5,-93.5,-95.6, 35.0, 22.6, 44.8, 75.5] [ -11.12485,  99.15449, -37.57515,-119.25449]
[ -3.9, 55.8,-83.3,  9.1, -2.7,-95.6, 37.7,-47.8] [ -82.84144, -48.75541,  37.24144,  10.05541]
[-76.5,-88.4,-76.7,-49.9, 84.5, 38.0,  4.2, 18.4] [   6.52461,  15.43907, -79.02461, -46.93907]
[ 64.2,-19.3, 67.2, 45.4,-27.1,-28.7, 64.7, -4.3] [  59.66292,  44.62400,  72.23708,  -3.52400]
[  9.8, 70.7,-66.2, 63.0,-58.7, 59.5, 83.7,-10.6] [  68.07646,  84.95469, -50.57646, -32.55469]
[ 62.9, 46.4, 85.0, 87.4, 36.3,-29.0,-63.0,-56.3] [  23.53487, -86.82822,  -1.53487, 117.92822]
[ -5.5, 35.6, 17.6,-54.3, -2.2, 66.8,-15.2, 11.8] [  24.15112,   7.63786, -21.75112, -50.13786]

Las victorias más cortas. No hay escapatorias.


gracias @Anush por ayudar a arreglar el color de fondo del diagrama

ngn
fuente

Respuestas:

16

Python 3 , 67 66 bytes, 53 bytes

def f(p,v,q,w):p-=q;d=((v-w)/p).real*p;return v-d,w+d

Pruébalo en línea!

-1 byte gracias a @ngn

-13 bytes gracias a @Neil

Esta función ftoma cuatro números complejos como entrada y devuelve dos números complejos. La versión sin golf se muestra a continuación.

Sin golf

def elastic_collision_complex(p1, v1, p2, v2):
    p12 = p1 - p2
    d = ((v1 - v2) / p12).real * p12
    return v1 - d, v2 + d

Pruébalo en línea!

La fórmula de cálculo se deriva de la fórmula del vector 2D en wiki . Como , la fórmula se puede simplificar a m1=m2

{v1=v1dvv2=v2+dv

Deje y , tenemosx12=x1x2v12=v1v2

dv=v12,x12x122x12=Re(v12x12¯)x12x12¯x12=Re(v12x12¯x12x12¯)x12=Re(v12x12)x12

En el programa de ungolfed, p12, v1 - v2, dcorresponden a , , y , respectivamente.x12y12dv

Joel
fuente
1
¡bien hecho! Este enfoque se ve diferente de la respuesta perl6 de Ramillies, que también utiliza números complejos. usted podría ahorrar un byte si se reemplaza r=p-qcon p-=qy uso posterior pen lugar de r, como en la respuesta de Neil JS
NGN
1
@ngn, se ve diferente pero es lo mismo, como Joel señala correctamente. Escribí la fórmula en una forma que era buena para el golf Perl 6, y presumiblemente Joel usó una que era mejor para Python. De todos modos, no pensé que a nadie más se le ocurriría una solución usando números complejos de forma independiente. ¡Buen trabajo!
Ramillies
3
Agradable, pero si usaste el algoritmo en la pregunta solo tomaría 53 bytes ...
Neil
1
@Neil Gracias por tu pista. El cálculo se simplifica enormemente ahora.
Joel
3
¡Realmente me gustan todas sus excelentes soluciones y explicaciones detalladas!
xnor
11

JavaScript (Node.js) , 90 88 bytes

(m,n,o,p,q,r,s,t,u=(q-=m)*q+(r-=n)*r,v=o*q+p*r-s*q-t*r)=>[o-(q*=v/u),p-(v*=r/u),s+q,t+v]

Pruébalo en línea! El enlace incluye un conjunto de pruebas. Explicación: q,rse reutilizan como el vector de diferencia entre los centros, y ues el cuadrado de su longitud. ves la diferencia en los productos punto de o,py s,tcon q,r, también lo v/ues el factor de escala q,rque da la cantidad de velocidad transferida de o,pa s,t. Editar: Guardado 2 bytes gracias a @Arnauld.

Neil
fuente
No esperaba que alguien simplificara el algoritmo tan rápido, ¡bien hecho! aquí hay una visualización de su solución (con la mejora de Arnauld)
ngn
@ngn ¿Enlace incorrecto?
Neil
El registro de tuberías de @Neil gitlab dice que debería estar allí. ctrl + f5? Las flechas controlan la bola roja. cambio acelera. probado en firefox y cromo. advertencia: sonido.
ngn
@ngn Ah, trabajando ahora, ¡gracias! (Obtuve un 404 antes. Además, estaba usando una pestaña privada, por lo que no tenía sonido por defecto, aunque no lo encontré intrusivo. Y soy inútil en los asteroides, de lo contrario pediría un "disparo" "clave ...)
Neil
8

Perl 6 ,75 64 63 61 bytes

11 bytes guardados al cambiar de mapa for, prescindiendo de la necesidad de poner cosas en variables intermedias para que las mapvea.

1 byte guardado al cambiar ($^a-$^c)².&{$_/abs}a ($^a-$^c).&{$_/.conj}.

2 bytes guardados gracias a @nwellnhof.

{(.($^b+$^d,{$_/.conj}($^a-$^c)*($b-$d).conj)/2 for *-*,*+*)}

Pruébalo en línea!


Explicación

Cuando la publicación original decía que la entrada podía ser números complejos, era demasiado difícil de resistir ... Entonces, esto toma 4 números complejos (posición 1, velocidad 1, posición 2, velocidad 2) y devuelve las velocidades como números complejos.

El programa utiliza el mismo algoritmo que se describe en el OP. Sin embargo, con números complejos, eso es bastante simple. Primero, observemos que el número complejo puntos desde la primera bola hasta la segunda. Entonces, si dividimos todas las velocidades por él, la dirección normal de repente coincide con el eje real y la dirección tangente con el eje imaginario. (Esto arruina las magnitudes pero no nos importa).d=p1p0

Ahora, necesitamos cambiar las partes normales (es decir, reales) de las velocidades y , y luego, multiplicarlo por nuevamente para hacer que el punto normal (y las velocidades) apunten en la dirección correcta (y hacia Desate las magnitudes). Por lo tanto, debemos calcular (donde = real parte, = parte imaginaria). Mezclemos el primero un poco (usando para conjugación compleja): v0/dv1/dd

v0=d(v1d+iv0d),v1=d(v0d+iv1d)
v0=d(v1d+iv0d)=d[12(v1d+v1d)+12(v0dv0d)]= =d2(v0+v1dv0v1d)=12(v0+v1dd(v0v1)).
El resultado para se puede obtener simplemente cambiando . Todo lo que hace es cambiar un signo: v1v0v1
v1=12[v0+v1+dd(v0v1)].

Y eso es. Todo lo que el programa hace es solo este cálculo, un poco de golf.

Ramillies
fuente
¡muy genial!
ngn
No sé mucho sobre Perl, pero creo que podría fusionar los dos cálculos conjugados en uno para guardar algunos bytes.
Joel
1
@ Joel - Lamentablemente, estoy bastante seguro de que no puedo. El primer conjugado actúa ($^a-$^c)(y solo dentro de una lambda que normaliza este número), el segundo actúa ($b-$d). Por lo tanto, realmente no se pueden reconciliar. Podría hacer una función que simplemente llamara .conj, pero que solo agregaría bytes (porque uso mucho la $_variable, que tiene la buena propiedad de que puede llamar métodos sin especificarla: en .conjlugar de $_.conj).
Ramillies
@ Ramillies Gracias por la explicación.
Joel
¿Cómo es relevante la magnitud de δ? Simplemente está dividiendo por δ, cambiando los componentes reales y luego multiplicando por δ nuevamente.
Neil
3

Jalea , 16 bytes

_/×ḋ÷²S¥_/ʋ¥N,$+

Pruébalo en línea!

Un enlace diádico que toma como argumento izquierdo una lista de las posiciones iniciales [[p0x, p0y], [p1x, p1y]]y su argumento derecho las velocidades iniciales [[v0x, v0y], [v1x, v2y]]. Devuelve una lista de las velocidades finales.[[v0x', v0y'], [v1x', v2y']]

Según el algoritmo utilizado por la respuesta de JavaScript de @ Neil, ¡ asegúrese de votar ese también!

Nick Kennedy
fuente
3

C (gcc) , 140 132 bytes

f(m,n,o,p,q,r,s,t,a)float*a,m,n,o,p,q,r,s,t;{q-=m;r-=n;m=q*q+r*r,n=o*q+p*r-s*q-t*r;q*=n/m;*a++=o-q;n*=r/m;*a++=p-n;*a++=s+q;*a=t+n;}

Pruébalo en línea!

Básicamente, un puerto de la respuesta JavaScript de @ Neil, pero luego @ceilingcat redujo 8 bytes reutilizando inteligentemente my nalmacenando temporarios.

G. Sliepen
fuente
2

Python 2 , 97 92 bytes

m,n,o,p,q,r,s,t=input()
q-=m
r-=n
a=o*q+p*r-s*q-t*r
a/=q*q+r*r
print o-a*q,p-a*r,s+a*q,t+a*r

Pruébalo en línea!

Versión modificada del enfoque de Neil.

Erik el Outgolfer
fuente
1

C (gcc) , 77 72 bytes

f(p,v,q,w,a)_Complex*a,p,v,q,w;{p-=q;p*=creal((v-w)/p);*a=v-p;a[1]=w+p;}

Pruébalo en línea!

Basado en la implementación de Python de @Joel

techo
fuente