Collision de boules de billard

24

Compte tenu des positions et des vitesses bidimensionnelles d'une paire de boules de billard juste avant l'impact, calculez leurs vitesses après une collision parfaitement élastique . Les boules sont supposées être des sphères idéales (ou de manière équivalente: des cercles) avec le même rayon, la même masse, une densité uniforme et sans frottement.

L'entrée se compose de 8 chiffres: p0x,p0y,v0x,v0y,p1x,p1y,v1x,v1yp0x,p0yest le centre de la première balle, v0x,v0ysa vitesse, et de même p1x,p1y,v1x,v1ypour la deuxième balle. Vous pouvez accepter des entrées dans n'importe quel ordre et structurées de n'importe quelle manière pratique, par exemple en tant que tableau 2x2x2, ou peut-être un tableau 2x2 pour pet deux tableaux de longueur 2 pour v0et v1. Il est également possible de prendre des nombres complexes (si votre langue les prend en charge) au lieu de paires xy. Cependant, vous ne devez pas prendre d'entrée dans un système de coordonnées autre que cartésien, c'est-à-dire que la polaire n'est pas autorisée.

Notez que le rayon d'une boule de billard est la moitié de la distance entre p0x,p0yet p1x,p1y, donc il n'est pas donné comme une partie explicite de l'entrée.

Écrivez un programme ou une fonction qui génère ou renvoie 4 nombres dans n'importe quelle représentation cartésienne pratique: les valeurs post-collision de v0x,v0y,v1x,v1y.

collision diagram

Un algorithme possible est:

  • trouver la ligne normale qui passe par les deux centres

  • trouver la ligne tangente qui passe par le milieu entre les deux centres et qui est perpendiculaire à la ligne normale

  • changer le système de coordonnées et décomposer v0x,v0yet v1x,v1yen leurs composants tangentiels et normaux v0t,v0netv1t,v1n

  • permuter les composants normaux de v0et v1, en préservant leurs composants tangentiels

  • revenir au système de coordonnées d'origine

Tests (résultats arrondis à 5 décimales):

   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]

Victoires les plus courtes. Pas de failles.


merci @Anush d'avoir aidé à corriger la couleur d'arrière-plan du diagramme

ngn
la source

Réponses:

16

Python 3 , 67 66 octets, 53 octets

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

Essayez-le en ligne!

-1 octet grâce à @ngn

-13 octets grâce à @Neil

Cette fonction f prend quatre nombres complexes en entrée et renvoie deux nombres complexes. La version non golfée est illustrée ci-dessous.

Non golfé

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

Essayez-le en ligne!

La formule de calcul est dérivée basée sur la formule du vecteur 2D sur wiki . Puisque m1=m2 , la formule peut être simplifiée en

{v1=v1dvv2=v2+dv

Soit x12=x1x2 et v12=v1v2 , nous avons

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

Dans le programme ungolfed, p12, v1 - v2, dcorrespondent à x12 , y12 , et dv , respectivement.

Joel
la source
1
bien joué! cette approche est différente de la réponse perl6 de Ramillies qui utilise également des nombres complexes. vous pouvez enregistrer un octet si vous remplacez r=p-qpar p-=qet utilisez davantage pau lieu de r, comme dans la réponse js de Neil
ngn
1
@ngn, ça a l'air différent mais c'est la même chose, comme Joel le note correctement. J'ai écrit la formule sous une forme qui était bonne pour le golf Perl 6, et Joel en a probablement utilisé une qui était meilleure pour Python. Quoi qu'il en soit, je ne pensais pas que quelqu'un d'autre trouverait une solution en utilisant des nombres complexes indépendamment. Bon travail!
Ramillies
3
Bien mais si vous
Neil
1
@Neil Merci pour votre conseil. Le calcul est maintenant grandement simplifié.
Joel
3
J'aime vraiment toutes vos excellentes solutions et explications détaillées!
xnor
11

JavaScript (Node.js) , 90 88 octets

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

Essayez-le en ligne! Le lien inclut une suite de tests. Explication: q,rsont réutilisés comme vecteur de différence entre les centres, et uest le carré de sa longueur. vest la différence entre les produits scalaires de o,pet s,tavec q,r, tout v/ucomme le facteur d'échelle pour q,rlequel donne la quantité de vitesse transférée de o,pà s,t. Edit: sauvé 2 octets grâce à @Arnauld.

Neil
la source
Je ne m'attendais pas à ce que quelqu'un simplifie l'algorithme si rapidement, bravo! voici une visualisation de votre solution (avec l'amélioration d'Arnauld)
ngn
@ngn Lien incorrect?
Neil
Le journal des pipelines de @Neil gitlab indique qu'il devrait être là. ctrl + f5? les flèches contrôlent la boule rouge. changement accélère. testé en firefox et chrome. avertissement: son.
ngn
@ngn Ah, je travaille maintenant, merci! (J'ai eu un 404 avant. De plus, j'utilisais un onglet privé, donc je n'avais pas de son par défaut, même si je ne le trouvais pas intrusif. Et je suis inutile chez Asteroids, sinon je demanderais un "shoot" "clé ...)
Neil
8

Perl 6 ,75 64 63 61 octets

11 octets économisés en passant de mapà for, dispensant de la nécessité de mettre les choses en variables intermédiaires pour les mapvoir.

1 octet enregistré en passant ($^a-$^c)².&{$_/abs}à ($^a-$^c).&{$_/.conj}.

2 octets enregistrés grâce à @nwellnhof.

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

Essayez-le en ligne!


Explication

Lorsque le message d'origine a dit que l'entrée pouvait être des nombres complexes, il était trop difficile de résister ... Cela prend donc 4 nombres complexes (position 1, vitesse 1, position 2, vitesse 2) et renvoie les vitesses sous forme de nombres complexes.

Le programme utilise exactement le même algorithme que celui décrit dans l'OP. Cependant, avec des nombres complexes, c'est assez simple. Tout d'abord, notons que le nombre complexe=p1-p0points de la première balle à la seconde. Donc, si nous divisons toutes les vitesses par elle, la direction normale coïncide soudainement avec l'axe réel et la direction tangente avec l'axe imaginaire. (Cela perturbe les grandeurs mais nous ne nous en soucions pas.)

Maintenant, nous devons changer les parties normales (c'est-à-dire réelles) des vitesses v0/ et v1/et après cela, multipliez-le par again to make the normal (and the velocities) point in the correct direction (and to unmess the magnitudes). So we need to calculate

v0=d(v1d+iv0d),v1=d(v0d+iv1d)
(where = real part, = imaginary part). Let's shuffle the first one a bit (using for complex conjugation):
v0=d(v1d+iv0d)=d[12(v1d+v1d)+12(v0dv0d)]= =d2(v0+v1dv0v1d)=12(v0+v1dd(v0v1)).
The result for v1 can be obtained just by switching v0v1. All that does is changing a sign:
v1=12[v0+v1+dd(v0v1)].

And that's it. All the program does is just this calculation, golfed a bit.

Ramillies
la source
very cool!­­­­­
ngn
I don't know much about Perl, but I think you could merge the two conjugate computations into one to save some bytes.
Joel
1
@Joel — Sadly, I'm pretty sure I can't. The first conjugate is acting on ($^a-$^c) (and only inside a lambda that normalizes this number), the second acts on ($b-$d). So they can't really be reconciled. I could make a function that would just call .conj, but that would only add bytes (because I heavily use the $_ variable, which has the nice property that you can call methods on it without specifying it: .conj instead of $_.conj).
Ramillies
@Ramillies Thanks for the explanation.
Joel
How is the δ's magnitude relevant? You're just dividing by δ, switching the real components, and then multiplying by δ again.
Neil
3

Jelly, 16 bytes

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

Try it online!

A dyadic link taking as its left argument a list of the initial positions [[p0x, p0y], [p1x, p1y]] and its right argument the initial velocities [[v0x, v0y], [v1x, v2y]]. Returns a list of the final velocities [[v0x', v0y'], [v1x', v2y']]

Based on the algorithm used by @Neil’s JavaScript answer so be sure to upvote that one too!

Nick Kennedy
la source
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;}

Try it online!

Basically a port of @Neil's JavaScript answer, but then @ceilingcat shaved off 8 bytes by cleverly reusing m and n to store temporaries.

G. Sliepen
la source
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

Try it online!

Modified version of Neil's approach.

Erik the Outgolfer
la source
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;}

Try it online!

Based on the python implementation of @Joel

ceilingcat
la source