diff --git a/week09/improvement/boids.py b/week09/improvement/boids.py index e1cba89..f329db7 100644 --- a/week09/improvement/boids.py +++ b/week09/improvement/boids.py @@ -1,44 +1,71 @@ """ -A deliberately bad implementation of +An improved implementation of [Boids](http://dl.acm.org/citation.cfm?doid=37401.37406) for use as an exercise on refactoring. This code simulates the swarming behaviour of bird-like objects ("boids"). -""" -from matplotlib import pyplot as plt -from matplotlib import animation +Aspects of boid motion simulated: +1. Boids want to fly towards centre of flock +2. Boids want to fly away from nearby boids +3. Boids want to have similar velocity to nearby boids +""" +# import random for definining boids' initial states import random -boids_x=[random.uniform(-450,50.0) for x in range(50)] -boids_y=[random.uniform(300.0,600.0) for x in range(50)] -boid_x_velocities=[random.uniform(0,10.0) for x in range(50)] -boid_y_velocities=[random.uniform(-20.0,20.0) for x in range(50)] -boids=(boids_x,boids_y,boid_x_velocities,boid_y_velocities) +# set number of boids +num_boids = 50 +xmin = -450 +xmax = 50 +ymin = 60 +ymax = 300 +xvmin = 0 +xvmax = 10 +yvmin = -20 +yvmax = 20 + +# create boids within function using user-defined values +def create_boids(num_boids,xmin,xmax,ymin,ymax,xvmin,xvmax,yvmin,yvmax): + # produce list of each variable + boids_x=[random.uniform(xmin,xmax) for x in range(num_boids)] + boids_y=[random.uniform(ymin,ymax) for x in range(num_boids)] + boid_x_velocities=[random.uniform(xvmin,xvmax) for x in range(num_boids)] + boid_y_velocities=[random.uniform(yxmin,yvmax) for x in range(num_boids)] + # produce tuple of variable lists + boids=(boids_x,boids_y,boid_x_velocities,boid_y_velocities) + return boids -def update_boids(boids): +boids = create_boids(num_boids,xmin,xmax,ymin,ymax,xvmin,xvmax,yvmin,yvmax) + +# define variables for updating +centre_scale = 0.01 +local_vel_scale = 0.125 +repel_thresh = 100 +local_vel_thresh = 10000 + +def update_boids(boids, centre_scale, local_vel_scale, repel_thresh, local_vel_thresh): + # define positions and velocities of boids + # xs - list of boid x positions + # ys - list of boid y positions + # xvs - list of boid x velocities + # yvs - list of boid y velocities xs,ys,xvs,yvs=boids - # Fly towards the middle - for i in range(len(xs)): - for j in range(len(xs)): - xvs[i]=xvs[i]+(xs[j]-xs[i])*0.01/len(xs) - for i in range(len(xs)): - for j in range(len(xs)): - yvs[i]=yvs[i]+(ys[j]-ys[i])*0.01/len(xs) - # Fly away from nearby boids + # simulate different aspects of boid motion for i in range(len(xs)): + # iterate over all other boids to define interactions for j in range(len(xs)): - if (xs[j]-xs[i])**2 + (ys[j]-ys[i])**2 < 100: + # Fly towards the middle (1) + xvs[i]=xvs[i]+(xs[j]-xs[i])*centre_scale/len(xs) + yvs[i]=yvs[i]+(ys[j]-ys[i])*centre_scale/len(xs) + # Fly away from nearby boids (2) + if (xs[j]-xs[i])**2 + (ys[j]-ys[i])**2 < repel_thresh: xvs[i]=xvs[i]+(xs[i]-xs[j]) yvs[i]=yvs[i]+(ys[i]-ys[j]) - # Try to match speed with nearby boids - for i in range(len(xs)): - for j in range(len(xs)): - if (xs[j]-xs[i])**2 + (ys[j]-ys[i])**2 < 10000: - xvs[i]=xvs[i]+(xvs[j]-xvs[i])*0.125/len(xs) - yvs[i]=yvs[i]+(yvs[j]-yvs[i])*0.125/len(xs) - # Move according to velocities - for i in range(len(xs)): + # Try to match speed with nearby boids (3) + if (xs[j]-xs[i])**2 + (ys[j]-ys[i])**2 < local_vel_thresh: + xvs[i]=xvs[i]+(xvs[j]-xvs[i])*local_vel_scale/len(xs) + yvs[i]=yvs[i]+(yvs[j]-yvs[i])*local_vel_scale/len(xs) + # Move according to velocities xs[i]=xs[i]+xvs[i] ys[i]=ys[i]+yvs[i] \ No newline at end of file diff --git a/week09/refactoring/initial_global.py b/week09/refactoring/initial_global.py index 21f1323..e3e223c 100644 --- a/week09/refactoring/initial_global.py +++ b/week09/refactoring/initial_global.py @@ -1,16 +1,16 @@ -def average_age(): +def average_age(group): """Compute the average age of the group's members.""" all_ages = [person["age"] for person in group.values()] return sum(all_ages) / len(group) -def forget(person1, person2): +def forget(group, person1, person2): """Remove the connection between two people.""" group[person1]["relations"].pop(person2, None) group[person2]["relations"].pop(person1, None) -def add_person(name, age, job, relations): +def add_person(group, name, age, job, relations): """Add a new person with the given characteristics to the group.""" new_person = { "age": age, @@ -19,8 +19,8 @@ def add_person(name, age, job, relations): } group[name] = new_person - -group = { +if __name__ == "__main__": + group = { "Jill": { "age": 26, "job": "biologist", @@ -43,19 +43,18 @@ def add_person(name, age, job, relations): "Jill": "partner" } } -} + } -nash_relations = { + nash_relations = { "John": "cousin", "Zalika": "landlord" -} + } -add_person("Nash", 34, "chef", nash_relations) + add_person(group, "Nash", 34, "chef", nash_relations) -forget("Nash", "John") + forget(group, "Nash", "John") -if __name__ == "__main__": assert len(group) == 4, "Group should have 4 members" - assert average_age() == 28.75, "Average age of the group is incorrect!" + assert average_age(group) == 28.75, "Average age of the group is incorrect!" assert len(group["Nash"]["relations"]) == 1, "Nash should only have one relation" print("All assertions have passed!")