Colisão de bolas de bilhar

24

Dadas as posições e velocidades bidimensionais de um par de bolas de bilhar logo antes do impacto, calcule suas velocidades após uma colisão perfeitamente elástica . As esferas são consideradas esferas ideais (ou equivalentemente: círculos) com o mesmo raio, mesma massa, densidade uniforme e sem atrito.

A entrada consiste em 8 números: p0x,p0y,v0x,v0y,p1x,p1y,v1x,v1yonde p0x,p0yé o centro da primeira bola, v0x,v0ysua velocidade e da mesma forma p1x,p1y,v1x,v1ypara a segunda bola. Você pode aceitar entrada em qualquer ordem e estruturado de qualquer maneira conveniente, por exemplo, como uma matriz 2x2x2, ou talvez uma matriz 2x2 para pe duas matrizes de comprimento-2 para v0e v1. Também é bom usar números complexos (se o seu idioma os suportar) em vez de pares xy. No entanto, você não deve receber entradas em um sistema de coordenadas diferente do cartesiano, ou seja, polar não é permitido.

Observe que o raio de uma bola de bilhar é metade da distância entre p0x,p0ye p1x,p1y, portanto, não é dado como uma parte explícita da entrada.

Escreva um programa ou função que produza ou retorne 4 números em qualquer representação cartesiana conveniente: os valores pós-colisão de v0x,v0y,v1x,v1y.

diagrama de colisão

Um possível algoritmo é:

  • encontre a linha normal que passa pelos dois centros

  • encontre a linha tangente que passa pelo ponto médio entre os dois centros e é perpendicular à linha normal

  • mudar o sistema de coordenadas e quebrar v0x,v0ye v1x,v1yem seus componentes tangencial e normal v0t,v0nev1t,v1n

  • trocar os componentes normais de v0e v1, preservando seus componentes tangenciais

  • voltar ao sistema de coordenadas original

Testes (resultados arredondados para 5 casas decimais):

   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]

Vitórias mais curtas. Sem brechas.


obrigado @Anush por ajudar a corrigir a cor de fundo do diagrama

ngn
fonte

Respostas:

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

Experimente online!

-1 byte graças a @ngn

-13 bytes graças a @Neil

Esta função frecebe quatro números complexos como entrada e retorna dois números complexos. A versão ungolfed é mostrada a seguir.

Ungolfed

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

Experimente online!

A fórmula de computação é derivada com base na fórmula de vetor 2D no wiki . Como m1=m2 , a fórmula pode ser simplificada para

{v1=v1dvv2=v2+dv

Vamos x12=x1x2 e v12=v1v2 , temos

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

No programa ungolfed, p12, v1 - v2, dcorrespondem aos x12 , y12 , e dv , respectivamente.

Joel
fonte
1
bem feito! essa abordagem parece diferente da resposta perl6 de Ramillies, que também usa números complexos. você pode salvar um byte se substituir r=p-qpor p-=qe continuar a usar em pvez de r, como na resposta js de Neil
ngn
1
@ngn, parece diferente, mas é o mesmo, como Joel observa corretamente. Eu escrevi a fórmula de uma forma que era boa para o golfe em Perl 6, e Joel presumivelmente usou uma que era melhor para o Python. De qualquer forma, não achei que mais alguém tivesse uma solução usando números complexos de forma independente. Bom trabalho!
Ramillies em
3
Bom, mas se você usasse o algoritmo na pergunta, levaria apenas 53 bytes ...
Neil
1
@ Neil Obrigado pela sua dica. O cálculo é bastante simplificado agora.
Joel
3
Estou gostando muito de todas as suas ótimas soluções e explicações detalhadas!
xnor 26/08
11

JavaScript (Node.js) , 90 88 bytes

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

Experimente online! O link inclui o conjunto de testes. Explicação: q,rsão redirecionados como o vetor de diferença entre os centros e ué o quadrado do seu comprimento. vé a diferença nos produtos de ponto de o,pe s,tcom q,r, assim v/ucomo o fator de escala q,rque fornece a quantidade de velocidade transferida de o,ppara s,t. Editar: salvou 2 bytes graças a @Arnauld.

Neil
fonte
eu não esperava que alguém simplificasse o algoritmo tão rapidamente, muito bem! aqui está uma visualização da sua solução (com a melhoria de Arnauld)
ngn
@ngn Link errado?
Neil
O log de dutos do @Neil gitlab diz que deveria estar lá. ctrl + f5? setas controlam a bola vermelha. mudança acelera. testado em firefox e cromo. aviso: som.
ngn
@ngn Ah, trabalhando agora, obrigado! (Eu já peguei um 404 antes. Além disso, eu estava usando uma guia particular, por isso não tinha som por padrão, embora não o achasse intrusivo. E sou inútil em Asteroids, caso contrário, pediria uma sessão de fotos "chave ...)
Neil
8

Perl 6 ,75 64 63. 61 bytes

11 bytes salvos mudando de mappara for, dispensando a necessidade de colocar as coisas em variáveis ​​intermediárias para o mapver.

1 byte salvo ao mudar ($^a-$^c)².&{$_/abs}para ($^a-$^c).&{$_/.conj}.

2 bytes salvos graças a @nwellnhof.

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

Experimente online!


Explicação

Quando o post original disse que a entrada poderia ser números complexos, era muito difícil resistir ... Portanto, são necessários 4 números complexos (posição 1, velocidade 1, posição 2, velocidade 2) e retornam as velocidades como números complexos.

d=p1p0

v0/dv1/dd

v0=d(v1d+iv0d),v1=d(v0d+iv1d)
v0=d(v1d+iv0d)=d[12(v1d+v1d)+12(v0dv0d)]= =d2(v0+v1dv0v1d)=12(v0+v1dd(v0v1)).
v1v0v1
v1=12[v0+v1+dd(v0v1)].

E é isso. Tudo o que o programa faz é apenas esse cálculo, um pouco de golfe.

Ramillies
fonte
muito legal!
ngn
Eu não sei muito sobre Perl, mas acho que você pode mesclar os dois cálculos conjugados em um para economizar alguns bytes.
Joel
1
@ Joel - Infelizmente, tenho certeza que não posso. O primeiro conjugado está atuando ($^a-$^c)(e somente dentro de um lambda que normaliza esse número), o segundo atua ($b-$d). Então eles não podem realmente ser reconciliados. Eu poderia criar uma função que chamaria apenas .conj, mas que adicionaria apenas bytes (porque eu uso muito a $_variável, que possui a propriedade nice, é possível chamar métodos nela sem especificá-la: em .conjvez de $_.conj).
Ramillies
@ Ramillies Obrigado pela explicação.
Joel
Como a magnitude de δ é relevante? Você está apenas dividindo por δ, trocando os componentes reais e depois multiplicando por δ novamente.
Neil
3

Gelatina , 16 bytes

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

Experimente online!

Um link diádico, tendo como argumento esquerdo uma lista das posições iniciais [[p0x, p0y], [p1x, p1y]]e seu argumento direito, as velocidades iniciais [[v0x, v0y], [v1x, v2y]]. Retorna uma lista das velocidades finais[[v0x', v0y'], [v1x', v2y']]

Com base no algoritmo usado pela resposta JavaScript de @ Neil, certifique-se de votar também nessa!

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

Experimente online!

Basicamente, uma porta da resposta JavaScript de @ Neil, mas o @ceilingcat reduzia 8 bytes reutilizando de maneira inteligente me narmazenando temporários.

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

Experimente online!

Versão modificada da abordagem de Neil.

Erik, o Outgolfer
fonte
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;}

Experimente online!

Com base na implementação python do @Joel

teto
fonte