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

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′=v1−dvv2′=v2+dv

Vamos x12=x1−x2 e v12=v1−v2 , temos

dv=⟨v12,x12⟩‖x12‖2x12=Re(v12⋅x12¯)x12⋅x12¯x12=Re(v12⋅x12¯x12⋅x12¯)x12=Re(v12x12)x12

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


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.


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=p1−p0

v0/dv1/dd

v0′=d(ℜv1d+iℑv0d),v1′=d(ℜv0d+iℑv1d)
ℜℑ⋆
v0′=d(ℜv1d+iℑv0d)=d[12(v1d+v1⋆d⋆)+12(v0d−v0⋆d⋆)]= =d2(v0+v1d−v0⋆−v1⋆d⋆)=12(v0+v1−dd⋆(v0⋆−v1⋆)).
v1′v0↔v1
v1′=12[v0+v1+dd⋆(v0⋆−v1⋆)].

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


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!


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.




Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.