Skip to content
Snippets Groups Projects
Select Git revision
  • d7c2ffa19cadd5639f36dc3e5c9cdbef79864098
  • master default protected
  • 0.6.5 protected
  • 0.6.4 protected
  • 0.6.3 protected
  • 0.6.2 protected
  • 0.6.1 protected
  • 0.6 protected
  • 0.5 protected
  • 0.4 protected
  • 0.3 protected
  • 0.2.1 protected
  • 0.2 protected
  • 0.1 protected
  • 0 protected
15 results

setup.py

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    ackland_simulation.py 18.81 KiB
    from graphics import * # get here: http://mcsp.wartburg.edu/zelle/python/graphics.py
    import time
    import random
    import math
    import csv
    
    # imports from our files
    from help_functions import *
    from classes import *
    from check_boundarys import *
    
    '''
    plot is not used here, because we could not figure
    out a way to close the plot and continue with the next generation
    '''
    # ------------------------------------------------------------------
    # global varibles
    
    
    # window dimensions
    winWidth = 700
    winHeight = 700
    
    # set true to show visualisation/write data in csv
    visual = True
    writecsv = False
    
    # names for csvs
    GENERATIONS = "generations.csv"
    TIMESTEPS = "timesteps.csv"
    
    if visual:
        window = GraphWin("Window", winWidth, winHeight)
    else:
        window = None
    
    # max time for one generation
    maxTime = 10000
    
    # number of agents
    agentNum = 80
    # number of predators
    predNum = agentNum//10
    # number of generations
    generations = 500
    
    # food cluster variables
    # soll insgesamt immer 128 ergeben
    foodCluster = 16
    clusterSize = 8
    clusterradius = 20
    
    # isFood turns on food simulation,
    # isPred turns on predator simulation
    isFood = False
    isPred = True
    Both = False
    
    # timestep 
    t = 0.1
    
    # values of Agents as given in the Paper
    rr = 5
    # area an agent can see
    As = 5000 * (rr**2)
    Am = 5 * (rr**2) * t
    
    # mutation values,
    # determine how fast aspects of Agents can mutate
    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
    
    
    # ------------------------------------------------------------------
    # Ackland
    
    # returns three lists, one for each zone,
    # contaning all other agent in the zone.
    # ignores al agents in the angle behind the current agent defined by blind.
    # the zones zor/zoo/zoa are defined by their radii zor_r/zoo_r/zoa_r
    
    # exactly the same as in couzin, but gets more arguments,
    # because they are not global here
    
    def neigbour_in_zones(agent, agents, zor_r, zoo_r, zoa_r, blind):
        zor = []
        zoo = []
        zoa = []
    
        for neighbour in agents:
            # find distance in x and y direction,
            # and use them to calculate the angle between
            # the movement-vector of agent and
            # the directiction-vector between agent and neighbour
            
            disVecX = neighbour.point.getX() - agent.point.getX()
            disVecY = neighbour.point.getY() - agent.point.getY()
            alpha = calc_angle(agent.x_velocity, agent.y_velocity, disVecX, disVecY)
    
            if (agent == neighbour):
                True
            elif alpha < 180 - blind and alpha > 180 + blind:
                True
    
            # if neighbour can be seen:
            # get distance dis between agent and neighbour,
            # and check if neighbour is in a zone of agent
            else:
                dis = absvec(neighbour.point.getX() - agent.point.getX(), neighbour.point.getY() - agent.point.getY())
                if dis <= zor_r:
                    zor.append(neighbour)
                elif dis <= zoo_r:
                    zoo.append(neighbour)
                elif dis <= zoa_r:
                    zoa.append(neighbour)
    
        return [zor, zoo, zoa]
    
    
    # update Velocity a la couzin
    # exactly the same as in couzin, but noise is
    # not global and attributes are named differently
    # for some reason...
    def updateV_couzin(agent, zones):
        dx = 0
        dy = 0
    
        #zor not empty
        if zones[0] != []:
            for neighbour in zones[0]:
                disX = neighbour.point.getX() - agent.point.getX()
                disY = neighbour.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)
    
            dx = -dx
            dy = -dy
    
        # zoo not empty; zoa empty
        elif zones[1] != []  and zones[2] == []:
            for neighbour in zones[1]:
                dx += neighbour.x_velocity / absvec(neighbour.x_velocity, neighbour.y_velocity)
                dy += neighbour.y_velocity / absvec(neighbour.x_velocity, neighbour.y_velocity)
    
            dx += agent.x_velocity / absvec(agent.x_velocity, agent.y_velocity)
            dy += agent.y_velocity / absvec(agent.x_velocity, agent.y_velocity)
    
    
        # zoo empty; zoa not empty
        elif zones[1] == []  and zones[2] != []:
            for neighbour in zones[2]:
                disX = neighbour.point.getX() - agent.point.getX()
                disY = neighbour.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)
    
        # zoo and zoa not empty
        elif zones[1] != []  and zones[2] != []:
            for neighbour in zones[1]:
                dx += neighbour.x_velocity / absvec(neighbour.x_velocity, neighbour.y_velocity)
                dy += neighbour.y_velocity / absvec(neighbour.x_velocity, neighbour.y_velocity)
    
            dx += agent.x_velocity / absvec(agent.x_velocity, agent.y_velocity)
            dy += agent.y_velocity / absvec(agent.x_velocity, agent.y_velocity)
    
            for neighbour in zones[2]:
                disX = neighbour.point.getX() - agent.point.getX()
                disY = neighbour.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)
    
            dx = 0.5*dx
            dy = 0.5*dy
    
        # all zones empty
        else:
            dx = agent.x_velocity
            dy = agent.y_velocity
    
        # randomness factor / error
        dx += random.uniform(-agent.noise/2, agent.noise/2)
        dy += random.uniform(-agent.noise/2, agent.noise/2)
    
        return [dx, dy]
    
    
    # checks if neares food is in zor, if yes, eat it
    # else checks if neares food is in zoa,
    # and returns vector pointing in it´s direction
    def check_food(agent, foods):
        dX = 0
        dY = 0
        
        if foods == []:
            return [dX,dY]
    
        nearestFood = nearest_neighbour(agent, foods)
        dis = distance(agent.point.getX(), nearestFood.point.getX(), agent.point.getY(), nearestFood.point.getY())
    
        if dis <= agent.zor_r:
            if visual:
                nearestFood.point.undraw()
            foods.remove(nearestFood)
            agent.foodLevel += 1
    
        elif dis <= agent.zoa_r:
            disX = nearestFood.point.getX() - agent.point.getX()
            disY = nearestFood.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]
    
    
    # else checks if neares predator is in zoa,
    # and returns vector pointing in it´s direction
    def check_predator(agent, predators):
        dX=0
        dY=0
        
        if predators == []:
            return [dX,dY]
    
        nearestPred = nearest_neighbour(agent, predators)
        dis = distance(agent.point.getX(), nearestPred.point.getX(), agent.point.getY(), nearestPred.point.getY())
    
        if dis <= agent.zoa_r:
            disX = nearestPred.point.getX() - agent.point.getX()
            disY = nearestPred.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]
    
    
    # checks if neares prey is in zor, if yes, eat it
    # else checks if neares prey is in zoa,
    # and returns vector pointing in it´s direction
    def check_prey(predator, agents):
        dX = predator.x_velocity
        dY = predator.y_velocity
        
        if agents == []:
            return [dX,dY]
    
        nearestPrey = nearest_neighbour(predator, agents)
        dis = distance(predator.point.getX(), nearestPrey.point.getX(), predator.point.getY(), nearestPrey.point.getY())
    
        if dis <= predator.zor_r:
            if visual:
                nearestPrey.point.undraw()
                nearestPrey.line.undraw()
                agents.remove(nearestPrey)
    
            predator.hasEaten = True
    
        elif dis <= predator.zoa_r:
            disX = nearestPrey.point.getX() - predator.point.getX()
            disY = nearestPrey.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]
    
    
    # return new velocity, taking food and predators into acount
    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]
    
    # ------------------------------------------------------------------
    # update functions
    
    #update agents
    def update_couzin(agents, foods, predators, winWidth, winHeight, window):
            # Velocity update
            for agent  in agents:
                neigh_matrix = neigbour_in_zones(agent, agents, agent.zor_r, agent.zoo_r, agent.zoa_r, agent.blind_angle,)
                agent.tempvelocity = updateV_final(agent, neigh_matrix, foods, predators)
                
            # move, draw
            for agent in agents:
                # test if in ragne of agent.turn_angle, if not rotate angle by maxTurn in
    	    # direction of new direction
                radTurn = math.radians(agent.turn_angle)
                negRadTurn = math.radians(360-agent.turn_angle)
    
                # check if rotation is in range of turn-angle
                agent = move_agent_couzin(agent, agent.turn_angle, radTurn, negRadTurn)
    
    	    # normalise direction vector to 1, and multiply by constant speed
                x = agent.x_velocity/absvec(agent.x_velocity, agent.y_velocity)  * agent.speed
                agent.y_velocity = agent.y_velocity/absvec(agent.x_velocity, agent.y_velocity)  * agent.speed
                agent.x_velocity = x
    
                agent = checkBoundary(agent, winWidth, winHeight)
    
    	    # draw agent
                if visual:
                    agent.drawLine()
                    
            return agents
    
    
    #update predator
    def update_predator(predator, agents, winWidth, winHeight, window):
        predator.tempvelocity = check_prey(predator, agents)
    
        radTurn = math.radians(predator.turn_angle)
        negRadTurn = math.radians(360-predator.turn_angle)
    
        # check if rotation is in range of turn-angle
        predator = move_agent_couzin(predator, predator.turn_angle, radTurn, negRadTurn)
    
        # normalise diection vector to 1, and multiply by constant speed
        x = predator.x_velocity/absvec(predator.x_velocity, predator.y_velocity)  * predator.speed
        predator.y_velocity = predator.y_velocity/absvec(predator.x_velocity, predator.y_velocity)  * predator.speed
        predator.x_velocity = x
    
        predator = checkBoundary(predator, winWidth, winHeight)
    
        # draw predator
        if visual:
            predator.drawLine()
            
        return predator
    
    
    # ------------------------------------------------------------------
    # next gen functions
    
    # mutate agent in order to get a child
    def mutate(parent):
    
        point = Point(random.uniform(0,winWidth/2), random.uniform(0,winHeight/2))
        child = AcklandAgent(point, window)
    
        # give them a random starting direction
        child.x_velocity = random.uniform(-1, 1)
        child.y_velocity = 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
    
    
    # --------------------------------------------------------------
    # get next generation food simulation
    
    # generate a "wheel of fortune"
    # depending on foodLevel of agent:
    # has eaten more <->
    # higher probability to get picked as parent
    def generateWheel(agents):
        wheel = []
        currentsum = 0
        for agent in agents:
            currentsum += agent.foodLevel
            wheel.append(currentsum)
        return wheel
    
    
    # use wheel to pick an agent to mutate
    # in order to get a child
    def pickParent(agents, wheel):
        r = random.randrange(wheel[-1]) +1
    
        for i in range(len(wheel)):
            if r <= wheel[i]:
                return agents[i]
    
    
    # generate next Generation of agents for the food simulation
    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
    
    # --------------------------------------------------------------
    # get next generation predator simulation
    
    # just pick one of those that survived randomly as parent
    def pickParent_simple_random(agents):
        r = random.randrange(len(agents))
        return agents[r]
    
    # generate next Generation of agents for the predator simulation
    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 main():
    
        agents = []
        foods = []
        predators = []
    
        # open csv to collect data
        if writecsv:
            with open(GENERATIONS,'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(TIMESTEPS,'w') as csvfile:
                filewriter = csv.writer(csvfile, delimiter=',',quotechar='|',quoting = csv.QUOTE_MINIMAL)
                filewriter.writerow(["Generations","Timestep","x","y","x_velocity","y_velocity","foodlevel"])
    
        widthTemp = winWidth
        heightTemp = winHeight
    
        maxLife = 1000
    
        global window
    
        # first generation , random
        for i in range (agentNum):
            agent = AcklandAgent(Point(random.uniform(0,winWidth/2), random.uniform(0,winHeight/2)) , window)
            agents.append(agent.create_random_agent(rr, As, Am))
    
        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(rr, As))
    
            # -----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
    
            if writecsv:
                for agent in agents:
                    with open(GENERATIONS,'a') as csvfile:
                        filewriter = csv.writer(csvfile, delimiter=',',quotechar='|',quoting = csv.QUOTE_MINIMAL)
                        filewriter.writerow([j, agent.speed, agent.turn_angle, agent.food_pref, agent.zoa_r, agent.zoo_r, agent.blind_angle, agent.noise, agent.anti_pred])
    
            # -----ausgabe ende------
    
            if isFood or Both:
                widthTemp = winWidth/2
                heightTemp = winHeight/2
            else:
                widthTemp = winWidth
                heightTemp = winHeight
    
            # main loop
            for timeStep in range(maxTime):
                # every 50 timesteps collect data
                if timeStep % 50 == 0 and j % 50 == 0 and writecsv:
                    for agent in agents:
                        with open(TIMESTEPS,'a') as csvfile:
                            filewriter = csv.writer(csvfile, delimiter=',',quotechar='|',quoting = csv.QUOTE_MINIMAL)
                            filewriter.writerow([j,timeStep,agent.point.getX(),agent.point.getY(),agent.x_velocity,agent.y_velocity,agent.foodLevel])
    
    
                # generate food and release agents at 1/4 of maxtime
                if timeStep == maxTime * 0.025 and (isFood or Both):
                    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)
                    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:
                        break
    
                # start predating / update predators
                if timeStep >= maxTime * 0.025 and (isPred or Both):
                    if predators == []:
                        break
                    else:
                        # delete current predator if it has eaten
                        if(predators[-1].hasEaten or predators[-1].lifeTime >= maxLife):
                            if visual:
                                predators[-1].line.undraw()
                            predators.pop()
                            
                        else:
                            predators[-1] = update_predator(predators[-1], agents, winWidth, winHeight, window)
                            predators[-1].lifeTime += 1
    
                # update agents
                agents = update_couzin(agents, foods, predators, widthTemp, heightTemp, window)
    
    
            print ("eating time: " + str(timeStep))
    
            # new windos and 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)
    
    
    main()