Dark theme

Classes and objects


This practical we'll finally get to meet some proper agents: we'll convert the code we've got into an object oriented version, complete with an agent class to encapsulate our agents' properties and behaviour.

First up, here's roughly where we should be again. I've cut anything that was experimental, leaving the core of our code: backup what you've got, then copy this into your model.py file.

import random
import operator
import matplotlib.pyplot

def distance_between(agents_row_a, agents_row_b):
    return (((agents_row_a[0] - agents_row_b[0])**2) +
        ((agents_row_a[1] - agents_row_b[1])**2))**0.5

num_of_agents = 10
num_of_iterations = 100
agents = []

# Make the agents.
for i in range(num_of_agents):
    agents.append([random.randint(0,99),random.randint(0,99)])

# Move the agents.
for j in range(num_of_iterations):
    for i in range(num_of_agents):

        if random.random() < 0.5:
            agents[i][0] = (agents[i][0] + 1) % 100
        else:
            agents[i][0] = (agents[i][0] - 1) % 100

        if random.random() < 0.5:
            agents[i][1] = (agents[i][1] + 1) % 100
        else:
            agents[i][1] = (agents[i][1] - 1) % 100


matplotlib.pyplot.xlim(0, 99)
matplotlib.pyplot.ylim(0, 99)
for i in range(num_of_agents):
    matplotlib.pyplot.scatter(agents[i][1],agents[i][0])
matplotlib.pyplot.show()

for agents_row_a in agents:
    for agents_row_b in agents:
        distance = distance_between(agents_row_a, agents_row_b)


As an aside, note that the code:

    for i in range(num_of_agents):
        if random.random() < 0.5:
            agents[i][0] = (agents[i][0] + 1) % 100

and

for agents_row_a in agents:
    for agents_row_b in agents:
        distance = distance_between(agents_row_a, agents_row_b)

both pull out agents: the first using an index, the second the for-each loop iterator. There's good no reason for the difference, other than in the first case we were trying to understand the data structure. Now we understand it, we might want to change the former so it uses the for-loop iterator style; but in the best "if it ain't broke don't fix it" fashion, let's leave it as it is for the moment.


We're going to make ourselves a Agent class, in a new agentframework.py module, and put most of the code (bold, above) that initialises the agents in a random location, and moves them, into the agent class. Here's what our model.py will look like when we're done:

import random
import operator
import matplotlib.pyplot
import agentframework

def distance_between(agents_row_a, agents_row_b):
    return (((agents_row_a.x - agents_row_b.x)**2) +
    ((agents_row_a.y - agents_row_b.y)**2))**0.5


num_of_agents = 10
num_of_iterations = 100
agents = []

# Make the agents.
for i in range(num_of_agents):
    agents.append(agentframework.Agent())

# Move the agents.
for j in range(num_of_iterations):
    for i in range(num_of_agents):

        agents[i].move()

matplotlib.pyplot.xlim(0, 99)
matplotlib.pyplot.ylim(0, 99)
for i in range(num_of_agents):
    matplotlib.pyplot.scatter(agents[i].x,agents[i].y)
matplotlib.pyplot.show()

for agents_row_a in agents:
    for agents_row_b in agents:
        distance = distance_between(agents_row_a, agents_row_b)

Here's the UML version. This is a class diagram. It says that there is one model with multiple agents it is responsible for the lifecycle of. The model will have a list of Agents, and a distance_between function. The Agents are going to have y and x coordinates. These will be protected to some degree and made available through appropriate accessor and mutator methods. They will also have a move method.

UML of the model

To start this process, make yourself a blank agentframework.py file in the same directory as your model.py. Open it up in Spyder, and define inside it an Agent class, with an __init__ method. Don't forget that all object methods have to have a parameter label to assign to the object when it is sent in; usually called self.

import agentframework at the top of model.py, and then convince yourself the two files are connected by somewhere in model.py making a single Agent:

a = agentframework.Agent()

Once you've got that running, we'll look at initalizing the Agent.


  1. This page
  2. Giving the agents attributes and behaviour <-- next
  3. Using the attributes and behaviour