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.

simu4_manger.png

Figure 1: À table !!!

Autres billets

Date: <2013-05-19>

Generated by Emacs 24.3.1 (Org mode 8.2.4) - Show Org source (htmlized)

CSS inspired by Tontof, colors by Chaotic Soul

Validate