Agent-Based Simulations
The main purpose of this project is to give you an opportunity to use your linked list within the context of an agent-based simulation.
In this week's simulation, we will have Agents that are on a 2D landscape. They will have positions in a continuous (floating point) 2D space, rather than the grid from the Game of Life. Like in the Game of Life, the agents are active and will implement an updateState method.
The Agent-based simulations were inspired by Growing Artificial Societies by Epstein and Axtell, two of the first researchers to make use computational modeling to examine social science questions about self-organizing societies.
Project Checklist: Before submitting your project, make sure you have completed all of the following!
- All of the coding work listed under tasks
- Your report describing the work you did in the project
- Your extensions should you choose to do any
Tasks
Agent Class
Create an abstract class called Agent. The simulations will require making two forms of agents with different updateState() methods. This is an ideal situation for using inheritance, which means starting with a base class: the Agent class.
The Agent class needs fields to store its x and y position. Use type double for the agent's position. It also needs an int field named radius that stores the radius within which the agent considers another agent a neighbor, and a boolean field named moved to store whether it changed position at the last call of updateState. The radius and moved fields should have a protected access modifier, not private! Feel free to try both options and see what happens when you try to access the radius/moved field in the SocialAgent class.
The Agent class should implement the following methods:
public Agent(double x0, double y0, int radius)a constructor that sets the position.public double getX()returns the x position.public double getY()returns the y position.public int getRadius()returns the radius.public boolean getMoved()returns the moved field.public void setX( double newX )sets the x position.public void setY( double newY )sets the y position.public void setRadius( int newRadius )sets the radius.public String toString()returns a String containing the x and y positions, e.g. "(3.024, 4.245)".public abstract void updateState( Landscape scape )does nothing, for now.public abstract void draw(Graphics g)does nothing, for now.
Testing agents: Once you have done the steps under SocialAgent and AntiSocialAgent below, complete and use this test code: AgentTests.java to evaluate the correctness of your implementation. Take a look at last week's tester for your Cell class to use as a model. This is what the autograder does to check your code.
SocialAgent
Create a (non abstract) SocialAgent class. The first agent we will implement will ultimately move towards other agents, creating groups of agents. SocialAgent will extend the Agent class. More information about inheritance.
The new class will need to override the constructor, and draw methods:
public SocialAgent(double x0, double y0, int radius)The constructor, which calls the super class constructor and sets the radius field. Remember to set all your class fields to some value by the end of the constructor!public SocialAgent(double x0, double y0, int radius) { super( x0, y0 , radius ); // remainder of constructor code }public void draw(Graphics g)draws a circle of radius 5 (i.e. it fits in a 10x10 box) at the Agent's location. If the agent moved during the last updateState, it is drawn with a lighter shade of blue, otherwise a darker shade of blue.public void draw(Graphics g){ if(!moved) g.setColor(new Color(0, 0, 255)); else g.setColor(new Color(125, 125, 255)); g.fillOval((int) getX(), (int) getY(), 5, 5); }public void updateState(Landscape scape)for now, leave this blank.
AntiSocialAgent
Create an AntiSocialAgent class. As opposed to SocialAgents, AntiSocialAgents try to move away from groups of Agents. AntiSocialAgent will also extend the Agent class.
The new class will need to override the constructor, and draw methods:
public AntiSocialAgent(double x0, double y0, int radius)The constructor, which calls the super class constructor and sets the radius field. Remember to set all your class fields to some value by the end of the constructor!public AntiSocialAgent(double x0, double y0, int radius) { super( x0, y0 , radius ); // remainder of constructor code }public void draw(Graphics g)draws a circle of radius 5 (i.e. it fits in a 10x10 box) at the Agent's location. If the agent moved during the last updateState, it is drawn with a lighter shade of red, otherwise a darker shade of red.public void draw(Graphics g){ if(!moved) g.setColor(new Color(255, 0, 0)); else g.setColor(new Color(255, 125, 125)); g.fillOval((int) getX(), (int) getY(), 5, 5); }public void updateState(Landscape scape)for now, leave this blank.
Landscape
Create a class called Landscape. It serves the same purpose as the Landscape in the Game of Life simulation, but is different enough that you probably don't want to copy the old one and edit it. Start with a new file. The Landscape will need fields to store its width and height (as ints) and a LinkedList of Agents. Use your implementation of a linked list. The Landscape needs the following methods:
public Landscape(int w, int h)a constructor that sets the width and height fields, and initializes the agent list.public int getHeight()returns the height.public int getWidth()returns the width.public void addAgent( Agent a )inserts an agent at the beginning of its list of agents.public String toString()returns a String representing the Landscape. It can be as simple as indicating the number of Agents on the Landscape.public LinkedList<Agent> getNeighbors(double x0, double y0, double radius)returns a list of the Agents within radius distance of the location x0, y0.public void draw(Graphics g)Calls the draw method of all the agents on the Landscape.
Testing Landscape: Once you have done the steps above, complete and use this test code: LandscapeTests.java to evaluate the correctness of your implementation. Take a look at last week's tester for your Landscape class to use as a model. This is what the autograder does to check your code.
Visualization
Make it possible to visualize your Landscape. Download the LandscapeDisplay.java file. It is almost identical to last week.
Test your visualization by running LandscapeDisplay as your main program. The main program adds 200 agents to the Landscape and then displays them.
updateState( )
Add a method to your SocialAgent class, public void updateState(Landscape scape).
If there are less than 4 agents within its own radius from itself, it changes both its x and y coordinates
by a random value between -10 and 10. Make sure that it stays within the boundary of the window!
To your AntiSocialAgent class, add an analagous method that would move the Agent if there is more than 1 neighbor within its radius.
As you code this function, if the (Anti/)SocialAgent moves, set the moved field to true, otherwise set it to false.
Testing UpdateState: Once you have done the steps above, complete and use this test code: UpdateStateTests.java to evaluate the correctness of your implementation. This is what the autograder does to check your code.
updateAgents( )
Add a method to your Landscape class, public int updateAgents(). The method should do the
following 3 things, then return the number of agents that moved during the update.
- Randomly select an agent from the list and store its x and y coordinates and its radius. Then delete the agent from the linked list of agents.
- Make a new AntiSocialAgent and give it the x and y coordinates and the radius of the deleted agent. Add it to the linked list of agents.
- Update the state of each agent in the linked list, in whatever order you'd like. Track how many of the agents moved.
Testing AgentSimulation: Once you have done the steps above and the AgentSimulation steps below, complete and use this test code: AgentSimulationTests.java to evaluate the correctness of your implementation. This is what the autograder does to check your code.
AgentSimulation
Create an AgentSimulation class. It should be loosely modeled after the LifeSimulation class. Write the code to run the following experiment in a method with this signature: public static int runExpt(int N). N is the initial number of SocialAgents and should be input into LifeSimulation as a command line parameter.
In runExpt, generate and randomly place N SocialAgents with radius 25 on a Landscape of size 500 by 500.
Create a loop that runs while the number of agents who have moved in the last time step is greater than zero
and your loop has been running for less than 5000 iterations. (Hint: you'll want to create a variable to track the number of
agents moved in the last step and set it to a non-zero value for the first iteration. you'll also need to
track to number of iterations of the loop).
Inside the loop, call updateAgents and store the number of agents moved during the update. Then call repaint, and Thread.sleep as in LifeSimulation. At the end of your method, return how many times your for loop ran.
Exploration
Required Element 1:Run experiments with the number of agents set to 50, 100, 150, 200 and 250. Record the number of iterations it takes for your simulation to stop (if it takes 5000 iterations, you can assume it timed out and put that as your result). Make a table of the number of iterations it takes the agents to stop moving by the number of agents in the simulation. Discuss the trends you see.
Required Element 2:Make a second table, graph or video based on a set of experiments of your choice. Include it in your report and clearly describe what the experiment was (e.g. how many agents, what was the radius size, what was the grid size). Discuss the trends you see.
Extensions
Please submit your extensions in a separate folder from your main project! We recommend that, once you finish the project, you copy all of your files into a separate extensions subfolder and work on your extensions there. As last week, these are only recommendations and you can choose from these ideas or develop your own. Any extension you take must be adequately detailed in your report.- Try creating other agent types that implement different rule sets. Be intentional about your agent design. (Up to 3 points for a substantially new agent, and 1 additional point if you do a thorough experimental evaluation)
- Instead of moving randomly, have your agent move towards other agents, or possibly towards some and away from others. (Up to 3 points, and 1 additional point if you do a thorough experimental evaluation)
- Experiment with the effects of modifying some of the update rules. These should be compare and contrast. Try to avoid comparing simulations where more than one thing has been changed. (2 points; must do at least 2 comparisons and a thorough experimental evaluation).
Congrats, you're done with everything except for your project report where you will communicate your findings from all that code! Make sure to write up your report in the project report file in the Google Classrooms assignment. The project report is an important part of the work in this project, so don't forget to do it!