J'ai des robots dans une formation rectangulaire avec des rangées et des colonnes. Un problème survient lorsqu'un bot est ajouté ou retiré de la formation. Lorsque cela se produit, les bots doivent se réorganiser de sorte que la formation rectangulaire soit toujours à peu près le même rapport d'aspect, et soit aussi rectangulaire que possible. Comment faire ça?
Quelques idées:
Lorsqu'un bot est ajouté ou supprimé, utilisez le nouveau nombre total de bots et le rapport d'aspect constant souhaité pour calculer la nouvelle largeur et hauteur de la formation qui correspond le mieux à ce rapport d'aspect. Ensuite, remaniez en quelque sorte les robots pour les adapter aux nouvelles dimensions.
Lorsqu'un bot est retiré, déplacez le bot qui se trouvait derrière lui à sa place et continuez jusqu'à la fin de la formation. Ensuite, égalisez le rang arrière autant que possible en mélangeant en quelque sorte les robots dans le rang arrière.
Une autre idée complètement différente consiste à imiter la façon dont les structures des molécules restent ensemble. Faites en sorte que chaque robot veuille être entouré de quatre autres robots en attirant les quatre robots les plus proches et en repoussant les autres. Repoussez tous les robots (y compris les quatre) qui sont trop proches pour assurer la séparation en utilisant la loi du carré inverse. Vous auriez également besoin d'une force supplémentaire pour façonner la structure entière. Mais cela semble très coûteux en calcul.
MISE À JOUR : Donc, en regardant la réponse de sarahm, j'ai trouvé une bonne fonction générale qui donne de bonnes dimensions.
J'ai d'abord résolu l'équation simultanée ci-dessous pour la largeur et la hauteur, puis arrondi les réponses.
width/height=aspect ratio of your choice
width*height=number of bots
Cela vous donne le rectangle entier le plus proche de ce rapport d'aspect pour votre nombre de bots. Le rectangle le plus proche sera la moitié du temps trop grand, et la moitié du temps trop petit (bien sûr, parfois, ce sera juste, mais qui s'en soucie). Dans les cas où le rectangle est un peu trop grand, rien ne doit être fait. Le dernier rang finira par être presque plein, ce qui est idéal. Dans les cas où le rectangle est un peu trop petit, vous avez eu des problèmes parce que ce minuscule débordement devra aller à son propre rang, ce qui a créé un rang avec seulement quelques bots dessus, ce qui n'est pas joli. Il y a aussi des cas où la différence est grande(plus de la moitié de la largeur), auquel cas ajoutez ou soustrayez un rang pour réduire la différence. Ensuite, lorsque le rectangle est trop petit, ajoutez une colonne pour l'agrandir un peu. Après cela, il semble que le dernier rang aura toujours au moins la moitié du nombre de robots que les autres rangs.
MISE À JOUR
Une fois que vous avez obtenu les dimensions, comparez-les aux dimensions actuelles. Si la façade de la nouvelle dimension est plus grande, pour chaque rang, sortez les bots du rang inférieur et poussez-les sur le rang actuel jusqu'à ce que le nombre de bots de ce rang soit égal à la façade. Continuez cet algorithme jusqu'à ce que vous arriviez au dernier rang. En utilisant cet algorithme, les robots se déplaceront pour s'adapter efficacement à la nouvelle dimension. Après cela, je pousse simplement le nouvel ancien au dernier rang. L'algorithme est légèrement différent pour les cas où la nouvelle façade est plus petite, mais vous pouvez le comprendre!
Il y a deux autres problèmes ensuite. Suppression, et une méthode d'addition plus flexible où les nouveaux robots ne sont pas nécessairement affectés au rang arrière, mais quelle que soit la position qui leur est la plus proche au moment où ils sont ajoutés.
Réponses:
Une autre technique consiste à imiter celle utilisée par les bataillons napoléoniens (et probablement aussi loin que les phalanges grecques sinon plus loin).
La façade est généralement maintenue constante, et lorsqu'un homme tombe (dans n'importe quel rang sauf le dos), il est remplacé par l'homme directement derrière lui qui s'avance. Le rang arrière est mélangé par les sous-officiers pour assurer quelques hommes à l'extrême de chaque flanc, et sinon pour remplir également.
La façade n'est réduite que lorsque le rang arrière tombe en dessous des densités prédéfinies. De même, lorsque le rang arrière est saturé, les figurants commencent d'abord à remplir un rang supplémentaire à partir des deux flancs, puis la façade est augmentée.
Lorsque vous changez de façade, je suggère que vos bots se déplacent du rang arrière vers les deux flancs lors de l'augmentation de la façade et qu'ils soient limités des deux flancs au rang arrière lors de la réduction de la façade.
Si j'ai raison de déduire que vous recherchez une impression "militaire" et que vos organisations de robots ressemblent à des phalanges, je pense que ce réarrangement ordonné est un meilleur moyen d'atteindre cet objectif.
Mise à jour :
Une façon simple de gérer la rangée arrière est de diviser les unités de la rangée arrière en trois escouades: une sur chaque flanc et une au centre. Selon que la façade est impaire ou paire et que le nombre d'unités de rang arrière est congru à 0,1 ou 2 mod 3, il y a exactement six cas à gérer.
Pour améliorer ce qui précède, envisagez d'espacer la ou les dernières unités de chaque escouade de rang arrière une fois que le remplissage tombe en dessous d'un seuil, comme ceci:
xxx.x .... x.xxx.x .... x. xxx
ou ceci:
xx.xx..x.xxx.x ... xxxx
Un peu plus de travail, pour une apparence encore meilleure.
Mise à jour # 2 :
Une réflexion supplémentaire sur la profondeur de la formation. L'impact du feu de volée, combiné avec la baïonnette moderne, a rendu les profondeurs de 3 ou 4 adéquates à la fin du 18e et au début du 19e siècle. (Les Britanniques ont rarement combattu dans 2 rangs, contrairement à la croyance populaire, jusqu'à la fin d'une bataille; d'une part, cela a rendu leurs lignes trop longues pour former rapidement des carrés.) Avant cela, il était courant d'avoir des profondeurs plus grandes, peut-être jusqu'à 8 ou 10 pour une phalange grecque équipée de Sarissa. Choisissez une profondeur qui crée l'impression que vous désirez.
Dans la vraie vie, les armées essaient de maintenir la façade des unités aussi longtemps que possible, au détriment de la fragilité accrue des unités, car cela simplifie la configuration d'un champ de bataille. César à Pharsale a délibérément réduit la profondeur de son unité pour augmenter la façade pour correspondre à celle des forces de Pompée. Comme le dit la citation: "Nous gagnons ou mourons aujourd'hui; les hommes de Pompey ont d'autres choix." (ce que César avait astucieusement et soigneusement assuré, bien sûr).
la source
En supposant qu'une unité est une structure de données linéaire (par exemple une liste ) de robots.
Tout d'abord, vous devez ajouter / supprimer le bot à / de la structure de données et déterminer le nouveau nombre de bots dans l'unité.
Ensuite, vous devez déterminer la nouvelle quantité de lignes et de colonnes à l'aide de https://en.wikipedia.org/wiki/Integer_factorization .
Bien sûr, cela n'est pas toujours possible en raison des nombres premiers . Lorsque la nouvelle taille d'unité est un nombre premier, vous devez utiliser la prochaine taille d'unité plus grande qui ne l'est pas.
Ensuite, il suffit d'itérer sur la structure de données, en affectant des bots dans l'ordre aux lignes et aux colonnes.
Pour placer les bots, il suffit d'itérer sur la structure de données, en attribuant à chaque bot une position décalée par rapport à la position des unités d'une quantité déterminée par la ligne et la colonne dans lesquelles se trouve le bot (ou, définissez ce point comme cible pour le mouvement des bots).
Pour faire une unité avec le centre dans un coin , la position d'un bot est donnée par
unitPosition + cap * columnNumber * botSeparationDistance + rightVector * rowNumber * botSeparationDistance
Pour faire une unité avec le centre au milieu , la position d'un bot est donnée par
unitPosition + n * (* columnNumber unitSeparationDistance - 0,5 * (* numberOfColumns botSeparationDistance) + rightVector * * rowNumber botSeparationDistance - 0,5 * (* numberOfRows botSeparationDistance)
où cap est un vecteur pointant dans la direction à laquelle l'unité fait face et droiteVecteur est un vecteur orthogonal au cap .
botSeparationDistance peut être modifié pour éloigner ou rapprocher les robots.
Si vous êtes de fantaisie de sentiment, vous pouvez compenser la dernière rangée de bots par rightVector * 0,5 * (numberOfColumns - actualNumberOfBotsInRow) pour centrer les sur la formation .
la source
Je stockerais les positions possibles dans un graphique avec des valeurs plus grandes étant des rectangles plus petits.
Chaque fois qu'un robot est supprimé, recherchez parmi tous les autres robots et trouvez celui dans un nœud avec la plus petite valeur. Utilisez A * ou un algorithme BST pour lui trouver un chemin de la plus petite valeur à l'espace vacant. S'il n'y a pas de robot avec une valeur inférieure à celle retirée, ne faites rien.
Vous devriez également pouvoir contrôler la façon dont le rectangle se désintègre. Par exemple, dans le graphique ci-dessous, lorsqu'un robot quitte le bas par le côté viendrait remplir sa place.
Ici, celui de 3,8 est supprimé afin que celui de 2,5 arrive et remplisse sa place.
Un autre exemple. Ici, 2.8 est supprimé pour que le plus petit nœud 2.2 vienne à sa place.
Vous voulez probablement un anneau de nœuds avec une valeur 0 que vous ne remplissez jamais autour de l'extérieur pour que votre algorithme de recherche de chemin trouve le trou avec.
Un bon tutoriel sur A * peut être trouvé ici .
la source