J'ai une grille de tuiles d'une taille finie connue qui forme une carte. Certaines tuiles à l'intérieur de la carte sont placées dans un ensemble appelé territoire. Ce territoire est connecté, mais on ne sait rien de sa forme. La plupart du temps, ce serait une goutte assez régulière, mais elle pourrait être très allongée dans une direction, et elle pourrait même avoir des trous. Je souhaite trouver la frontière (extérieure) du territoire.
Autrement dit, je veux une liste de toutes les tuiles qui touchent l'une des tuiles du territoire sans être elle-même sur le territoire. Quel est un moyen efficace de trouver cela?
Pour une difficulté supplémentaire, il arrive que mes tuiles soient des hexagones, mais je soupçonne que cela ne fait pas trop de différence, chaque tuile est toujours étiquetée avec une coordonnée entière x et y et, étant donné une tuile, je peux facilement trouver ses voisins. Voici quelques exemples: le noir est le territoire et le bleu la frontière que je veux trouver. En soi, ce n'est pas un problème difficile, Un algorithme simple pour cela, en pseudo-python, est:
def find_border_of_territory(territory):
border = []
for tile in territory:
for neighbor in tile.neighbors():
if neighbor not in territory and neighbor not in border:
border.add(neighbor)
Cependant, c'est lent et j'aimerais quelque chose de mieux. J'ai une boucle O (n) sur le territoire, une autre boucle (courte, mais quand même) sur tous les voisins, puis je dois vérifier l'appartenance sur deux listes, dont l'une est de taille n. Cela donne une échelle redoutable de O (n ^ 2). Je peux réduire cela à O (n) en utilisant des ensembles au lieu de listes pour la frontière et le territoire afin que l'adhésion soit rapide à vérifier, mais ce n'est toujours pas génial. Je m'attends à ce qu'il y ait de nombreux cas où le territoire est grand mais la frontière est petite en raison d'une simple mise à l'échelle zone vs ligne. Par exemple, si le territoire est un hex de rayon 5, il est de taille 91 mais la frontière n'est que de taille 36.
Quelqu'un peut-il proposer quelque chose de mieux?
Éditer:
Pour répondre à certaines des questions ci-dessous. Le territoire peut varier en taille, de 20 à 100 environ. L'ensemble de tuiles formant le territoire est un attribut d'un objet, et c'est cet objet qui a besoin d'un ensemble de toutes les tuiles de bordure.
Initialement, le territoire est créé comme un bloc, puis gagne principalement des tuiles une par une. Dans ce cas, il est vrai que le moyen le plus rapide consiste simplement à conserver un ensemble de bordure et à le mettre à jour uniquement sur la tuile obtenue. Parfois, un grand changement dans le territoire peut se produire - il devra donc être recalculé complètement à ce moment-là.
Je suis maintenant d'avis que faire un simple algorithme de recherche de frontière est la meilleure solution. La seule complexité supplémentaire que cela soulève est de garantir que la frontière est recalculée à chaque fois qu'elle devrait l'être, mais pas plus. Je suis assez confiant que cela peut être fait de manière fiable dans mon cadre actuel.
En ce qui concerne le timing, dans mon code actuel, j'ai quelques routines qui doivent vérifier chaque tuile du territoire. Pas à chaque tour, mais à la création et parfois après. Cela prend plus de 50% du temps de fonctionnement de ma combinaison de code de test, même si c'est une très petite partie du programme complet. Je tenais donc à minimiser les répétitions. CEPENDANT, le code de test implique beaucoup plus de création d'objets qu'une exécution normale du programme (naturellement), donc je me rends compte que cela pourrait ne pas être très pertinent.