A RePast Tutorial by John T. Murphy, University of Arizona & Arizona State University (contact)
At this point the model will load and run, but it won't do anything. Pressing the 'begin' button causes errors. Our next task will be to add actions to the model, so that it can be run through time.
For now we will focus on a boring element: getting agents to 'age.' Once per time step, the agents 'stepsToLive' variable should go down one. This is a very simple action, and for now we'll even ignore the implications of what will happen when it hits zero; instead, we'll just focus on how RePast uses a Schedule object to manage actions in the simulation.
We will need to create a method in the CarryDropAgent called 'step'; this is the easy part. For now, all it has to do is decrement the 'stepsToLive' variable.
The subtler part is creating the schedule object. Making an instance of the schedule object is done in the 'setup' method; in this case we tell the object that we want it to run in time steps with an interval of '1'
We must next specify what we want the schedule object to do. This is done by creating an inner class- that is, a class that is defined within another class instead of on its own- and adding it to the Schedule object using one of RePast's built-in functions. These built in functions allow you to specify when the action defined by the inner class is executed.
All of this goes on in the 'buildSchedule' method of the model object. The inner class created must extend the 'BasicAction' object, which requires that it define a method called 'execute()'. Within this 'execute' method you can specify what actions are to be taken. Our actions will simply be to:
Notice that our shuffle routine makes use of another RePast tool, SimUtilities; RePast has a built-in tool to shuffle ArrayLists, which we can use to randomize the order in which the agents are called to step. Note that the 'shuffle' function requires the cern.jet.random library; you may need to add this to your project's build path, and it may be found in a file called colt.jar. (See Build Path in the introduction to this tutorial.)
The code to achieve this is:
// CarryDropModel
package demo;
import java.awt.Color;
import java.util.ArrayList;
import uchicago.src.sim.engine.BasicAction;
import uchicago.src.sim.engine.Schedule;
import uchicago.src.sim.engine.SimInit;
import uchicago.src.sim.engine.SimModelImpl;
import uchicago.src.sim.gui.DisplaySurface;
import uchicago.src.sim.gui.ColorMap;
import uchicago.src.sim.gui.Object2DDisplay;
import uchicago.src.sim.gui.Value2DDisplay;
import uchicago.src.sim.util.SimUtilities;
public class CarryDropModel extends SimModelImpl {
// Default Values
private static final int NUMAGENTS = 100;
private static final int WORLDXSIZE = 40;
private static final int WORLDYSIZE = 40;
private static final int TOTALMONEY = 1000;
private static final int AGENT_MIN_LIFESPAN = 30;
private static final int AGENT_MAX_LIFESPAN = 50;
private int numAgents = NUMAGENTS;
private int worldXSize = WORLDXSIZE;
private int worldYSize = WORLDYSIZE;
private int money = TOTALMONEY;
private int agentMinLifespan = AGENT_MIN_LIFESPAN;
private int agentMaxLifespan = AGENT_MAX_LIFESPAN;
private Schedule schedule;
private CarryDropSpace cdSpace;
private ArrayList agentList;
private DisplaySurface displaySurf;
public String getName(){
return "Carry And Drop";
}
public void setup(){
System.out.println("Running setup");
cdSpace = null;
agentList = new ArrayList();
schedule = new Schedule(1);
if (displaySurf != null){
displaySurf.dispose();
}
displaySurf = null;
displaySurf = new DisplaySurface(this, "Carry Drop Model Window 1");
registerDisplaySurface("Carry Drop Model Window 1", displaySurf);
}
public void begin(){
buildModel();
buildSchedule();
buildDisplay();
displaySurf.display();
}
public void buildModel(){
System.out.println("Running BuildModel");
cdSpace = new CarryDropSpace(worldXSize, worldYSize);
cdSpace.spreadMoney(money);
for(int i = 0; i < numAgents; i++){
addNewAgent();
}
for(int i = 0; i < agentList.size(); i++){
CarryDropAgent cda = (CarryDropAgent)agentList.get(i);
cda.report();
}
}
public void buildSchedule(){
System.out.println("Running BuildSchedule");
class CarryDropStep extends BasicAction {
public void execute() {
SimUtilities.shuffle(agentList);
for(int i =0; i < agentList.size(); i++){
CarryDropAgent cda = (CarryDropAgent)agentList.get(i);
cda.step();
}
}
}
schedule.scheduleActionBeginning(0, new CarryDropStep());
}
public void buildDisplay(){
System.out.println("Running BuildDisplay");
ColorMap map = new ColorMap();
for(int i = 1; i<16; i++){
map.mapColor(i, new Color((int)(i * 8 + 127), 0, 0));
}
map.mapColor(0, Color.white);
Value2DDisplay displayMoney =
new Value2DDisplay(cdSpace.getCurrentMoneySpace(), map);
Object2DDisplay displayAgents = new Object2DDisplay(cdSpace.getCurrentAgentSpace());
displayAgents.setObjectList(agentList);
displaySurf.addDisplayable(displayMoney, "Money");
displaySurf.addDisplayable(displayAgents, "Agents");
}
private void addNewAgent(){
CarryDropAgent a = new CarryDropAgent(agentMinLifespan, agentMaxLifespan);
agentList.add(a);
cdSpace.addAgent(a);
}
public Schedule getSchedule(){
return schedule;
}
public String[] getInitParam(){
String[] initParams = { "NumAgents", "WorldXSize", "WorldYSize", "Money", "AgentMinLifespan", "AgentMaxLifespan"};
return initParams;
}
public int getNumAgents(){
return numAgents;
}
public void setNumAgents(int na){
numAgents = na;
}
public int getWorldXSize(){
return worldXSize;
}
public void setWorldXSize(int wxs){
worldXSize = wxs;
}
public int getWorldYSize(){
return worldYSize;
}
public void setWorldYSize(int wys){
worldYSize = wys;
}
public int getMoney() {
return money;
}
public void setMoney(int i) {
money = i;
}
public int getAgentMaxLifespan() {
return agentMaxLifespan;
}
public int getAgentMinLifespan() {
return agentMinLifespan;
}
public void setAgentMaxLifespan(int i) {
agentMaxLifespan = i;
}
public void setAgentMinLifespan(int i) {
agentMinLifespan = i;
}
public static void main(String[] args) {
SimInit init = new SimInit();
CarryDropModel model = new CarryDropModel();
init.loadModel(model, "", false);
}
}
// CarryDropAgent
package demo;
import java.awt.Color;
import uchicago.src.sim.gui.Drawable;
import uchicago.src.sim.gui.SimGraphics;
public class CarryDropAgent implements Drawable{
private int x;
private int y;
private int money;
private int stepsToLive;
private static int IDNumber = 0;
private int ID;
public CarryDropAgent(int minLifespan, int maxLifespan){
x = -1;
y = -1;
money = 0;
stepsToLive =
(int)((Math.random() * (maxLifespan - minLifespan)) + minLifespan);
IDNumber++;
ID = IDNumber;
}
public void setXY(int newX, int newY){
x = newX;
y = newY;
}
public String getID(){
return "A-" + ID;
}
public int getMoney(){
return money;
}
public int getStepsToLive(){
return stepsToLive;
}
public void report(){
System.out.println(getID() +
" at " +
x + ", " + y +
" has " +
getMoney() + " dollars" +
" and " +
getStepsToLive() + " steps to live.");
}
public int getX(){
return x;
}
public int getY(){
return y;
}
public void draw(SimGraphics G){
G.drawFastRoundRect(Color.blue);
}
public void step(){
stepsToLive--;
}
}
// CarryDropSpace
package demo;
import uchicago.src.sim.space.Object2DGrid;
public class CarryDropSpace {
private Object2DGrid moneySpace;
private Object2DGrid agentSpace;
public CarryDropSpace(int xSize, int ySize){
moneySpace = new Object2DGrid(xSize, ySize);
agentSpace = new Object2DGrid(xSize, ySize);
for(int i = 0; i < xSize; i++){
for(int j = 0; j < ySize; j++){
moneySpace.putObjectAt(i,j,new Integer(0));
}
}
}
public void spreadMoney(int money){
// Randomly place money in moneySpace
for(int i = 0; i < money; i++){
// Choose coordinates
int x = (int)(Math.random()*(moneySpace.getSizeX()));
int y = (int)(Math.random()*(moneySpace.getSizeY()));
// Get the value of the object at those coordinates
int currentValue = getMoneyAt(x, y);
// Replace the Integer object with another one with the new value
moneySpace.putObjectAt(x,y,new Integer(currentValue + 1));
}
}
public int getMoneyAt(int x, int y){
int i;
if(moneySpace.getObjectAt(x,y)!= null){
i = ((Integer)moneySpace.getObjectAt(x,y)).intValue();
}
else{
i = 0;
}
return i;
}
public Object2DGrid getCurrentMoneySpace(){
return moneySpace;
}
public Object2DGrid getCurrentAgentSpace(){
return agentSpace;
}
public boolean isCellOccupied(int x, int y){
boolean retVal = false;
if(agentSpace.getObjectAt(x, y)!=null) retVal = true;
return retVal;
}
public boolean addAgent(CarryDropAgent agent){
boolean retVal = false;
int count = 0;
int countLimit = 10 * agentSpace.getSizeX() * agentSpace.getSizeY();
while((retVal==false) && (count < countLimit)){
int x = (int)(Math.random()*(agentSpace.getSizeX()));
int y = (int)(Math.random()*(agentSpace.getSizeY()));
if(isCellOccupied(x,y) == false){
agentSpace.putObjectAt(x,y,agent);
agent.setXY(x,y);
retVal = true;
}
count++;
}
return retVal;
}
}
The line of code that adds the inner class to the schedule is worth close inspection. It is creating a new instance of that inner class to add, and it is using a particular function to add it; in our case, the function we use states the first time step in which we want the action to be taken (0); we will take a slightly different approach in the next step.
The code given above will run- it's not very exciting, but now you can step forward in time, watch the tick count rise, and get no errors.
Next: Another Schedule Example
Go to Table of Contents
A RePast Tutorial by John T. Murphy, University of Arizona & Arizona State University (contact)