Kaynağa Gözat

Tentatives d'amelioration des perf de la recherche de chemins
Coordonnees hexagonales tranformees en entiers (pour de meilleures perf)

Signed-off-by: unknown <olivier.massot@DSI5301067.cg67.fr>

unknown 10 yıl önce
ebeveyn
işleme
3047dbf3a0
7 değiştirilmiş dosya ile 140 ekleme ve 110 silme
  1. BIN
      doc/perfg_pathfinding.xls
  2. 99 81
      lib/AEtoile.py
  3. 14 17
      lib/Actions.py
  4. 8 2
      lib/Case.py
  5. 11 2
      lib/Pion.py
  6. 5 4
      lib/Plateau.py
  7. 3 4
      parties/Partie1/svg/infos_sauvegarde

BIN
doc/perfg_pathfinding.xls


+ 99 - 81
lib/AEtoile.py

@@ -3,95 +3,18 @@
 """algorithme de recherche du plus court chemin entre deux cases"""
 from math import *
 import time
+from threading import Thread
 
 #pour des performances correctes, ne pas utiliser pour de deplacements de plus de 100 cases
 
-
+        
 def distance(coord1, coord2):
     return sqrt((coord1[0] - coord2[0])**2 + (coord1[1] - coord2[1])**2)
 
 def distanceCarree(coord1, coord2):
     """bcp plus rapide a calculer que la distance reelle"""
     return (coord1[0] - coord2[0])**2 + (coord1[1] - coord2[1])**2
-
-def chemin(plateau, origine, cible):
-    """retourne la liste des coord a traverser pour atteindre l'objectif
-        se base sur la fonction estFranchissable() des cases"""
-    print "calcul chemin: {} -> {}".format(origine, cible)
-    nO = N(origine)
-    nO.parent = None
-    nO.coutG = 0
-    nO.cout = 0
-
-    filOuvert = []   #"liste ouverte": noeuds etudies et a etudier
-    filFerme = [nO]    #"liste fermee":  noeuds retenus
-    chemin = []
-    position = nO
-    echec = False
-    it = 0
-    
-    #on continue jusqu'a tomber sur la case cible, ou jusqu'a un echec
-    while position.coord != cible and not echec:
-        
-        #on etudie tous les voisins de la case en cours
-        for coord in plateau.cases[position.coord].voisins:
-            
-            #on elimine les cases deja retenues (celles qui sont dans le fil ferme)
-            trouve = False
-            for nTest in filFerme:
-                if nTest.coord == coord:
-                    trouve = True
-            if not trouve:
-                
-                #on elimine les cases infranchissables
-                if plateau.cases[coord].estFranchissable():
-                    noeud = N(coord)
-                    
-                    #on calcule le cout de la case
-                    noeud.creer(position, cible, plateau.cases[coord].coutDep())
-
-                    #si le noeud est trouve dans la liste ouverte, on le compare a celui-ci
-                    # si ce nouveau noeud a un cout moindre, on remplace
-                    # sinon on ajoute ce noeud a la liste ouverte
-                    trouve = False
-                    for nTest in filOuvert:
-                        if nTest.coord == noeud.coord:
-                            if noeud.cout < nTest.cout:
-                                nTest.parent = noeud.parent
-                                nTest.cout = noeud.cout
-                                trouve = True
-                                
-                    if not trouve:
-                        filOuvert.append(noeud)
-
-        #on parcourt les noeuds de la liste ouverte
-        #et on cherche le meilleur noeud (le cout le plus faible)
-        #si trouve: on l'ajoute a la liste fermee, on le retire de la liste ouverte et on continue
-        #sinon, le chemin n'existe pas
-        meilleur = None                
-                        
-        for noeud in filOuvert:
-            if meilleur == None:
-                meilleur = noeud
-            else:
-                if noeud.cout < meilleur.cout:
-                    meilleur = noeud
-                
-        if meilleur:
-            filFerme.append(meilleur)
-            filOuvert.remove(meilleur)
-            position = meilleur
-        else:
-            echec = True
-
-    #on revient de parent en parent jusqu'a l'arrivee
-    if not echec:
-        while position.coord != origine:
-            chemin.insert(0, position.coord)
-            position = position.parent
-            
-    return chemin                    
-                    
+       
 class N():
     """noeud du chemin"""
     def __init__(self, coord):
@@ -109,7 +32,102 @@ class N():
         self.coutG = self.parent.coutG + self.kDep
         self.cout =  (self.coutG)**2 + self.coutH
 
-
+class Chemin(Thread):
+    def __init__(self, plateau, origine, cible):
+        self.plateau = plateau
+        self.origine = origine
+        self.cible = cible
+        self.echec = False
+        self.stop = False
+
+    def arreter(self):
+        self.stop = True
+
+    def liste(self):
+        """retourne la liste des coord a traverser pour atteindre l'objectif
+           se base sur la fonction estFranchissable() des cases"""
+        Thread.__init__(self)
+        t0 = time.time()
+        nO = N(self.origine)
+        nO.parent = None
+        nO.coutG = 0
+        nO.cout = 0
+
+        filOuvert = []   #"liste ouverte": noeuds etudies et a etudier
+        filFerme = [nO]    #"liste fermee":  noeuds retenus
+        chemin = []
+        position = nO
+        echec = False
+        
+        #on continue jusqu'a tomber sur la case cible, ou jusqu'a un echec
+        while position.coord != self.cible and not self.echec:
+            
+            #on etudie tous les voisins de la case en cours
+            for coord in self.plateau.cases[position.coord].voisins:
+                if self.stop: return []
+                #on elimine les cases deja retenues (celles qui sont dans le fil ferme)
+                trouve = False
+                for nTest in filFerme:
+                    if self.stop: return []
+                    if nTest.coord == coord:
+                        trouve = True
+                if not trouve:
+                    
+                    #on elimine les cases infranchissables
+                    if self.plateau.cases[coord].estFranchissable():
+                        noeud = N(coord)
+                        
+                        #on calcule le cout de la case
+                        if self.stop: return []
+                        noeud.creer(position, self.cible, self.plateau.cases[coord].coutDep())
+
+                        #si le noeud est trouve dans la liste ouverte, on le compare a celui-ci
+                        # si ce nouveau noeud a un cout moindre, on remplace
+                        # sinon on ajoute ce noeud a la liste ouverte
+                        trouve = False
+                        for nTest in filOuvert:
+                            if self.stop: return []
+                            if nTest.coord == noeud.coord:
+                                if noeud.cout < nTest.cout:
+                                    nTest.parent = noeud.parent
+                                    nTest.cout = noeud.cout
+                                    trouve = True
+                                    
+                        if not trouve:
+                            filOuvert.append(noeud)
+
+            #on parcourt les noeuds de la liste ouverte
+            #et on cherche le meilleur noeud (le cout le plus faible)
+            #si trouve: on l'ajoute a la liste fermee, on le retire de la liste ouverte et on continue
+            #sinon, le chemin n'existe pas
+            meilleur = None                
+                            
+            for noeud in filOuvert:
+                if self.stop: return []
+                if meilleur == None:
+                    meilleur = noeud
+                else:
+                    if noeud.cout < meilleur.cout:
+                        meilleur = noeud
+                    
+            if meilleur:
+                filFerme.append(meilleur)
+                filOuvert.remove(meilleur)
+                position = meilleur
+            else:
+                echec = True
+
+        #on revient de parent en parent jusqu'a l'arrivee
+        if not self.echec:
+            while position.coord != self.origine:
+                if self.stop: return []
+                chemin.insert(0, position.coord)
+                position = position.parent
+        else:
+            chemin = []
+        print len(chemin), time.time() - t0
+        return chemin   
+    
 ### pour les tests
 
 ##class Plateau():

+ 14 - 17
lib/Actions.py

@@ -74,10 +74,18 @@ class Deplacement(Action):
     def __init__(self):
         super(Deplacement, self).__init__()
         self._chemin = []  #liste des coord des cases a traverser
+        self._chercheurChemin = None
         self._cout = 0     #cout en points de dep
+        self._t0 = 0       #date de la derniere maj, pour eviter l'accumulation de mises a jours lors du survol des cases
+
+    def desactiver(self):
+        if self._chercheurChemin:
+            self._chercheurChemin = None
+        super(Deplacement, self).desactiver()
 
     def valider(self):
         if self.estValide():
+            self.plateau.pionDeposer(self._coordCible)
             super(Deplacement, self).valider()
 
     def estValide(self):
@@ -89,14 +97,14 @@ class Deplacement(Action):
 
     def maj(self):
         self.afficherCibles(False)
-
         self._chemin = []
         self._cout = 0
+        if self._chercheurChemin:
+            self._chercheurChemin = None
 
-        a = threading.Thread(None, self.filPathFinding, None, (self._coordCible,), {}) 
-        a.start()
-        
-        self.afficherCibles(True)
+        self._chercheurChemin = AEtoile.Chemin(self.plateau, self.coordActeur(), self._coordCible)
+        self._chemin = self._chercheurChemin.liste()
+        self.afficherCibles(True)    
 
     def afficherCibles(self, actif):
         for coord in self._chemin:
@@ -106,18 +114,7 @@ class Deplacement(Action):
         cout = 0
         for coord in self._chemin:
             cout += self.plateau.cases[coord].coutDep()
-        print "{}  s'est deplacé et a utilisé {} points de mouvement".format(self.acteur().txtId(), cout)
-
-    def filPathFinding(self, coord):
-        """thread qui gere le petit delai d'attente que
-            l'on observe avant de calculer le chemin"""
-        time.sleep(0.2)
-        if self._coordCible == coord:
-            self._chemin = AEtoile.chemin(self.plateau, self.coordActeur(), self._coordCible)
-            self.afficherCibles(True)
-            
-        
-
+        print "{} s'est deplacé et a utilisé {} points de mouvement".format(self.acteur().txtId(), cout)
         
 
 

+ 8 - 2
lib/Case.py

@@ -76,7 +76,9 @@ class Case(QGraphicsPolygonItem):
    
         #enregistrement du centre
         if self.plateau.formeCases == "H":  #refPlateau
-            self.centreGraphique = QPointF(((self.x*0.866)+0.5773)*self.plateau.hCase, (self.y+0.5)*self.plateau.hCase)
+            k = 0
+            if 1 == (self.x % 2): k = 0.5
+            self.centreGraphique = QPointF(((self.x*0.866)+0.5773)*self.plateau.hCase, (self.y+k+0.5)*self.plateau.hCase)
         else:
             self.centreGraphique = QPointF((self.x+0.5)*self.plateau.hCase, (self.y+0.5)*self.plateau.hCase)
         
@@ -146,6 +148,10 @@ class Case(QGraphicsPolygonItem):
         """renvoie l'objet graphique hexagone de la case"""
         polygone = QPolygonF()
         if self.plateau.formeCases == "H":
+            #si x est impair sur un plateau a cases hexagonales, le y est augmente de 0.5
+            if 1 == (x % 2):
+                y += 0.5
+                
             polygone  << QPointF(((x*0.866)+0.2886)*self.plateau.hCase,  y*self.plateau.hCase) \
                       << QPointF(((x*0.866)+0.866)*self.plateau.hCase,   y*self.plateau.hCase) \
                       << QPointF(((x*0.866)+1.1547)*self.plateau.hCase, (y+0.5)*self.plateau.hCase) \
@@ -164,7 +170,7 @@ class Case(QGraphicsPolygonItem):
            seulement cases existantes sur le plateau / seulement cases adjacentes (cas des cases carrees)"""
         voisins = []
         if self.plateau.formeCases == "H":
-            lst = [(x, y-1), (x+1, y-0.5), (x+1, y+0.5), (x,  y+1), (x-1, y+0.5), (x-1, y-0.5)]         
+            lst = [(x, y-1), (x+1, y-1), (x+1, y), (x,  y+1), (x-1, y), (x-1, y-1)]
         else:
             lst = [(x, y-1), (x+1, y-1), (x+1, y), (x+1, y+1), (x,   y+1), (x-1, y+1), (x-1, y), (x-1, y-1)]
                   

+ 11 - 2
lib/Pion.py

@@ -63,6 +63,14 @@ class Pion(QGraphicsItem):
         """renvoie l'image a afficher dans les listes"""
         return self.logo
 
+    def yReel(self):
+        """renvoie le y reel (pour les contructions graphiques"""
+        if 1 == (self.position[0] % 2):
+             y = self.position[1] + 0.5
+        else:
+             y = self.position[1]
+        return y
+    
     ###attributs du pion
     def position(self):
         """retourne la position actuelle du pion"""
@@ -101,7 +109,8 @@ class Pion(QGraphicsItem):
         self.polygoneGraphique.setParentItem(self)
         self.polygoneGraphique.setPos(QPointF(0,0))
         if self.plateau.formeCases == "H":
-            self.polygoneGraphique.setTransformOriginPoint(QPointF(2*0.2886*self.plateau.hCase,0.5*self.plateau.hCase))
+            
+            self.polygoneGraphique.setTransformOriginPoint(QPointF(2*0.2886*self.plateau.hCase, 0.5*self.plateau.hCase))
         else:
             self.polygoneGraphique.setTransformOriginPoint(QPointF(0.5*self.plateau.hCase,0.5*self.plateau.hCase))
 
@@ -154,7 +163,7 @@ class Pion(QGraphicsItem):
             #on replace
             if self.plateau.formeCases == "H":
                 angleRotation = 60
-                positionGraphique = QPointF(self.position[0] * 0.866 * self.plateau.hCase, self.position[1] * self.plateau.hCase)
+                positionGraphique = QPointF(self.position[0] * 0.866 * self.plateau.hCase, self.yReel() * self.plateau.hCase)
             else:
                 angleRotation = 90
                 positionGraphique = QPointF(self.position[0] * self.plateau.hCase, self.position[1] * self.plateau.hCase)

+ 5 - 4
lib/Plateau.py

@@ -124,9 +124,9 @@ class Plateau(QGraphicsScene):
         #cree les cases hexagonales
         for x in range(nbCasesX):
             for y in range(nbCasesY):
-                if formeCases == "H":
-                     if 1 == (x % 2):
-                          y += 0.5
+##                if formeCases == "H":
+##                     if 1 == (x % 2):
+##                          y += 0.5
                 c = Case(self)
                 c.creer(x, y, couleur)
                 self.cases[(x,y)] = c
@@ -1226,6 +1226,7 @@ class Plateau(QGraphicsScene):
             for coord in listeCases:
                 polygone = case.polygone(coord[0], coord[1])
                 voisins =  self.lstCoordAdjacentes(coord[0], coord[1])
+                
                 for i in range(0, len(voisins)):
                     if not voisins[i] in listeCases:
                        j = i+1
@@ -1264,7 +1265,7 @@ class Plateau(QGraphicsScene):
         """renvoie la liste des coordonnees adjacentes, sans condition d'existence sur le plateau
            attention: l'ordre est important"""
         if self.formeCases == "H":
-            voisins = [(x, y-1), (x+1, y-0.5), (x+1, y+0.5), (x,  y+1), (x-1, y+0.5), (x-1, y-0.5)]         
+            voisins = [(x, y-1), (x+1, y-1), (x+1, y), (x,  y+1), (x-1, y), (x-1, y-1)]
         else:
             voisins = [(x, y-1), (x+1, y), (x,   y+1), (x-1, y)]
         return voisins                                        

+ 3 - 4
parties/Partie1/svg/infos_sauvegarde

@@ -1,5 +1,4 @@
-€}qU0}q(Unomqcsip
+€}qU0}q(Unomcsip
 _unpickle_type
-qUPyQt4.QtCoreqU
-QByteArrayUwxc…‡RqUdateCreationqGAÕ[:š-UdateSvgqGAÕ[Qu/Uchapitreq	U1UenCoursq
-‰Upublicq‰us.
+qUPyQt4.QtCoreqU
+QByteArrayUwxc…‡RqUdateCreationGAÕ[:š-UdateSvgGAÕ[Qu/UchapitreU1UenCours‰Upublic‰us.