Ce défi est basé sur la détection de collision réelle que j'ai dû écrire récemment pour un jeu simple.
Écrivez un programme ou une fonction qui, compte tenu de deux objets, renvoie une valeur vraie ou fausse selon que les deux objets sont en collision (c'est-à-dire se croisent) ou non.
Vous devez prendre en charge trois types d'objets:
- Segments de ligne : représentés par 4 flottants, indiquant les deux extrémités, à savoir (x 1 , y 1 ) et (x 2 , y 2 ) . Vous pouvez supposer que les points d'extrémité ne sont pas identiques (donc le segment de ligne n'est pas dégénéré).
- Disques : c'est-à-dire des cercles remplis, représentés par 3 flotteurs, deux pour le centre (x, y) et un (positif) pour le rayon r .
- Cavités : ce sont le complément d'un disque. C'est-à-dire qu'une cavité remplit tout l'espace 2D, à l' exception d' une région circulaire, spécifiée par un centre et un rayon.
Votre programme ou fonction recevra deux de ces objets sous la forme d'un entier identifiant (de votre choix) et leurs 3 ou 4 flottants. Vous pouvez prendre des entrées via STDIN, ARGV ou un argument de fonction. Vous pouvez représenter l'entrée sous n'importe quelle forme pratique qui n'est pas prétraitée, par exemple 8 à 10 nombres individuels, deux listes de valeurs séparées par des virgules ou deux listes. Le résultat peut être retourné ou écrit dans STDOUT.
Vous pouvez supposer que les objets sont séparés d' au moins 10 à 10 unités de longueur ou se croisent d'autant, vous n'avez donc pas à vous soucier des limitations des types à virgule flottante.
Il s'agit du code golf, donc la réponse la plus courte (en octets) l'emporte.
Cas de test
Représentant des segments de ligne avec 0
, des disques avec 1
et des cavités avec 2
, en utilisant un format d'entrée basé sur une liste, les éléments suivants devraient tous produire une sortie véridique:
[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
tandis que les éléments suivants devraient tous entraîner une sortie fausse
[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
la source
[0,[-2,0],[-1,0]], [0,[1,0],[2,0]]
Réponses:
APL,
279208206203Les sauts de ligne dans la fonction
f
sont pour plus de clarté. Ils doivent être remplacés par le séparateur d'instructions⋄
Cela fait si longtemps que je n'ai pas créé un programme APL aussi complexe. Je pense que la dernière fois ce mais je ne suis même pas sûr que c'était aussi complexe.
Format d'entrée
Fondamentalement identique à l'OP, sauf
0
pour la cavité, le1
disque et le2
segment de ligne.Mise à jour majeure
J'ai réussi à jouer beaucoup de caractères en utilisant un algorithme différent. Plus de
g
taureaux ** t !!La fonction principale
f
est divisée en cas:2 2≡x
: Segment-segmentDans ce cas, calculez le vecteur à partir des points d'extrémité de chaque ligne et résolvez un système d'équations linéaires pour vérifier si l'intersection est contenue dans les vecteurs.
Mises en garde:
Exemples: (Notez la mise en garde 1 en action sur la figure de droite)
2≡2⌷x
: Segment-autreDans ce cas, l'autre objet est circulaire. Vérifiez si les points d'extrémité du segment se trouvent dans le cercle à l'aide de la vérification de distance.
Dans le cas du disque, construisez également un segment de ligne de diamètre perpendiculaire au segment donné. Vérifiez si les segments entrent en collision par récursivité.
Dans le cas de la cavité, se faufiler dans un "temps 0" dans la construction dudit segment pour le faire dégénérer. (Voir pourquoi j'utilise
0
pour la cavité et1
pour le disque maintenant?) Comme le segment donné n'est pas dégénéré, la détection de collision segment-segment renvoie toujours false.Enfin, combinez les résultats des contrôles de distance et de la détection de collision. Pour le cas de la cavité, annulez d'abord les résultats des contrôles de distance. Ensuite (dans les deux cas) OU les 3 résultats ensemble.
Concernant les mises en garde segment-segment, le numéro 3 est adressé (et exploité). Le numéro 2 n'est pas un problème car nous croisons ici des segments perpendiculaires, qui ne sont jamais parallèles s'ils ne sont pas dégénérés. Le numéro 1 ne prend effet que dans le boîtier du disque, lorsque l'un des points d'extrémité donnés se trouve sur le diamètre construit. Si le point final est bien à l'intérieur du cercle, les vérifications de distance auraient pris soin de lui. Si le point final est sur le cercle, puisque le diamètre construit est parallèle au segment donné, ce dernier doit être tangent au cercle avec un seul point touchant le disque, ce qui n'est pas une entrée valide.
Exemples:
Cas par défaut: Autre-autre
Calculez la distance entre les centres. La collision disque-disque se produit si et seulement si la distance est inférieure à la somme des rayons. La collision disque-cavité se produit si et seulement si la distance est supérieure à la différence de rayons.
Pour prendre soin du cas cavité-cavité, annulez le résultat du contrôle de distance, ET avec chacun des entiers d'identification, puis OU ensemble. En utilisant une certaine logique, on peut montrer que ce processus retourne vrai si et seulement si les deux entiers identifiants sont faux (cas Cavité-cavité), ou si le contrôle de distance est retourné vrai
la source
Javascript - 393 octets
Minifié:
Étendu:
Remarques:
F
qui accepte les arguments requis et renvoie la valeur requiseF( 0,[[0,0],[2,2]], 0,[[1,0],[2,4]] )
ouF( 1,[[3,0],1], 2,[[0,0],1] )
.la source
Python, 284
J'utilise un algorithme assez ordonné par rapport à toutes ces astuces géométriques, mais il obtient les bonnes réponses même s'il faut plus d'une minute pour parcourir les cas de test. Le gros avantage est que je n'ai qu'à écrire les trois fonctions de notation, et l'escalade s'occupe de tous les cas de bord.
Golfé:
Non golfé:
Et enfin, un script de test au cas où quelqu'un d'autre voudrait essayer cela en python:
la source