Billardkugeln Kollision

24

Berechnen Sie anhand der zweidimensionalen Positionen und Geschwindigkeiten eines Billardkugelpaares unmittelbar vor dem Aufprall die Geschwindigkeiten nach einer perfekt elastischen Kollision . Es wird angenommen, dass die Kugeln ideale Kugeln (oder gleichwertige Kreise) mit dem gleichen Radius, der gleichen Masse, der gleichen Dichte und ohne Reibung sind.

Die Eingabe besteht aus 8 Zahlen: p0x,p0y,v0x,v0y,p1x,p1y,v1x,v1yWo p0x,p0yist der Mittelpunkt des ersten Balls, v0x,v0yseine Geschwindigkeit und in ähnlicher Weise p1x,p1y,v1x,v1yfür den zweiten Ball. Sie können Eingaben in beliebiger Reihenfolge und in beliebiger Weise strukturieren, z. B. als 2x2x2-Array oder als 2x2-Array für pund als zwei Arrays der Länge 2 für v0und v1. Es ist auch in Ordnung, komplexe Zahlen (sofern Ihre Sprache diese unterstützt) anstelle von xy-Paaren zu verwenden. Sie sollten jedoch keine Eingabe in einem anderen Koordinatensystem als kartesisch vornehmen, dh polar ist nicht zulässig.

Beachten Sie, dass der Radius einer Billardkugel die Hälfte des Abstands zwischen p0x,p0yund beträgt und p1x,p1ydaher nicht als expliziter Teil der Eingabe angegeben wird.

Schreiben Sie ein Programm oder eine Funktion, die 4 Zahlen in einer beliebigen geeigneten kartesischen Darstellung ausgibt oder zurückgibt: die Post-Collision-Werte von v0x,v0y,v1x,v1y.

Kollisionsdiagramm

Ein möglicher Algorithmus ist:

  • Finden Sie die normale Linie, die durch beide Zentren verläuft

  • Finden Sie die Tangente , die durch den Mittelpunkt zwischen den beiden Zentren verläuft und senkrecht zur Normalen verläuft

  • ändern Koordinatensystem und bricht v0x,v0yund v1x,v1yin ihre tangentialen und normalen Komponenten v0t,v0nundv1t,v1n

  • Vertauschen Sie die normalen Komponenten von v0und v1, wobei die tangentialen Komponenten erhalten bleiben

  • Wechseln Sie zurück zum ursprünglichen Koordinatensystem

Tests (Ergebnisse auf 5 Dezimalstellen gerundet):

   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]

Kürzeste Siege. Keine Lücken.


Vielen Dank an @Anush, dass Sie dabei helfen, die Hintergrundfarbe des Diagramms zu korrigieren

ngn
quelle

Antworten:

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

Probieren Sie es online!

-1 Byte danke an @ngn

-13 Bytes dank @Neil

Diese Funktion verwendet fvier komplexe Zahlen als Eingabe und gibt zwei komplexe Zahlen zurück. Die ungolfed Version wird im Folgenden gezeigt.

Ungolfed

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

Probieren Sie es online!

Die Berechnungsformel basiert auf der 2D-Vektorformel im Wiki . Da m1=m2 , kann die Formel vereinfacht werden zu

{v1=v1-dvv2=v2+dv

Lassen x12=x1-x2 und v12=v1-v2 , haben wir

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

Im ungolfed Programm p12, v1 - v2, dentsprechen x12 , y12 , und dv , respectively.

Joel
quelle
1
gut gemacht! Dieser Ansatz unterscheidet sich von der perl6-Antwort von Ramillies, bei der auch komplexe Zahlen verwendet werden. Sie könnten ein Byte speichern , wenn Sie ersetzen r=p-qmit p-=qund die weitere Verwendung pstatt r, wie in Neils js Antwort
ngn
1
@ngn, es sieht anders aus, ist aber dasselbe, wie Joel richtig bemerkt. Ich habe die Formel in einer Form geschrieben, die für das Golfen mit Perl 6 gut ist, und Joel hat vermutlich eine verwendet, die für Python besser ist. Jedenfalls hätte ich nicht gedacht, dass irgendjemand eine Lösung finden würde, bei der komplexe Zahlen unabhängig voneinander verwendet werden. Gut gemacht!
Ramillies
3
Schön, aber wenn Sie den Algorithmus in der Frage verwenden, würde es nur 53 Bytes dauern ...
Neil
1
@ Neil Danke für deinen Hinweis. Die Berechnung wird jetzt stark vereinfacht.
Joel
3
Ich freue mich sehr über all Ihre tollen Lösungen und detaillierten Erklärungen!
26.
11

JavaScript (Node.js) , 90 88 Byte

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

Probieren Sie es online! Link enthält Testsuite. Erläuterung: Sie q,rwerden als Differenzvektor zwischen den Mittelpunkten verwendet und usind das Quadrat seiner Länge. vist der Unterschied in den Punktprodukten von o,pund s,tmit q,r, so v/uist der Skalierungsfaktor dafür q,rder Betrag der Geschwindigkeit, die von o,pzu übertragen wird s,t. Bearbeiten: 2 Bytes dank @Arnauld gespeichert.

Neil
quelle
Ich hätte nicht gedacht, dass jemand den Algorithmus so schnell so stark vereinfachen würde. Gut gemacht! Hier ist eine Visualisierung Ihrer Lösung (mit Arnauld's Verbesserung)
25.
@ngn Falscher Link?
Neil
@ Neil Gitlab Pipelines-Protokoll sagt, es sollte da sein. Strg + F5? Pfeile steuern die rote Kugel. Schicht beschleunigt. getestet in Firefox und Chrom. Warnung: Ton.
25.
@ngn Ah, arbeite jetzt, danke! (Ich habe vorher eine 404 bekommen. Außerdem habe ich einen privaten Tab verwendet, daher hatte ich standardmäßig keinen Ton, obwohl ich ihn nicht als aufdringlich empfand. Und bei Asteroids bin ich nutzlos, sonst würde ich nach einem "Shooting" fragen "Schlüssel ...)
Neil
8

Perl 6 ,75 64 63 61 Bytes

Durch das Umschalten von mapauf werden 11 Bytes gespart for, ohne dass Dinge in Zwischenvariablen für die mapAnzeige gestellt werden müssen.

1 Byte gespeichert durch Änderung ($^a-$^c)².&{$_/abs}von ($^a-$^c).&{$_/.conj}.

2 Bytes gespart dank @nwellnhof.

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

Probieren Sie es online!


Erläuterung

Als der ursprüngliche Post sagte, dass es sich bei der Eingabe um komplexe Zahlen handeln könnte, war es zu schwierig, dem Widerstand zu widerstehen. Es werden also 4 komplexe Zahlen (Position 1, Geschwindigkeit 1, Position 2, Geschwindigkeit 2) verwendet und die Geschwindigkeiten werden als komplexe Zahlen zurückgegeben.

d=p1-p0

v0/dv1/dd

v0=d(v1d+ichv0d),v1=d(v0d+ichv1d)
v0=d(v1d+ichv0d)=d[12(v1d+v1d)+12(v0d-v0d)]= =d2(v0+v1d-v0-v1d)=12(v0+v1-dd(v0-v1)).
v1v0v1
v1=12[v0+v1+dd(v0-v1)].

Und das ist es. Alles, was das Programm macht, ist nur diese Berechnung, ein bisschen Golf.

Ramillies
quelle
sehr cool!
25.
Ich weiß nicht viel über Perl, aber ich denke, Sie könnten die beiden konjugierten Berechnungen zu einer zusammenführen, um einige Bytes zu sparen.
Joel
1
@ Joel - Leider bin ich mir ziemlich sicher, dass ich nicht kann. Das erste Konjugat wirkt auf ($^a-$^c)(und nur in einem Lambda, das diese Zahl normalisiert), das zweite wirkt auf ($b-$d). Sie können also nicht wirklich miteinander in Einklang gebracht werden. Ich könnte eine Funktion erstellen, die nur aufruft .conj, aber nur Bytes hinzufügt (weil ich die $_Variable stark verwende , die die nette Eigenschaft hat, dass Sie Methoden aufrufen können, ohne sie anzugeben: .conjstatt $_.conj).
Ramillies
@ Ramillies Danke für die Erklärung.
Joel
Wie ist die Größe von δ relevant? Sie dividieren einfach durch δ, tauschen die reellen Komponenten und multiplizieren dann erneut mit δ.
Neil
3

Gelee , 16 Bytes

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

Probieren Sie es online!

Ein dyadischer Link, der als linkes Argument eine Liste der Anfangspositionen [[p0x, p0y], [p1x, p1y]]und als rechtes Argument die Anfangsgeschwindigkeiten verwendet [[v0x, v0y], [v1x, v2y]]. Gibt eine Liste der Endgeschwindigkeiten zurück[[v0x', v0y'], [v1x', v2y']]

Basierend auf dem von @ Neils JavaScript-Antwort verwendeten Algorithmus , stimmen Sie auch diesem zu!

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

Probieren Sie es online!

Grundsätzlich ein Port von Neils JavaScript-Antwort, aber dann hat @ceilingcat 8 Bytes gespart, indem es Temporäre geschickt wiederverwendet mund ngespeichert hat.

G. Sliepen
quelle
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

Probieren Sie es online!

Modifizierte Version von Neils Ansatz.

Erik der Outgolfer
quelle
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;}

Probieren Sie es online!

Basiert auf der Python-Implementierung von @Joel

Ceilingcat
quelle