Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
ackland_1_8.py 23.58 KiB
from graphics import *
import time
import random
import math
import csv

#-----global variables--------------------
visual = True
winWidth = 700
winHeight = 700

if visual:
    window = GraphWin("Window", winWidth, winHeight)
else:
    window = None

maxTime = 10000

agentNum = 80
predNum = 8#agentNum/10
generations = 100

foodCluster = 16
clusterSize = 8
clusterradius = 20

# choose simulation type
isFood = False
isPred = True
Both = False

t = 0.1

rr = 5

# area an agent can see
As = 5000 * (rr**2)
Am = 5 * (rr**2) * t

#mutate values
m_zoo_r = 5/2.0
m_zoa_r = 10/2.0
m_speed = 0.1/2.0
m_food = 0.1/2.0
m_pred = 0.1/2.0
m_noise = 0.05/2.0

#-----Agent class--------------------

class Agent:
    def __init__(self, point, window ):
            self.color = color_rgb(0,0,0)

            self.point = point
            self.window = window
            self.Velocity_x = 1
            self.Velocity_y = 1
            self.tempV = [0,0]

            self.line = Line(self.point, Point(self.point.getX() + self.Velocity_x, self.point.getY()+self.Velocity_y))

            #evolvable
            self.speed = 4
            self.zor_r = 5#fix
            self.zoo_r = 20
            self.zoa_r = 200

            self.attCircle = Circle(self.point, self.zoa_r)

            self.blind_angle = 30
            self.turn_angle = 50

            self.food_pref = 5
            self.anti_pred = 0
            self.foodlevel = 0
            self.noise = 2

    def drawLine(self):
        self.line.undraw()
        self.line = Line(self.point, Point(self.point.getX() + self.Velocity_x, self.point.getY()+self.Velocity_y))
        self.line.setArrow("last")
        self.line.setFill(self.color)
        self.line.draw(self.window)

    def create_random_agent(self):
        self.Velocity_x = random.uniform(-1, 1)
        self.Velocity_y = random.uniform(-1, 1)

        self.zor_r = rr
        self.zoa_r = random.uniform( math.sqrt(As/(2*math.pi)), 1.5*math.sqrt(As/(2*math.pi)) )
        self.zoo_r = random.uniform(rr, self.zoa_r)

        self.speed = random.uniform(1, 5)
        self.blind_angle = (360 - math.degrees(As/(self.zoa_r**2)) ) / 2
        self.turn_angle = math.degrees(Am/(2*(self.speed**2)))

        self.food_pref = random.uniform(0,5)
        self.anti_pred = random.uniform(0,5)

        self.noise = random.uniform(0,1)

        r = random.randrange(256)
        g = random.randrange(256)
        b = random.randrange(256)

        return self
        #agent.color = color_rgb(r,g,b)

"""
        self.attCircle.undraw()
        self.attCircle = Circle(self.point, self.zoa_r)
        self.attCircle.setOutline("black")
        self.attCircle.draw(self.window)
"""
#-----Predator class--------------------

class Predator:

    def __init__(self, point, window ):
        self.color = "red"
        self.point = point
        self.window = window
        self.Velocity_x = 1
        self.Velocity_y = 1
        self.tempV = [0,0]

        self.line = Line(self.point, Point(self.point.getX() + self.Velocity_x, self.point.getY()+self.Velocity_y))

        #evolvable
        self.speed = 5.5

        self.zor_r = 10#fix
        #self.zoo_r = 20
        self.zoa_r = 200

        self.attCircle = Circle(self.point, self.zoa_r)

        self.blind_angle = 135
        self.turn_angle = 50

        #self.food_pref = 5
        #self.anti_pred = 0
        #self.foodlevel = 0
        self.noise = 2
        self.hasEaten = False
        self.lifeTime = 0

    def drawLine(self):
        self.line.undraw()
        self.line = Line(self.point, Point(self.point.getX() + self.Velocity_x, self.point.getY()+self.Velocity_y))
        self.line.setArrow("last")
        self.line.setFill(self.color)
        self.line.draw(self.window)

    def create_random_predator(self):
        self.Velocity_x = random.uniform(-1, 1)
        self.Velocity_y = random.uniform(-1, 1)

        self.zor_r = rr
        view_angle = 360-(self.blind_angle*2)
        self.zoa_r = 20*math.sqrt(As/view_angle)
        #self.blind_angle = (360 - math.degrees(As/(self.zoa_r**2)) ) / 2
        #self.turn_angle = math.degrees(1.5*Am/(2*(self.speed**2)))
        self.turn_angle = 140

        return(self)


#-----Food class--------------------

class Food:
    def __init__(self, Point):
            self.point = Point

def generate_food(widthTemp, heightTemp):
    foods = []
    for j in range (foodCluster):
        x = random.uniform(widthTemp + clusterradius, winWidth-clusterradius)
        y = random.uniform(heightTemp + clusterradius, winHeight- clusterradius)
        for k in range (clusterSize):
            xk = random.uniform(x - clusterradius, x + clusterradius)
            yk = random.uniform(y - clusterradius, y + clusterradius)
            f = Food(Point(xk, yk))
            if visual:
                f.point.setFill("blue")
                f.point.draw(window)
            foods.append(f)
    return foods

#-----help functions--------------------


# Distance function betwen points xi, yi and xii,yii
def distance(xi,xii,yi,yii):
    sq1 = (xi-xii)*(xi-xii)
    sq2 = (yi-yii)*(yi-yii)
    return math.sqrt(sq1 + sq2)

# absolute value of a vector (a,b)
def absvec(a, b):
    m = math.sqrt(a*a + b*b)
    if m == 0: m = 0.001
    return m

# angle between two direction vectors
def calc_angle(x1, y1, x2, y2):
        skalar = x1*x2 + y1*y2
        abs1 = absvec(x1, y1)
        abs2 = absvec(x2, y2)

        erg = skalar/(abs1* abs2)
        if erg > 1:
            #print erg
            erg=1

        elif erg < -1:
            #print erg
            erg=-1
        return math.degrees(math.acos(erg))

# returns nearest neighbour of a in aas
def nearest_neighbour(a,aas):

    minDis = float('inf')
    nn = None

    for b in aas:

        disVecX = b.point.getX() - a.point.getX()
        disVecY = b.point.getY() - a.point.getY()
        alpha = calc_angle(a.Velocity_x,a.Velocity_y, disVecX, disVecY)

        if (a == b):
            True
        elif alpha < 180 - a.blind_angle and alpha > 180 + a.blind_angle:
            True
        elif (nn == None):
            nn = b
        else:
            dis = distance(a.point.getX(),b.point.getX(), a.point.getY(), b.point.getY())
            if(dis < minDis):
                minDis = dis
                nn = b
    return nn


#-----couzin movement--------------------

# returns three lists, one for each zone,
# contaning all other agents in the zone.
# ignores all agents in the angle behind the current agent defined by blind.
def neigbour_in_zones(a, aas):
    zor = []
    zoo = []
    zoa = []

    for agent in aas:
        disVecX = agent.point.getX() - a.point.getX()
        disVecY = agent.point.getY() - a.point.getY()
        alpha = calc_angle(a.Velocity_x, a.Velocity_y, disVecX, disVecY)

        if (a == agent):
            True
        elif alpha < 180 - a.blind_angle and alpha > 180 + a.blind_angle:
            True
        else:
            dis = absvec(agent.point.getX() - a.point.getX() , agent.point.getY() - a.point.getY() )
            if dis <= a.zor_r:
                zor.append(agent)
            elif dis <= a.zoo_r:
                zoo.append(agent)
            elif dis <= a.zoa_r:
                zoa.append(agent)

    #print len(zoo)+len(zor)+len(zoa)
    return [zor, zoo, zoa]

#update Velocity a la couzin
def updateV_couzin(a, matrix):

    dx=0
    dy=0

    #zor
    if matrix[0] != []:
        for agent in matrix[0]:
            disX = agent.point.getX() - a.point.getX()
            disY = agent.point.getY() - a.point.getY()

            rX = disX/absvec(disX, disY)
            rY = disY/absvec(disX, disY)

            dx += rX / absvec(rX, rY)
            dy += rY / absvec(rX, rY)

        dx = -dx
        dy = -dy

    # zoo ; zoa leer
    elif matrix[1] != []  and matrix[2] == []:
        for agent in matrix[1]:
            dx += agent.Velocity_x / absvec(agent.Velocity_x, agent.Velocity_y)
            dy += agent.Velocity_y / absvec(agent.Velocity_x, agent.Velocity_y)
        dx += a.Velocity_x / absvec(a.Velocity_x, a.Velocity_y)
        dy += a.Velocity_y / absvec(a.Velocity_x, a.Velocity_y)


    # zoo leer ; zoa
    elif matrix[1] == []  and matrix[2] != []:
        for agent in matrix[2]:
            disX = agent.point.getX() - a.point.getX()
            disY = agent.point.getY() - a.point.getY()

            rX = disX/absvec(disX, disY)
            rY = disY/absvec(disX, disY)

            dx += rX / absvec(rX, rY)
            dy += rY / absvec(rX, rY)

    # zoo ; zoa
    elif matrix[1] != []  and matrix[2] != []:
        for agent in matrix[1]:
            dx += agent.Velocity_x / absvec(agent.Velocity_x, agent.Velocity_y)
            dy += agent.Velocity_y / absvec(agent.Velocity_x, agent.Velocity_y)
        dx += a.Velocity_x / absvec(a.Velocity_x, a.Velocity_y)
        dy += a.Velocity_y / absvec(a.Velocity_x, a.Velocity_y)

        for agent in matrix[2]:
            disX = agent.point.getX() - a.point.getX()
            disY = agent.point.getY() - a.point.getY()

            rX = disX/absvec(disX, disY)
            rY = disY/absvec(disX, disY)

            dx += rX / absvec(rX, rY)
            dy += rY / absvec(rX, rY)

        dx = 0.5*dx
        dy = 0.5*dy

	# all zones empty
    else:
        dx = a.Velocity_x
        dy = a.Velocity_y

	# randomness factor / error
    dx += random.uniform(-a.noise/2, a.noise/2)
    dy += random.uniform(-a.noise/2, a.noise/2)

    return [dx, dy]

# searches nearest food item, checks if it can be eaten,
# else returns direction vector pointing towards it
def check_food(agent, foods):
    dX=0
    dY=0
    if foods == []:
        return [dX,dY]

    nf = nearest_neighbour(agent, foods)
    dis = distance(agent.point.getX(), nf.point.getX(), agent.point.getY(), nf.point.getY())


    if dis<=agent.zor_r:
        nf.point.undraw()
        foods.remove(nf)
        agent.foodlevel += 1

    elif dis<=agent.zoa_r:
        disX = nf.point.getX() - agent.point.getX()
        disY = nf.point.getY() - agent.point.getY()

        rX = disX/absvec(disX, disY)
        rY = disY/absvec(disX, disY)

        dX = rX / absvec(rX, rY)
        dY = rY / absvec(rX, rY)

    return [dX, dY]

#same as checkfood, but can not eat a predator
def check_predator(agent, predators):
    dX=0
    dY=0
    if predators == []:
        return [dX,dY]

    nf = nearest_neighbour(agent, predators)
    dis = distance(agent.point.getX(), nf.point.getX(), agent.point.getY(), nf.point.getY())

    if dis<=agent.zoa_r:
        disX = nf.point.getX() - agent.point.getX()
        disY = nf.point.getY() - agent.point.getY()

        rX = disX/absvec(disX, disY)
        rY = disY/absvec(disX, disY)

        dX = rX / absvec(rX, rY)
        dY = rY / absvec(rX, rY)

    return [dX, dY]

#check for nearest prey in agents, and test if it can be eaten
def check_prey(predator, agents):
    dX = predator.Velocity_x
    dY = predator.Velocity_y

    if agents == []:
        return [dX,dY]

    na = nearest_neighbour(predator, agents)
    dis = distance(predator.point.getX(), na.point.getX(), predator.point.getY(), na.point.getY())

    if dis <= predator.zor_r:
        if visual:
            na.point.undraw()
            na.line.undraw()
            agents.remove(na)

        predator.hasEaten = True

    elif dis <= predator.zoa_r:
        disX = na.point.getX() - predator.point.getX()
        disY = na.point.getY() - predator.point.getY()

        rX = disX/absvec(disX, disY)
        rY = disY/absvec(disX, disY)

        dX = rX / absvec(rX, rY)
        dY = rY / absvec(rX, rY)

    return [dX, dY]

# updates velocity, taking food and predators and other agents into account
def updateV_final(agent, matrix,foods, predators):
    vc = updateV_couzin(agent, matrix)
    vf = check_food(agent, foods)
    vp = check_predator(agent, predators)

    vvX = vc[0] + agent.food_pref* vf[0] - agent.anti_pred * vp[0]
    vvY = vc[1] + agent.food_pref* vf[1] - agent.anti_pred * vp[1]

    return [vvX, vvY]


# check for window boundaries
def checkBoundary(agent, winWidth, winHeight):
    point = agent.point
    point.move(agent.Velocity_x,agent.Velocity_y)

    x = point.getX()
    y = point.getY()

    if x > 0 and y < winHeight and x < winWidth and y > 0:
        agent.point = point

    else:
        if x <= 0 or x >= winWidth:
            agent.Velocity_x = agent.Velocity_x * (-1)

        if y <= 0 or y >= winHeight:
            agent.Velocity_y = agent.Velocity_y * (-1)

        agent.point.move(agent.Velocity_x,agent.Velocity_y)
    return agent


#update and draw agents
def update_couzin(agents,foods, predators,winWidth, winHeight, window):
        # Velocity update
        for agent  in agents:
            neigbour_matrix = neigbour_in_zones(agent, agents)
            agent.tempV = updateV_final(agent, neigbour_matrix, foods, predators)

        # move, draw
        for agent in agents:
            # alpha = calc_angle(agent[1], agent[2],agent.tempV[0],agent[4][1])
            X = agent.Velocity_x
            y = agent.Velocity_y
	    # test if in ragne of agent.turn_angle,
	    # if true, set velocity == new velocity
	    # else rotate angle by maxTurn in
	    # direction of new direction
            radTurn = math.radians(agent.turn_angle)
            negRadTurn = math.radians(360-agent.turn_angle)

            angle_old = math.atan2(agent.Velocity_y, agent.Velocity_x)
            angle_new = math.atan2(agent.tempV[1], agent.tempV[0])
            alpha = math.degrees(angle_old - angle_new)

            if abs(alpha) > 180:
                if alpha < 0:
                    alpha += 360
                else:
                    alpha -= 360

            if abs(alpha)<agent.turn_angle:
                x = agent.tempV[0]
                y = agent.tempV[1]
            elif alpha < 0:
                x =  agent.Velocity_x * math.cos(radTurn) - agent.Velocity_y  * math.sin(radTurn)
                y =  agent.Velocity_x * math.sin(radTurn) + agent.Velocity_y  * math.cos(radTurn)
            else:
                x =  agent.Velocity_x * math.cos(negRadTurn) - agent.Velocity_y  * math.sin(negRadTurn)
                y =  agent.Velocity_x * math.sin(negRadTurn) + agent.Velocity_y  * math.cos(negRadTurn)

		# normalise dirction vector to 1, and multiply by constant speed

            absLen = absvec(x, y)
            agent.Velocity_x= x/absLen  * agent.speed
            agent.Velocity_y = y/absLen  * agent.speed
            agent = checkBoundary(agent, winWidth, winHeight)

		# draw arrow
            if visual:
                agent.drawLine()
        return agents

#update and draw predator
def update_predator(predator, agents, winWidth, winHeight, window):

    x = predator.Velocity_x
    y = predator.Velocity_y
    predator.tempV = check_prey(predator, agents)

    # test if in ragne of agent.turn_angle,
    # if true, set velocity == new velocity
    # else rotate angle by maxTurn in
    # direction of new direction

    radTurn = math.radians(predator.turn_angle)
    negRadTurn = math.radians(360-predator.turn_angle)

    angle_old = math.atan2(predator.Velocity_y, predator.Velocity_x)
    angle_new = math.atan2(predator.tempV[1], predator.tempV[0])
    alpha = math.degrees(angle_old - angle_new)

    if abs(alpha) > 180:
        if alpha < 0:
            alpha += 360
        else:
            alpha -= 360

    if abs(alpha)<predator.turn_angle:
        x = predator.tempV[0]
        y = predator.tempV[1]
    elif alpha < 0:
        x =  predator.Velocity_x * math.cos(radTurn) - predator.Velocity_y  * math.sin(radTurn)
        y =  predator.Velocity_x * math.sin(radTurn) + predator.Velocity_y  * math.cos(radTurn)
    else:
        x =  predator.Velocity_x * math.cos(negRadTurn) - predator.Velocity_y  * math.sin(negRadTurn)
        y =  predator.Velocity_x * math.sin(negRadTurn) + predator.Velocity_y  * math.cos(negRadTurn)

    # normalise diection vector to 1, and multiply by constant speed
    absLen = absvec(x, y)
    predator.Velocity_x = x/absLen  * predator.speed
    predator.Velocity_y = y/absLen  * predator.speed
    predator = checkBoundary(predator, winWidth, winHeight)

    # draw arrow
    if visual:
        predator.drawLine()
    return predator


# for choosing parent
def generateWheel(agents):
    """
    foodsum = 0
    for agent in agents:
        foodsum += agent.foodlevel
    """
    wheel = []
    currentsum = 0
    for agent in agents:
        currentsum += agent.foodlevel
        wheel.append(currentsum)
    return wheel

# chooses parent to mutate
def pickParent(agents, wheel):
    r = random.randrange(wheel[-1]) +1

    for i in range(len(wheel)):
        if r <= wheel[i]:
            return agents[i]

# greates a new agent, and assinges random values close to those of the parent
def mutate(parent):

    point = Point(random.uniform(0,winWidth/2), random.uniform(0,winHeight/2))
    child = Agent(point, window)

    child.Velocity_x = random.uniform(-1, 1)
    child.Velocity_y = random.uniform(-1, 1)

    child.zoa_r = random.uniform(parent.zoa_r - m_zoa_r, parent.zoa_r + m_zoa_r )
    child.zoa_r = max (child.zoa_r, math.sqrt(As/(2*math.pi)) )

    child.zoo_r = random.uniform(parent.zoo_r - m_zoo_r, parent.zoo_r + m_zoo_r)
    child.zoo_r = min( child.zoa_r , max(child.zoo_r, child.zor_r))

    child.speed = random.uniform(parent.speed - m_speed, parent.speed + m_speed)
    child.speed = min( 5 , max(child.speed, 1))

    child.blind_angle = (360 - math.degrees(As/(child.zoa_r**2)) ) / 2
    child.turn_angle = math.degrees(Am/(2*(child.speed**2)))

    child.food_pref = random.uniform(parent.food_pref - m_food, parent.food_pref + m_food)
    child.anti_pred = random.uniform(parent.anti_pred - m_pred, parent.anti_pred + m_pred)

    child.noise = random.uniform(parent.noise - m_noise, parent.noise + m_noise)

    return child

# picks parents, creates new agents with mutated values,
# returns them in a new agents list
def nextGen_food(agents):
    wheel = generateWheel(agents)
    tempAgents = []

    for i in range(agentNum):
        if wheel[-1] == 0:
            parent = pickParent_simple_random(agents)
        else:
            parent = pickParent(agents, wheel)
        child = mutate(parent)
        tempAgents.append(child)

    return tempAgents


#----------new generation for predator simulation
def pickParent_simple_random(agents):
    r = random.randrange(len(agents))
    return agents[r]

# picks parents, creates new agents with mutated values,
# returns them in a new agents list
def nextGen_pred(agents):
    tempAgents = []

    for i in range(agentNum):
        parent = pickParent_simple_random(agents)
        child = mutate(parent)
        tempAgents.append(child)

    return tempAgents

# ------------main------------------------
def simulate():
    # zones for couzin, vicsek
    # radii of zones
    # swarm: 10, 20, 200
    # torus: 5, 60, 200
    # dynamic parallel group: 5, 100, 200
    # highly parallel group: 5, 180, 200
    agents = []
    foods = []
    predators = []

    with open('data_param.csv','w') as csvfile:
        filewriter = csv.writer(csvfile, delimiter=',',quotechar='|',quoting = csv.QUOTE_MINIMAL)
        filewriter.writerow(["Iterations","Speed","turn","food pref","zoa","zoo","blind","noise","antipred"])

    with open('data_time.csv','w') as csvfile:
        filewriter = csv.writer(csvfile, delimiter=',',quotechar='|',quoting = csv.QUOTE_MINIMAL)
        filewriter.writerow(["x","y","x_velocity","y_velocity","foodlevel"])

    widthTemp = winWidth
    heightTemp = winHeight

    maxLife = 1000

    global window

    # first generation , random
    for i in range (agentNum):
        agent = Agent(Point(random.uniform(0,winWidth/2), random.uniform(0,winHeight/2)) , window)
        agents.append(agent.create_random_agent())


    for j in range(generations):
        if isPred or Both:
            for i in range(predNum):
                predator = Predator(Point(random.uniform(0,winWidth), random.uniform(0,winHeight)) , window)
                predators.append(predator.create_random_predator())

        # -----ausgabe------
        print ("generation " + str(j))

        avgSpeed = 0
        avgTurn = 0
        avgFood = 0
        avgPred = 0
        avgZOA = 0
        avgZOO = 0
        avgBlind = 0
        avgNoise = 0

        maxSpeed = 0
        maxTurnAngle = 0
        for agent in agents:
            avgSpeed += agent.speed
            avgPred += agent.anti_pred
            avgTurn += agent.turn_angle
            avgFood += agent.food_pref
            avgZOA += agent.zoa_r
            avgZOO += agent.zoo_r
            avgBlind += agent.blind_angle
            avgNoise += agent.noise

            if agent.speed > maxSpeed:
                maxSpeed = agent.speed
            if agent.turn_angle > maxTurnAngle:
                maxTurnAngle = agent.turn_angle

        avgSpeed /= agentNum
        avgTurn /= agentNum
        avgFood /= agentNum
        avgZOA /= agentNum
        avgZOO /= agentNum
        avgBlind /= agentNum
        avgNoise /= agentNum
        avgPred /= agentNum

        #("speed: " +str(avgSpeed))
        #print ("turn: " +str(avgTurn))
        #print ("food pref: " +str(avgFood))
        #print ("zoa: " +str(avgZOA))
        #print ("zoo: " +str(avgZOO))
        #print ("blind: " +str(avgBlind))
        #print ("noise: "+str(avgNoise))
        #print ("antipred: " + str(avgPred))
        #print ("maxspeed " +str(maxSpeed) )
        #print ("maxTurnAngle " +str(maxTurnAngle) )

        for agent in agents:
            with open('data_param.csv','a') as csvfile:
                filewriter = csv.writer(csvfile, delimiter=',',quotechar='|',quoting = csv.QUOTE_MINIMAL)
                filewriter.writerow([j, agent.speed, agent.turn, agent.food_pref, agent.zoa_r, agent.zoo_r, agent.blind_angle, agent.noise, agent.anti_pred])


        # -----ausgabe ende------

        #if visual:
        #   for agent in agents:
        #       agent.point.undraw()
        #       agent.point.draw(window)


        if isFood or Both:
            widthTemp = winWidth/2
            heightTemp = winHeight/2
        else:
            widthTemp = winWidth
            heightTemp = winHeight

        #timeStep = 0
        for timeStep in range(maxTime):

            # generate food and release agents
            if timeStep == maxTime * 0.025 and (isFood or Both):
                foods = generate_food(widthTemp, heightTemp)

                widthTemp = winWidth
                heightTemp = winHeight

            # exit generation if enough food has been eaten
            if timeStep >= maxTime * 0.025 and isFood:
                if len(foods) <= 1.0/8 * clusterSize * foodCluster:
                    #print ("done eating")
                    break

            # start predating
            if timeStep >= maxTime * 0.025 and (isPred or Both):
                if predators == []:
                    #print ("preds are done")
                    break
                else:
                    if(predators[-1].hasEaten or predators[-1].lifeTime >= maxLife):
                        print ("hasEaten")
                        if visual:
                            predators[-1].line.undraw()

                        predators.pop()
                    else:
                        predators[-1] = update_predator(predators[-1], agents, winWidth, winHeight, window)
                        predators[-1].lifeTime += 1
                        #print "pred absvec: " + str (absvec(predators[-1].Velocity_x, predators[-1].Velocity_y))


            # update agents
            agents = update_couzin(agents, foods, predators, widthTemp, heightTemp, window)


            #if visual:
            #   time.sleep(0.01*t)

        print ("eating time: " + str(timeStep))

        # new windos + new generation
        if visual:
            window.close()
            window = GraphWin("Window", winWidth, winHeight)
        if isFood or Both:
            agents = nextGen_food(agents)
        elif isPred:
            agents = nextGen_pred(agents)


simulate()