Tabrakan bola bilyar

24

Mengingat posisi 2-dimensi dan kecepatan sepasang bola biliar tepat sebelum benturan, hitung kecepatannya setelah tumbukan elastis sempurna . Bola diasumsikan sebagai bola ideal (atau setara: lingkaran) dengan jari-jari yang sama, massa yang sama, kerapatan seragam, dan tidak ada gesekan.

Input terdiri dari 8 angka: di p0x,p0y,v0x,v0y,p1x,p1y,v1x,v1ymana p0x,p0yadalah pusat bola pertama, v0x,v0ykecepatannya, dan sama p1x,p1y,v1x,v1yuntuk bola kedua. Anda dapat menerima input dalam urutan apa pun dan terstruktur dengan cara apa pun yang mudah, misalnya sebagai array 2x2x2, atau mungkin array 2x2 untuk pdan dua array panjang-2 untuk v0dan v1. Tidak masalah untuk mengambil bilangan kompleks (jika bahasa Anda mendukungnya) alih-alih pasangan xy. Namun, Anda tidak boleh mengambil input dalam sistem koordinat selain dari Cartesian, yaitu kutub tidak diperbolehkan.

Perhatikan bahwa jari-jari bola biliar adalah setengah jarak antara p0x,p0ydan p1x,p1y, jadi itu tidak diberikan sebagai bagian eksplisit dari input.

Tulis sebuah program atau fungsi yang menghasilkan atau mengembalikan 4 angka dalam representasi Cartesian yang nyaman: nilai-nilai pasca-tabrakan v0x,v0y,v1x,v1y.

diagram tumbukan

Algoritma yang mungkin adalah:

  • temukan garis normal yang melewati kedua pusat

  • temukan garis singgung yang melewati titik tengah antara dua pusat dan tegak lurus terhadap garis normal

  • berubah sistem koordinat dan memecah v0x,v0ydan v1x,v1ymenjadi komponen-komponen tangensial dan normal mereka v0t,v0ndanv1t,v1n

  • menukar komponen normal v0dan v1, mempertahankan komponen tangensial mereka

  • ubah kembali ke sistem koordinat asli

Tes (hasil dibulatkan ke 5 tempat desimal):

   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]

Kemenangan terpendek. Tidak ada celah.


terima kasih @Anush untuk membantu memperbaiki warna latar belakang diagram

ngn
sumber

Jawaban:

16

Python 3 , 67 66 byte, 53 byte

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

Cobalah online!

-1 byte terima kasih kepada @ngn

-13 byte terima kasih kepada @Neil

Fungsi ini fmengambil empat bilangan kompleks sebagai input dan mengembalikan dua bilangan kompleks. Versi ungolfed ditampilkan sebagai berikut.

Tidak disatukan

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

Cobalah online!

Rumus perhitungan diturunkan berdasarkan rumus vektor-2D pada wiki . Karena m1=m2 , rumus ini dapat disederhanakan menjadi

{v1=v1dvv2=v2+dv

Misalkan x12=x1x2 dan v12=v1v2 , sudah

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

Dalam program ungolfed, p12, v1 - v2, dsesuai dengan x12 , y12 , dan dv , masing-masing.

Joel
sumber
1
sudah selesai dilakukan dengan baik! pendekatan ini terlihat berbeda dari jawaban perl6 Ramillies yang juga menggunakan bilangan kompleks. Anda bisa menghemat satu byte jika Anda mengganti r=p-qdengan p-=qdan menggunakan lebih lanjut palih-alih r, seperti dalam jawaban js Neil
ngn
1
@ ngn, terlihat berbeda tetapi sama, seperti dicatat Joel dengan benar. Saya menulis rumus dalam bentuk yang baik untuk golf Perl 6, dan Joel mungkin menggunakan formula yang lebih baik untuk Python. Bagaimanapun, saya tidak berpikir bahwa ada orang lain yang akan memberikan solusi menggunakan bilangan kompleks secara mandiri. Kerja bagus!
Ramillies
3
Bagus tetapi jika Anda menggunakan algoritma dalam pertanyaan itu hanya akan butuh 53 byte ...
Neil
1
@ Neil Terima kasih atas petunjuk Anda. Perhitungannya sangat disederhanakan sekarang.
Joel
3
Saya sangat menyukai semua solusi hebat dan penjelasan terperinci Anda!
xnor
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]

Cobalah online! Tautan termasuk test suite. Penjelasan: q,rdigunakan kembali sebagai vektor perbedaan antara pusat, dan umerupakan kuadrat dari panjangnya. vadalah perbedaan dalam produk titik dari o,pdan s,tdengan q,r, demikian v/ujuga faktor penskalaan untuk q,ryang memberikan jumlah kecepatan yang ditransfer dari o,pke s,t. Sunting: Disimpan 2 byte berkat @Arnauld.

Neil
sumber
Saya tidak berharap seseorang akan menyederhanakan algoritma dengan sangat cepat, bagus sekali! inilah visualisasi solusi Anda (dengan peningkatan Arnauld)
ngn
@ ngn Tautan salah?
Neil
Log pipa @Neil gitlab mengatakan seharusnya ada di sana. ctrl + f5? panah mengendalikan bola merah. Pergeseran mempercepat. diuji dalam firefox dan chromium. peringatan: suara.
ngn
@ ngn Ah, bekerja sekarang, terima kasih! (Saya mendapat 404 sebelumnya. Juga, saya menggunakan tab pribadi, jadi saya tidak memiliki suara secara default, meskipun saya tidak menganggapnya mengganggu. Dan saya tidak berguna di Asteroid, kalau tidak saya akan meminta pemotretan " "kunci ...)
Neil
8

Perl 6 ,75 64 63 61 byte

11 byte disimpan dengan beralih dari mapke for, menghilangkan kebutuhan untuk memasukkan hal-hal ke dalam variabel perantara untuk mapdilihat.

1 byte disimpan dengan mengubah ($^a-$^c)².&{$_/abs}ke ($^a-$^c).&{$_/.conj}.

2 byte disimpan berkat @nwellnhof.

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

Cobalah online!


Penjelasan

Ketika posting asli mengatakan bahwa input bisa berupa bilangan kompleks, terlalu sulit untuk menolak ... Jadi ini membutuhkan 4 bilangan kompleks (posisi 1, kecepatan 1, posisi 2, kecepatan 2) dan mengembalikan kecepatan sebagai bilangan kompleks.

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.

Ramillies
sumber
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
sumber
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
sumber
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
sumber
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
sumber