Esse desafio é baseado na detecção de colisão real que tive que escrever recentemente para um jogo simples.
Escreva um programa ou função que, dados dois objetos, retorne um valor verdadeiro ou falso, dependendo de os dois objetos estarem em colisão (ou seja, se cruzarem) ou não.
Você precisa suportar três tipos de objetos:
- Segmentos de linha : representados por 4 pontos flutuantes, indicando os dois pontos finais, ou seja (x 1 , y 1 ) e (x 2 , y 2 ) . Você pode assumir que os pontos de extremidade não são idênticos (portanto, o segmento de linha não é degenerado).
- Discos : ou seja, círculos preenchidos, representados por 3 flutuadores, dois para o centro (x, y) e um (positivo) para o raio r .
- Cavidades : são o complemento de um disco. Ou seja, uma cavidade preenche todo o espaço 2D, exceto uma região circular, especificada por um centro e raio.
Seu programa ou função receberá dois desses objetos na forma de um número inteiro de identificação (de sua escolha) e seus 3 ou 4 carros alegóricos. Você pode receber entradas via STDIN, ARGV ou argumento de função. Você pode representar a entrada de qualquer forma conveniente que não seja pré-processada, por exemplo, 8 a 10 números individuais, duas listas de valores separadas por vírgula ou duas listas. O resultado pode ser retornado ou gravado em STDOUT.
Você pode supor que os objetos estejam com pelo menos 10 a 10 unidades de comprimento ou se cruzam com isso, portanto, não precisa se preocupar com as limitações dos tipos de ponto flutuante.
Isso é código de golfe, então a resposta mais curta (em bytes) vence.
Casos de teste
Representando segmentos de linha com 0
, discos 1
e cavidades com 2
, usando um formato de entrada baseado em lista, todos os itens a seguir devem produzir uma saída verdadeira:
[0,[0,0],[2,2]], [0,[1,0],[2,4]] # Crossing line segments
[0,[0.5,0],[-0.5,0]], [1,[0,0],1] # Line contained in a disc
[0,[0.5,0],[1.5,0]], [1,[0,0],1] # Line partially within disc
[0,[-1.5,0.5],[1.5,0.5]], [1,[0,0],1] # Line cutting through disc
[0,[0.5,2],[-0.5,2]], [2,[0,0],1] # Line outside cavity
[0,[0.5,0],[1.5,0]], [2,[0,0],1] # Line partially outside cavity
[0,[-1.5,0.5],[1.5,0.5]], [2,[0,0],1] # Line cutting through cavity
[1,[0,0],1], [1,[0,0],2] # Disc contained within another
[1,[0,0],1.1], [1,[2,0],1.1] # Intersecting discs
[1,[3,0],1], [2,[0,0],1] # Disc outside cavity
[1,[1,0],0.1], [2,[0,0],1] # Disc partially outside cavity
[1,[0,0],2], [2,[0,0],1] # Disc encircling cavity
[2,[0,0],1], [2,[0,0],1] # Any two cavities intersect
[2,[-1,0],1], [2,[1,0],1] # Any two cavities intersect
enquanto o seguinte deve resultar em uma saída falsa
[0,[0,0],[1,0]], [0,[0,1],[1,1]] # Parallel lines
[0,[-2,0],[-1,0]], [0,[1,0],[2,0]] # Collinear non-overlapping lines
[0,[0,0],[2,0]], [0,[1,1],[1,2]] # Intersection outside one segment
[0,[0,0],[1,0]], [0,[2,1],[2,3]] # Intersection outside both segments
[0,[-1,2],[1,2]], [1,[0,0],1] # Line passes outside disc
[0,[2,0],[3,0]], [1,[0,0],1] # Circle lies outside segment
[0,[-0.5,0.5],[0.5,-0.5]], [2,[0,0],1] # Line inside cavity
[1,[-1,0],1], [1,[1,1],0.5] # Non-intersecting circles
[1,[0.5,0],0.1], [2,[0,0],1] # Circle contained within cavity
fonte
[0,[-2,0],[-1,0]], [0,[1,0],[2,0]]
Respostas:
APL,
279208206203Quebras de linha na função
f
são para maior clareza. Eles devem ser substituídos pelo separador de instruções⋄
Faz tanto tempo desde a última vez que criei um programa APL tão complexo. Acho que a última vez foi essa, mas nem tenho certeza se isso foi tão complexo.
Formato de entrada
Basicamente igual ao OP, exceto
0
para cavidade,1
disco e2
segmento de linha.Major update
Consegui jogar muitos caracteres usando um algoritmo diferente. Não há mais
g
touros ** t !!A função principal
f
é dividida em casos:2 2≡x
: Segmento-segmentoNesse caso, calcule o vetor a partir dos pontos finais de cada linha e resolva um sistema de equações lineares para verificar se a interseção está contida nos vetores.
Ressalvas:
Exemplos: (Observe a advertência 1 em ação na figura à direita)
2≡2⌷x
: Segmento-outroNesse caso, o outro objeto é circular. Verifique se os pontos finais do segmento estão dentro do círculo usando a verificação de distância.
No caso do disco, também construa um segmento de linha do diâmetro perpendicular ao segmento especificado. Verifique se os segmentos colidem por recursão.
No caso da cavidade, esgueirar-se "vezes 0" na construção do referido segmento para fazê-lo degenerar. (Veja por que eu uso agora
0
para cavidade e1
disco?) Como o segmento especificado não é degenerado, a detecção de colisão de segmento de segmento sempre retorna falso.Finalmente, combine os resultados das verificações de distância e a detecção de colisão. Para o caso de cavidade, negue primeiro os resultados das verificações de distância. Então (em ambos os casos) OU os 3 resultados juntos.
Em relação às advertências segmento a segmento, os números 3 são abordados (e explorados). O número 2 não é um problema, pois estamos cruzando segmentos perpendiculares aqui, que nunca são paralelos se não forem degenerados. O número 1 entra em vigor apenas na caixa do disco, quando um dos pontos finais especificados está no diâmetro construído. Se o ponto final estiver bem dentro do círculo, as verificações de distância teriam resolvido isso. Se o ponto final estiver no círculo, já que o diâmetro construído é paralelo ao segmento especificado, o último deve ser tangente ao círculo, com apenas um ponto tocando no disco, o que não é uma entrada válida.
Exemplos:
Caso padrão: Outro-outro
Calcule a distância entre os centros. A colisão de disco ocorre se, e somente se, a distância for menor que a soma dos raios. A colisão da cavidade do disco ocorre se, e somente se, a distância for maior que a diferença nos raios.
Para cuidar do caso cavidade-cavidade, negue o resultado da verificação da distância E com cada um dos números inteiros de identificação e, em seguida, com OU. Usando alguma lógica, pode-se mostrar que esse processo retorna verdadeiro se e somente se ambos os números inteiros de identificação forem falsos (caso Cavidade-cavidade) ou se a verificação de distância retornou verdadeiro
fonte
Javascript - 393 bytes
Minificado:
Expandido:
Notas:
F
que aceita os argumentos necessários e retorna o valor necessárioF( 0,[[0,0],[2,2]], 0,[[1,0],[2,4]] )
ouF( 1,[[3,0],1], 2,[[0,0],1] )
.fonte
Python, 284
Estou usando um algoritmo de lixo bastante comparado a todos esses truques geométricos, mas ele obtém as respostas certas, mesmo que demore mais de um minuto para passar pelos casos de teste. A grande vantagem é que eu só tenho que escrever as três funções de pontuação e a escalada cuida de todos os casos extremos.
Golfe:
Ungolfed:
E, finalmente, um script de teste, caso alguém queira tentar isso em python:
fonte