ビリヤードボールの衝突


24

衝突直前のビリヤードボールの2次元の位置と速度を考慮して、完全に弾性衝突した後の速度を計算します。ボールは、同じ半径、同じ質量、均一な密度、および摩擦のない理想的な球体(または同等:円)と見なされます。

入力は8個の数字から構成されています。p0x,p0y,v0x,v0y,p1x,p1y,v1x,v1yここで、p0x,p0y第1のボールの中心であり、v0x,v0yその速度、および同様にp1x,p1y,v1x,v1y第2のボールのために。入力を任意の順序で受け入れ、便利な方法で構造化できます。たとえば、2x2x2配列、またはpandの2x2配列とandの2つのlength-2配列v0などv1です。また、xyペアの代わりに複素数(言語でサポートされている場合)を使用しても問題ありません。ただし、デカルト座標以外の座標系では入力しないでください。つまり、極座標は使用できません。

ビリヤードボールの半径はp0x,p0yとの間の距離の半分であることに注意してください。そのp1x,p1yため、入力の明示的な部分としては与えられません。

便利なデカルト表現で4つの数値を出力または返すプログラムまたは関数を記述しますv0x,v0y,v1x,v1y。衝突後の値です。

衝突図

可能なアルゴリズムは次のとおりです。

  • 両方の中心を通る法線を見つける

  • 2つの中心の中間点を通り、法線に垂直な接線を見つける

  • 変更は、システムを調整し、打破v0x,v0yし、v1x,v1yその接線と通常の成分へv0t,v0nv1t,v1n

  • v0およびの法線成分を交換し、v1接線成分を保存します

  • 元の座標系に戻す

テスト(小数点以下5桁に丸められた結果):

   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]

最短勝。抜け穴はありません。


ダイアグラムの背景色の修正を支援してくれた@Anushに感謝

回答:


16

Pythonの367 66バイト、53のバイト

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

オンラインでお試しください!

@ngnのおかげで-1バイト

@Neilのおかげで-13バイト

この関数fは、4つの複素数を入力として受け取り、2つの複素数を返します。未使用のバージョンを以下に示します。

非ゴルフ

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

オンラインでお試しください!

計算式は、wikiの 2Dベクトル式に基づいて導出されます。以来、m1=m2、式を簡略化することができる

{v1=v1dvv2=v2+dv

ましょうx12=x1x2及びv12=v1v2、我々が持っています、

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

ungolfedプログラムにおいて、p12v1 - v2d対応するx12y12、及びdvはそれぞれ、。


1
よくやった!このアプローチは、複素数も使用するRamilliesのperl6の回答とは異なります。あなたが交換する場合は、バイトを救うことができるr=p-qp-=q、さらに使用pの代わりrのように、ニールのJS答え
NGN

1
@ngn、見た目は異なりますが、Joelが正しく指摘しているように同じです。Perl 6のゴルフに適した形式で式を作成しましたが、JoelはPythonに適した式を使用したと考えられます。とにかく、私は他のだれかが複素数を独立して使用する解決策を思い付くとは思わなかった。よくやった!
ラミリーズ

3
いいですが、質問でアルゴリズムを使用した場合、53バイトしかかかりません...
Neil

1
@Neilあなたのヒントをありがとう。計算が大幅に簡素化されました。
ジョエル

3
あなたの素晴らしい解決策と詳細な説明を本当に気に入っています!
xnor

11

JavaScript(Node.js)90 88バイト

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

オンラインでお試しください!リンクにはテストスイートが含まれます。説明:q,rは、中心間の差ベクトルとして再利用され、uその長さの2乗です。vドット積の差であるo,ps,tとは、q,rそう、v/uのスケーリングファクタであるq,rから転送速度の量与えることo,pにはs,t。編集:@Arnauldのおかげで2バイト保存されました。


誰かがそんなに早くアルゴリズムを単純化することを期待していませんでした。ここの可視化(アルノーの改善で)ソリューションの
NGN

@ngn間違ったリンク?
ニール

@Neil gitlabのパイプラインログには、それがあるはずだと書かれています。ctrl + f5?矢印は赤いボールを制御します。シフトが加速します。FirefoxおよびChromeでテスト済み。警告:音。
ngn

@ngnああ、今働いています、ありがとう!(前に404を取得しました。また、プライベートタブを使用していたため、デフォルトではサウンドがありませんでしたが、邪魔になりませんでした。また、Asteroidsでは役に立たないため、「シュート」を要求しました。 "キー...)
ニール

8

Perl 675 64 63 61バイト

からmapに切り替えることで11バイトが節約さforれ、map見るために中間変数に物を入れる必要がなくなります。

に変更($^a-$^c)².&{$_/abs}することで1バイト節約され($^a-$^c).&{$_/.conj}ます。

@nwellnhofのおかげで2バイト節約されました。

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

オンラインでお試しください!


説明

元の投稿が入力が複素数である可能性があると言ったとき、抵抗するのは難しすぎました...したがって、これは4つの複素数(位置1、速度1、位置2、速度2)を取り、速度を複素数として返します。

d=p1p0

v0/dv1/dd

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.


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!


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.




弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.