Les fourmis, suite et fin
J’ai enfin pris le temps de nettoyer le dernier code… Voilà donc l'article qui va avec, plutôt indigeste… Comme d’habitude, trois fichiers :
display.py
Rien qui change à part la façon de faire les rectangles, ainsi que la position du point de départ et la nourriture :
def populate(self, gridFood, startPos): """initialise la grille""" w = self.wsiz h = self.hsiz x = self.dimx y = self.dimy #on met le point de départ en rouge item = self.scene.addRect(startPos[0]*w/x, startPos[1]*h/y, w/x, h/y, self.pen, QtGui.QBrush(QtGui.QColor("red"))) #que l'on passe en avant item.setZValue(2) #on place de la même façon la nourriture, en vert for i in range(len(gridFood)): for j in range(len(gridFood[0])): if gridFood[i][j]: item = self.scene.addRect(i*w/x, j*h/y, w/x, h/y, self.pen, QtGui.QBrush(QtGui.QColor("green"))) item.setZValue(2)
ant.py
Le plus gros changement se fait chez les fourmis. Sur le chemin du retour, elles se « rappellent » de leur chemin, et évite de faire des boucles…
def shorten(lwloop): """ On enlève les boucles de la liste """ i = 0 while i < len(lwloop): item = lwloop[i] lwloop.reverse() last = len(lwloop) - (lwloop.index(item) + 1) lwloop.reverse() lwloop.__delslice__(i, last) i = i + 1
Pour se déplacer, si elles trouvent de la nourriture à côté d’elles, elles y vont. Une fois qu’elles l’ont, elles retournent au point de départ.
def move(self): """ Un pas, selon l'environnemnt. """ #Si a trouvé de la nourriture if self.parentGrid.gridFood[self.coord[0]][self.coord[1]]: #retour a la maison self.goHome = True #sans faire de boucle shorten(self.pathDone) #si sur le chemin du retour if self.goHome: #et qu'il reste du chemin if self.pathDone: self.lastCoord = self.coord self.coord = self.pathDone.pop() else: #sinon, on repart self.goHome = False
Sinon, elles errent, ou essayent plus ou moins de suivre un chemin de phéromones.
else: #si pas encore trouvé de nourritére directions = [(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)] gfood = self.parentGrid.gridFood food = [(gfood[(self.coord[0] + x) % self.parentGrid.xmax] [(self.coord[1] + y) % self.parentGrid.ymax], [(self.coord[0] + x) % self.parentGrid.xmax, (self.coord[1] + y) % self.parentGrid.ymax]) for (x, y) in directions] food.sort() #si de la nourriture juste a coté, on y va if (food[-1][0]): self.lastCoord = self.coord self.coord = food[-1][1] else: #sinon où sont les phéromones ? grid = self.parentGrid.gridPhero phero = [(grid[(self.coord[0] + x) % self.parentGrid.xmax] [(self.coord[1] + y) % self.parentGrid.ymax], [(self.coord[0] + x) % self.parentGrid.xmax, (self.coord[1] + y) % self.parentGrid.ymax]) for (x,y) in directions] actualPhero = [(i, j) for (i, j) in phero if (i!= 0)] lenAP = len(actualPhero) if lenAP > 0: #À 95%, on suit la plus forte phéromones if (randint(0,100) < 95): newCoord = actualPhero[randint(0,lenAP-1)][1] else: #sinon, on erre newCoord = phero[randint(0,7)][1] else: #s'il n'y a pas de phéromones à côté, on erre newCoord = phero[randint(0,7)][1] while newCoord == self.lastCoord: #mais on ne veut pas retourner sur nos pas! newCoord = phero[randint(0,7)][1] self.lastCoord = self.coord self.coord = newCoord self.pathDone += [self.coord[:]]
simu.py
Rien de bien différent si ce n’est la façon de générer les phéromones
#taux de phéromones qu'une fourmi pose self.pheroUp = 50 #taux d'évaporation des phéromones self.pheroDown = 0.1 self.dictPhero = {} # { taux : [liste de [x, y]]} self.gridPhero = [[0 for _ in range(self.ymax)] for _ in range(self.xmax)] #point de départ et nourriture self.gridFood = [[0 for _ in range(self.ymax)] for _ in range(self.xmax)] self.gridFood[10][10] = 1 startPos = [self.xmax/2, self.ymax/2] #no food on starting pos self.gridFood[startPos[0]][startPos[1]] = 0 #le widget central est notre affichage de la grille self.resize(self.wsize, self.hsize) self.centralWidget = GridDisplay(self.xmax, self.ymax, self.wsize, self.hsize) self.setCentralWidget(self.centralWidget) self.centralWidget.populate(self.gridFood, startPos)
Un dernier mot
Pour dire qu’au final, on a quelque chose qui tient vaguement la route. Si vous voulez rendre les fourmis plus intelligentes, c’est dans la fonction move
qu’il faut aller. Pour jouer avec les « 95% » et sur le fait que prendre un random, c’est pas terrible. Le mieux serait de choisir une direction et de garder ± le cap.
Faudrait aussi ajouter quelques p’tites choses comme des boutons pour arrêter, changer la vitesse, modifier les options (nombre de fourmis, taille, etc.), mais ça, vous êtes grand ;]
Oh, et pour les sources, direction bitbucket.
Figure 1: À table !!!