# Boids I recently came across an article that mentioned boids, which is essentially a computer simulation of a flock a birds. Boids uses three simple rules, from which complex behaviour emerges. Having studied large scale distributed systems I'm familiar with emergent behaviour, but I haven't seen anything that looks as impressive as boids.

The three rules of the Boid system are:

Rule 1: Don't overcrowd near-by boids Rule 2: Move closer to near-by boids Rule 3: Move in the general direction of the other boids

I thought I'd have a crack at implementing my own boids. I hadn't used PyGame before, but it looked ideal for this project.

First I came up with a basic boid class that stores the boids position and velocity.

``````class Boid:
def __init__(self, x, y):
self.x = x
self.y = y
self.velocityX = random.randint(1, 10) / 10.0
self.velocityY = random.randint(1, 10) / 10.0
``````

I added a method to move the boid based on its velocity, and a method to detect the distance between two boids. Then I added the code for each of the rules. Rule 1: Don't overcrowd near-by boids.

``````    "Move away from a set of boids. This avoids crowding"
def moveAway(self, boids, minDistance):
if len(boids) &lt; 1: return

distanceX = 0
distanceY = 0
numClose = 0

for boid in boids:
distance = self.distance(boid)
if  distance &lt; minDistance:
numClose += 1
xdiff = (self.x - boid.x)
ydiff = (self.y - boid.y)

if xdiff &gt;= 0: xdiff = math.sqrt(minDistance) - xdiff
elif xdiff &lt; 0: xdiff = -math.sqrt(minDistance) - xdiff

if ydiff &gt;= 0: ydiff = math.sqrt(minDistance) - ydiff
elif ydiff &lt; 0: ydiff = -math.sqrt(minDistance) - ydiff

distanceX += xdiff
distanceY += ydiff

if numClose == 0:
return

self.velocityX -= distanceX / 5
self.velocityY -= distanceY / 5
``````

Rule 2: Move closer to near-by boids.

``````    "Move closer to a set of boids"
def moveCloser(self, boids):
if len(boids) &lt; 1: return

# calculate the average distances from the other boids
avgX = 0
avgY = 0
for boid in boids:
if boid.x == self.x and boid.y == self.y:
continue

avgX += (self.x - boid.x)
avgY += (self.y - boid.y)

avgX /= len(boids)
avgY /= len(boids)

# set our velocity towards the others
distance = math.sqrt((avgX * avgX) + (avgY * avgY)) * -1.0

self.velocityX -= (avgX / 100)
self.velocityY -= (avgY / 100)
``````

Rule 3: Move in the general direction of the other boids

``````    "Move with a set of boids"
def moveWith(self, boids):
if len(boids) &lt; 1: return
# calculate the average velocities of the other boids
avgX = 0
avgY = 0

for boid in boids:
avgX += boid.velocityX
avgY += boid.velocityY

avgX /= len(boids)
avgY /= len(boids)

# set our velocity towards the others
self.velocityX += (avgX / 40)
self.velocityY += (avgY / 40)
``````

So that was the boid code sorted. Then all that was required was some code to tie it all together and display the boids:

``````pygame.init()

size = width, height = 800, 600
black = 0, 0, 0

maxVelocity = 10
numBoids = 50
boids = []

screen = pygame.display.set_mode(size)

ballrect = ball.get_rect()

# create boids at random positions
for i in range(numBoids):
boids.append(Boid(random.randint(0, width), random.randint(0, height)))

while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()

for boid in boids:
closeBoids = []
for otherBoid in boids:
if otherBoid == boid: continue
distance = boid.distance(otherBoid)
if distance &lt; 200:
closeBoids.append(otherBoid)

boid.moveCloser(closeBoids)
boid.moveWith(closeBoids)
boid.moveAway(closeBoids, 20)

# ensure they stay within the screen space
# if we roubound we can lose some of our velocity
border = 25
if boid.x &lt; border and boid.velocityX &lt; 0:
boid.velocityX = -boid.velocityX * random.random()
if boid.x &gt; width - border and boid.velocityX &gt; 0:
boid.velocityX = -boid.velocityX * random.random()
if boid.y &lt; border and boid.velocityY &lt; 0:
boid.velocityY = -boid.velocityY * random.random()
if boid.y &gt; height - border and boid.velocityY &gt; 0:
boid.velocityY = -boid.velocityY * random.random()

boid.move()

screen.fill(black)
for boid in boids:
boidRect = pygame.Rect(ballrect)
boidRect.x = boid.x
boidRect.y = boid.y
screen.blit(ball, boidRect)
pygame.display.flip()
``````

I'm really impressed with the results! From the interaction of three simple rules some quite complex behaviour emerges.