撞球撞


24

给定一对撞球在撞击前的二维位置和速度,计算出完全弹性碰撞后的速度。假定这些球是具有相同半径,相同质量,均匀密度且无摩擦的理想球体(或等效地:圆形)。

输入由8个数字:p0x,p0y,v0x,v0y,p1x,p1y,v1x,v1y其中p0x,p0y是所述第一球,中心v0x,v0y其速度,并且类似地p1x,p1y,v1x,v1y,第二球。可以接受以任何顺序输入,并且在任何方便的方式结构化,例如,作为一个2x2x2的阵列,或者一个2×2阵列p和两个长度为2的数组为v0v1。也可以使用复数(如果您的语言支持)而不是xy对。但是,您不应在非直角坐标系的坐标系中进行输入,即不允许使用极坐标。

请注意,撞球的半径是p0x,p0y和之间的距离的一半p1x,p1y,因此并未将其作为输入的明确部分给出。

编写一个程序或函数,以任何方便的笛卡尔表示形式输出或返回4个数字:的碰撞后值v0x,v0y,v1x,v1y

碰撞图

可能的算法是:

  • 找到穿过两个中心的法线

  • 找到穿过两个中心之间的中点并垂直于法线的切线

  • 改变坐标系和分解v0x,v0y,并v1x,v1y纳入其切线和正常组件v0t,v0nv1t,v1n

  • 交换的正常组成部分v0v1,维护他们的切向分量

  • 改回原始坐标系

测试(结果四舍五入到小数点后五位):

   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 帮助修复图表的背景色

Answers:


16

Python 3中67 66个字节,53个字节

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

在线尝试!

-1个字节感谢@ngn

-13字节感谢@Neil

此函数f将四个复数作为输入并返回两个复数。非高尔夫版本如下所示。

不打高尔夫球

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

在线尝试!

计算公式是基于Wiki上的2D矢量公式得出的。由于1个=2,公式可以被简化为

{v1个=v1个-dvv2=v2+dv

X12=X1个-X2v12=v1个-v2,我们有

dv=v12X12X122X12=[RËv12X12¯X12X12¯X12=[RËv12X12¯X12X12¯X12=[RËv12X12X12

在ungolfed程序,p12v1 - v2d对应于X12ÿ12,和dv,分别。


1
做得好!这种方法看起来与Ramillies的perl6答案不同,后者也使用复数。您可以保存一个字节,如果您将其替换r=p-qp-=q并进一步p代替使用r,例如Neil的js答案
ngn

1
@ngn,它看起来有所不同,但相同,正如Joel正确指出的那样。我以对Perl 6打高尔夫球有用的形式编写了公式,而Joel大概使用了对Python更好的公式。无论如何,我不认为其他人会想出一个独立使用复数的解决方案。做得好!
Ramillies

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是其长度的平方。v在的点积的差异o,ps,tq,r,因此v/u是缩放因子用于q,r给出速度的从转移量o,ps,t。编辑:由于@Arnauld,节省了2个字节。


我没想到有人会这么快,做得好简化算法!这是您的解决方案的可视化(经过Arnauld的改进)
ngn

@ngn错误的链接?
尼尔

@Neil gitlab的管道日志说应该在那儿。Ctrl + F5?箭头控制红球。转变加速。经过Firefox和铬测试。警告:声音。
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=p1个-p0

v0/dv1个/dd

v0=dv1个d+一世v0dv1个=dv0d+一世v1个d
v0=dv1个d+一世v0d=d[1个2v1个d+v1个d+1个2v0d-v0d]= =d2v0+v1个d-v0-v1个d=1个2v0+v1个-ddv0-v1个
v1个v0v1个
v1个=1个2[v0+v1个+ddv0-v1个]

就是这样。该程序所做的只是该计算,有些打高尔夫球。


很酷!
ngn

我对Perl不太了解,但是我认为您可以将两个共轭计算合并为一个以节省一些字节。
乔尔

1
@Joel-可悲的是,我敢肯定我不会。第一个共轭作用于($^a-$^c)(并且仅在标准化该数字的lambda内部)作用,第二个共轭作用于($b-$d)。因此,他们根本无法和解。我可以制作一个只会调用的函数.conj,但是只会增加字节(因为我大量使用了该$_变量,该变量具有不错的属性,您可以在不指定该变量的情况下调用方法:.conj而不是$_.conj)。
Ramillies

@Ramillies感谢您的解释。
乔尔

δ的大小如何相关?您只需将其除以δ,切换实分量,然后再次乘以δ。
尼尔

3

果冻,16字节

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

在线尝试!

双向链接,以初始位置列表作为左变量[[p0x, p0y], [p1x, p1y]],右初始速度作为右变量[[v0x, v0y], [v1x, v2y]]。返回最终速度的列表[[v0x', v0y'], [v1x', v2y']]

基于@Neil JavaScript答案使用的算法,因此请确保也支持该算法!


3

C(GCC) 140个 132字节

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;}

在线尝试!

基本上是@Neil的JavaScript答案的端口,但是@ceilingcat通过巧妙地重用mn存储临时对象而减少了8个字节。




By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.