simulationen
Deutsch   English   Français   

SIMULATIONS

 

 

SIMULATION D'UN ESSAIM

 

Le comportement collectif des animaux est un phénomène fréquent dans la nature. Les individus d'une population se comportent comme s'ils faisaient partie d'un ensemble plus vaste. Ce comportement présente plusieurs avantages, notamment une meilleure protection contre les prédateurs grâce à une vigilance collective, ainsi qu'une réduction de la dépense énergétique lors des déplacements. Dans notre exemple, nous simulons le déplacement d'une nuée d'oiseaux.

Dans ton programme, tu détermines les cellules voisines en sélectionnant, parmi les quatre cellules adjacentes, celles qui ne se trouvent ni sur un mur ni à l'extérieur de la grille. Un oiseau qui se déplace dans un groupe cherche, d'une part, à rester proche de ses voisins et, d'autre part, à éviter les collisions. Son comportement peut être décrit par les trois règles suivantes :

1. Séparation: Chaque Actor maintient une certaine distance par rapport à ses voisins afin d'éviter les collisions. Le vecteur d'accélération de l'Actor est dirigé dans le sens opposé au vecteur résultant de la somme des positions de ses voisins.

2. Alignement: L'objectif est d'adapter la vitesse et la direction de l'Actor à celles de ses voisins. Le vecteur vitesse de l'Actor est déterminé à partir de la moyenne des vecteurs vitesse de ses voisins.

3. Cohésion: L'objectif est de maintenir la cohésion du groupe et de permettre à chaque Actor de rester aussi proche que possible de ses voisins. Le vecteur d'accélération de l'Actor est dirigé vers le centre de masse commun de ses voisins.

Programme:

# Swarm.py
from gamegrid import *
import math
import random

class Tree(Actor):
    def __init__(self):
        Actor.__init__(self, "sprites/tree1.png")

class Bird(Actor):
    def __init__(self):
        Actor.__init__(self, True, "sprites/arrow1.png")
        self.r = GGVector(0, 0)  # Position
        self.v = GGVector(0, 0)  # Velocity
        self.a = GGVector(0, 0)  # Acceleration
 
    # Called when actor is added to gamegrid
    def reset(self):
        self.r.x=self.getX()
        self.r.y=self.getY()
        self.v.x=startVelocity*math.cos(math.radians(self.getDirection()))
        self.v.y=startVelocity*math.sin(math.radians(self.getDirection()))
  
    # ----------- cohesion ---------------
    def cohesion(self, distance):
        return self.getCenterOfMass(distance).sub(self.r)

    # ----------- alignment --------------
    def alignment(self, distance):
        align = self.getAverageVelocity(distance)
        align = align.sub(self.v)
        return align

    # ----------- separation -------------
    def separation(self, distance):
        repulse = GGVector()
        # ------ from birds ------
        for p in birdPositions:
            dist = p.sub(self.r)
            d = dist.magnitude()
            if d < distance and d != 0:
                repulse = repulse.add(dist.mult((d-distance)/d))

        # ------ from trees ------
        trees = self.gameGrid.getActors(Tree)
        for actor in trees:
            p = GGVector(actor.getX(), actor.getY())
            dist = p.sub(self.r)
            d = dist.magnitude()
            if d < distance and d != 0:
               repulse = repulse.add(dist.mult((d-distance)/d))
        return repulse
  
    # ----------- wall interaction -------
    def wallInteraction(self):
        width = self.gameGrid.getWidth()
        height = self.gameGrid.getHeight()
        acc = GGVector()
        if self.r.x < wallDist:
            distFactor = (wallDist - self.r.x) / wallDist
            acc = GGVector(wallWeight * distFactor, 0)
        if width - self.r.x < wallDist:
            distFactor = ((width - self.r.x)-wallDist)/wallDist
            acc = GGVector(wallWeight * distFactor, 0)
        if self.r.y < wallDist:
            distFactor = (wallDist - self.r.y) / wallDist
            acc = GGVector(0, wallWeight * distFactor)
        if height - self.r.y < wallDist:
            distFactor = ((height - self.r.y)-wallDist)/wallDist
            acc = GGVector(0, wallWeight * distFactor)
        return acc
  
    def getPosition(self):
        return self.r
      
    def getVelocity(self):
        return self.v

    def getCenterOfMass(self, distance):
        center = GGVector()
        sum = 0
        for p in birdPositions:
            dist = p.sub(self.r)
            d = dist.magnitude()
            if d < distance:
                center = center.add(p)
                sum += 1
        if sum != 0:        
            return center.mult(1.0/sum)
        else:
            return center

    def getAverageVelocity(self, distance):
        avg = GGVector()
        sum = 0
        for i in range(len(birdPositions)):
            p = birdPositions[i]
            if (self.r.x - p.x)*(self.r.x-p.x) + \
               (self.r.y - p.y)*(self.r.y-p.y)<distance*distance:
                avg = avg.add(birdVelocities[i]);
                sum += 1
        return avg.mult(1.0/sum)

    def limitSpeed(self):
        m = self.v.magnitude()
        if m < minSpeed:
            self.v = self.v.mult(minSpeed / m)
        if m > maxSpeed:
            self.v = self.v.mult(minSpeed / m)

    def setAcceleration(self):
        self.a = self.cohesion(cohDist).mult(cohWeight)
        self.a = self.a.add(self.separation(sepDist).mult(sepWeight))
        self.a = self.a.add(self.alignment(aligDist).mult(aligWeight))
        self.a = self.a.add(self.wallInteraction())

    def act(self):
        self.setAcceleration()
        self.v = self.v.add(self.a) # new velocity
        self.limitSpeed()
        self.r = self.r.add(self.v) # new position
        self.setDirection(int(math.degrees(self.v.getDirection())))
        self.setLocation(Location(int(self.r.x), int(self.r.y)))

# global section 
def populateTrees(number):
    blockSize = 70
    treesPerBlock = 10
    for block in range(number // treesPerBlock):
        x = getRandomNumber(800 // blockSize) * blockSize
        y = getRandomNumber(600 // blockSize) * blockSize
        for t in range(treesPerBlock):
            dx = getRandomNumber(blockSize)
            dy = getRandomNumber(blockSize)
            addActor(Tree(), Location(x + dx, y + dy))
                
def generateBirds(number):
    for i in range(number):
        addActorNoRefresh(Bird(), getRandomLocation(), 
                                  getRandomDirection())
    onAct()  # Initialize birdPositions, birdVelocities
     
def onAct():
    global birdPositions, birdVelocities
    # Update bird positions and velocities
    birdPositions = []
    birdVelocities = []
    for b in getActors(Bird):
        birdPositions.append(b.getPosition())
        birdVelocities.append(b.getVelocity())
 
def getRandomNumber(limit):
    return random.randint(0, limit-1)

# coupling constants 
cohDist = 100
cohWeight = 0.01
aligDist = 30
aligWeight = 1
sepDist = 30
sepWeight = 0.2
wallDist = 20
wallWeight = 2
maxSpeed = 20
minSpeed = 10
startVelocity = 10
numberTrees = 100
numberBirds = 50

birdPositions  = []
birdVelocities  = []

makeGameGrid(800, 600, 1, False)
registerAct(onAct)
setSimulationPeriod(10)
setBgColor(Color.blue)
setTitle("Swarm Simulation")
show()
populateTrees(numberTrees)
generateBirds(numberBirds)
doRun()
► Copy to clipboard

 

 

MACHINE À EXPRESSO

 

 

Dans la vie quotidienne, tu rencontres de nombreux appareils et machines qui peuvent être considérés comme des automates. Parmi ceux-ci figurent les distributeurs de boissons, les machines à laver, les distributeurs automatiques de billets, etc. En tant qu'ingénieur ou informaticien, tu conçois un tel automate en considérant qu'il passe progressivement d'un état actuel à un état suivant. Ce changement d'état dépend des données fournies par les capteurs ainsi que de l'utilisation des boutons et des interrupteurs.

 

Dans cet exemple, tu développes une machine à expresso qui possède trois états :

  • OFF : la machine est éteinte.
  • STANDBY : la machine est allumée et prête à fonctionner.
  • WORKING : la pompe à café est en marche.

Quatre boutons-poussoirs permettent de commander la machine : allumer (turnOn), éteindre (turnOff), mettre la pompe à café en marche (work) et arrêter la pompe à café (stop). Tu peux représenter le fonctionnement de la machine à café de manière plus claire à l'aide d'un diagramme d'états. Dans ce diagramme, les états sont représentés par des cercles et les transitions par des flèches, accompagnées des indications concernant les entrées et les sorties.

 

Programme:

#Espresso.py
from gamegrid import *

def pressEvent(e):
    global state
    loc = toLocationInGrid(e.getX(), e.getY())
    if loc == Location(1, 2): # off
        state = "OFF"
        led.show(0)
        coffee.hide()
    elif loc == Location(2, 2): # on
        if state == "OFF":
            state = "STANDBY"
            led.show(1)
    elif loc == Location(4, 2): # stop
        if state == "WORKING":
            state = "STANDBY"
            coffee.hide()
    elif loc == Location(5, 2): # work
        if state == "STANDBY":
            state = "WORKING"
            coffee.show()
    setTitle("State: " + str(state))
    refresh()
        
state = "OFF"
makeGameGrid(7, 11, 50, None, "sprites/espresso.png", False, 
             mousePressed = pressEvent)
show()
setTitle("State: " + str(state))
led = Actor("sprites/lightout.gif", 2)
addActor(led, Location(3, 3))
coffee = Actor("sprites/coffee.png")
addActor(coffee, Location(3, 6))
coffee.hide()
refresh()
► Copy to clipboard