3
\$\begingroup\$

I was not sure if I should post about 200 lines here. I want to make this ant simulation faster. The bottleneck is at Ant.checkdistancebetweenantsandfood().

It would be great if you have some hints for some cleaner or more efficient code. I hope this is the right place to show this code.

import random
import time
import datetime
# TODO
# food - 100 portions okay
# bring food to the hill okay
# bring food to the hill - direct way
# use food over time
# die if food is out
# bear if enough food is there
# trail okay
# trail disolves over time
# opponent - different properties
# new food
# inside ant hill ?
# make calculations faster
#############################
# PLOT - BEGIN
#############################
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
# field size
size = 30
# black ants
x1 = [0]
y1 = [0]
points, = ax.plot(x1, y1, marker='o', linestyle='None', alpha=0.3,
 markersize=5, c='black')
# ant hill
x2 = [0]
y2 = [0]
points2, = ax.plot(x2, y2, marker='o', linestyle='None', alpha=0.6,
 markersize=30, c='brown')
# food
foodamount = 220
foodposx = []
foodposy = []
for i in range(foodamount):
 foodposx.append(random.randint(0, 2*size)-size)
 foodposy.append(random.randint(0, 2*size)-size)
points3, = ax.plot(foodposx, foodposy, marker='o', linestyle='None',
 alpha=0.6, markersize=5, c='green')
foundenoughfood = 20
anthillfood = 0
# movement
speed = .4
# trail
trailx = [0]
traily = [0]
trail, = ax.plot(trailx, traily, marker='o', linestyle='None', alpha=0.6,
 markersize=5, c='orange')
#trailduration = []
bearingspeed = 100 # higher value = slower bearing
# red ants
#...
ax.set_xlim(-size, size)
ax.set_ylim(-size, size)
new_x = np.random.randint(10, size=1)
new_y = np.random.randint(10, size=1)
points.set_data(new_x, new_y)
plt.pause(.0000000000001)
#############################
# PLOT - END
#############################
class Antqueen:
 counter = 2
 def __init__(self, name):
 """Initializes the data."""
 self.name = name
 print("(Initializing {0})".format(self.name))
 def bear(self):
 # print Antqueen.counter, 'ants born'
 self.name = 'ant_' + str(Antqueen.counter)
 Antqueen.counter = Antqueen.counter + 1
 ants[self.name] = None
 globals()[self.name] = Ant(self.name)
class Ant:
 population = 0
 def __init__(self, name):
 """Initializes the data."""
 self.name = name
 self.food = 10
 self.posx = 0.0
 self.posy = 0.0
 #print("(Initializing {0})".format(self.name))
 Ant.population += 1
 def die(self):
 """I am dying."""
 print("{0} is dead!".format(self.name))
 Ant.population -= 1
 if Ant.population == 0:
 print("{0} was the last one.".format(self.name))
 else:
 print("There are still {0:d} ants working.".format(Ant.population))
 def sayHi(self):
 print("Hello, call me {0}.".format(self.name))
 # move + trail
 def move(self):
 if globals()[name].food < foundenoughfood:
 self.posx = self.posx + speed*(random.random()-random.random())
 self.posy = self.posy + speed*(random.random()-random.random())
 # found enough food
 # go back to home
 else:
 # close to the ant hill
 # lay down some food to the ant hill
 if abs(self.posx) < .5:
 if abs(self.posy) < .5:
 global anthillfood
 anthillfood = anthillfood + globals()[name].food - 10
 #print "anthillfood: ", anthillfood
 # lay down everything but 10
 globals()[name].food = 10
 # far away from the ant hill
 # set trail
 trailx.append(self.posx)
 traily.append(self.posy)
 # draw the trail ###
 trail.set_data(trailx, traily)
 # move towards the ant hill
 vecx = -self.posx
 vecy = -self.posy
 len_vec = np.sqrt(vecx**2+vecy**2)
 self.posx = self.posx + vecx*1.0/len_vec/3 + speed*(random.random()-random.random())/1.5
 self.posy = self.posy + vecy*1.0/len_vec/3 + speed*(random.random()-random.random())/1.5
 def eat(self, name, foodnumber, foodposx, foodposy):
 if foodtable[foodnumber][1] > 0:
 # food on ground decreases
 foodtable[foodnumber][1] = foodtable[foodnumber][1] - 1
 # food in ant increases
 globals()[name].food = globals()[name].food + 1
 #print name, globals()[name].food, "food"
 # food is empty
 if foodtable[foodnumber][1] == 0:
 #print "foodposx: ", foodposx
 del foodposx[foodnumber]
 del foodposy[foodnumber]
 points3.set_data(foodposx, foodposy)
 @classmethod
 def howMany(cls):
 """Prints the current population."""
 print("We have {0:d} ants.".format(cls.population))
 def checkdistancebetweenantsandfood(self):
 for name in ants.keys():
 for i in range(len(foodposx)-1):
 # measure distance between ant and food
 if -1 < globals()[name].posx - foodposx[i] < 1:
 if -1 < globals()[name].posy - foodposy[i] < 1:
 globals()[name].eat(name, i, foodposx, foodposy)
 # slower
 #distance = np.sqrt((globals()[name].posx - foodposx[i])**2 + (globals()[name].posy - foodposy[i])**2)
 #if distance < 1:
 # globals()[name].eat(name, i, foodposx, foodposy)
# generate ant queen
antqueen = Antqueen("antqueen")
# generate some ants
ants = {'ant_1': None}
for name in ants.keys():
 globals()[name] = Ant(name)
# amount of food
foodtable = []
for i in range(foodamount):
 foodtable.append([i, 10])
#############################
# start simulation
#############################
for i in range(100000):
 # move all ants
 for name in ants.keys():
 globals()[name].move()
 # generate more ants
 if (i % bearingspeed == 0):
 antqueen.bear()
 # plot ants
 allposx = []
 allposy = []
 for name in ants.keys():
 allposx.append(globals()[name].posx)
 allposy.append(globals()[name].posy)
 points.set_data(allposx, allposy)
 plt.draw()
 #plt.pause(0.000000000001) # draw is faster
 # ants find food
 for name in ants.keys():
 globals()[name].checkdistancebetweenantsandfood()
200_success
146k22 gold badges190 silver badges479 bronze badges
asked Jan 13, 2014 at 6:42
\$\endgroup\$
5
  • 1
    \$\begingroup\$ Have you tried the "slower" code without calling np.sqrt()? (In other words, work using the square of the distance.) \$\endgroup\$ Commented Jan 13, 2014 at 9:43
  • \$\begingroup\$ The square of the distance? Do you mean distance**(0.5)? \$\endgroup\$ Commented Jan 13, 2014 at 10:47
  • 1
    \$\begingroup\$ dist_sq = (globals()[name].posx - foodposx[i])**2 + (globals()[name].posy - foodposy[i])**2; if dist_sq < 1 * 1: eat(...) \$\endgroup\$ Commented Jan 13, 2014 at 10:50
  • 1
    \$\begingroup\$ globals() is meant for special uses only. Why don't you simply store the Ant objects in the ants dictionary? \$\endgroup\$ Commented Jan 13, 2014 at 12:29
  • 1
    \$\begingroup\$ This could be a fun week-end CR challenge \$\endgroup\$ Commented Jan 19, 2014 at 14:16

2 Answers 2

2
\$\begingroup\$

It looks like you're looping through the ants twice, once inside checkdistancebetweenantsandfood() and once when you call it. That seems like it's probably wrong.

Method:

 def checkdistancebetweenantsandfood(self):
 for name in ants.keys():
 for i in range(len(foodposx)-1):
 # measure distance between ant and food
 if -1 < globals()[name].posx - foodposx[i] < 1:
 if -1 < globals()[name].posy - foodposy[i] < 1:
 globals()[name].eat(name, i, foodposx, foodposy)

Call:

 # ants find food
 for name in ants.keys():
 globals()[name].checkdistancebetweenantsandfood()

Other optimizations

Another possible optimization is to exit the loop if a food source is found. Presumably the ants can only eat from one food source at a time.

Example:

 def checkdistancebetweenantsandfood(self):
 for name in ants.keys():
 for i in range(len(foodposx)-1):
 # measure distance between ant and food
 if -1 < globals()[name].posx - foodposx[i] < 1:
 if -1 < globals()[name].posy - foodposy[i] < 1:
 globals()[name].eat(name, i, foodposx, foodposy)
 break

If there are many food sources, you might try putting the food sources into a grid based on their position. That way the ants only need to check the for food sources in adjacent cells instead of having to loop through all of the food sources.

answered Jan 18, 2014 at 19:07
\$\endgroup\$
1
\$\begingroup\$

PEP-8 suggest the following about function names:

Function names should be lowercase, with words separated by underscores as necessary to improve readability.

check_distance_between_ants_and_food would follow this guidance and would be easier to read.

answered Jan 25, 2014 at 23:28
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.