package RandomMoveInGrid; // A simple model of bugs in a 2D world. // See the Readme.txt file for details. import java.io.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Formatter; import java.awt.Point; import uchicago.src.sim.engine.Schedule; import uchicago.src.sim.engine.SimModelImpl; import uchicago.src.sim.util.*; import uchicago.src.sim.gui.*; import uchicago.src.sim.space.*; public class Model extends ModelParameters { // instance variables public int numAgents = 10; public ArrayList agentList = new ArrayList (); public Schedule schedule; public int sizeX = 20, sizeY = 20; // integer size of the world public Object2DGrid world; // 2D class from Repast public double avgAgentX; // observed avg Agent X location ///////////////////////////////////////////////////////////////////////////// // addModelSpecificParameters // add alias and long name for Model parameters you want to set at run time // the long name should be same as instance variable // // Note: the generic parameters from ModelParameters are already available. public void addModelSpecificParameters () { parametersMap.put( "X", "sizeX" ); parametersMap.put( "Y", "sizeY" ); parametersMap.put( "nA", "numAgents" ); } // control what appears in the repast parameter panel public String[] getInitParam () { String[] params = { "numAgents", "sizeX", "sizeY", // these are from the super class: "rDebug" }; return params; } //////////////////////////////////////////////////////////////////////////// // constructor, if need to do anything special. public Model () { } /////////////////////////////////////////////////////////////////////////// // setup // set defaults after a run start or restart public void setup () { if ( rDebug > 0 ) System.out.printf( "==> setup...\n" ); schedule = null; numAgents = 10; agentList = new ArrayList (); sizeX = 21; sizeY = 21; world = null; System.gc (); // garabage collection of discarded objects super.setup(); // THIS SHOULD BE CALLED after setting defaults in setup(). schedule = new Schedule (1); // create AFTER calling super.setup() if ( rDebug > 0 ) System.out.printf( "\n<=== Model-setup() done.\n" ); } /////////////////////////////////////////////////////////////////////////// // buildModel // We build the "conceptual" parts of the model. // (vs the display parts, and the schedule) // // Create a 2D world, tell the Agents about it. // Create agents, put them in the world, one per cell, // and also add them to the agentList. public void buildModel () { if ( rDebug > 0 ) System.out.printf( "==> buildModel...\n" ); // CALL FIRST -- defined in super class -- it starts RNG, etc buildModelStart(); /////////////////////////////////////////////////////////////////////// // *** Change below here -- initialization // create the 2D grid world of requested size world = new Object2DGrid( sizeX, sizeY ); // tell the Agent class about this (Model) and world Agent.setModel( this ); Agent.setWorld( world ); for ( int i = 0; i < numAgents; ++i ) { int x, y; Agent a = new Agent(); do { x = Model.getUniformIntFromTo( 0, sizeX-1 ); y = Model.getUniformIntFromTo( 0, sizeY-1 ); } while ( world.getObjectAt( x, y ) != null ); world.putObjectAt( x, y, a ); a.setX( x ); a.setY( y ); agentList.add( a ); } // *** End Change -- initialization /////////////////////////////////////////////////////////////////////// // some post-load finishing touches startReportFile(); // you probably don't want to remove any of the following // calls to process parameter changes and write the // initial state to the report file. // NB -> you might remove/add more agentChange processing applyAnyStoredChanges(); stepReport(); getReportFile().flush(); getPlaintextReportFile().flush(); if ( rDebug > 0 ) System.out.printf( "<== buildModel done.\n" ); } /////////////////////////////////////////////////////////////////////////// // step // The top of the "conceptual" model's main dynamics // Each time step (user presses Step or Run buttons...) // this is what happens. // Currently: Just tell each agent to execute its own step method! // // NB: At the end, it calls stepReport() to write to report file. public void step () { if ( rDebug > 0 ) System.out.printf( "==> Model step %.0f:\n", getTickCount() ); for ( Agent a : agentList ) a.step(); if ( rDebug > 0 ) System.out.printf( "<== Model step done.\n" ); stepReport(); } ///////////////////////////////////////////////////////////////////////////////// // stepReport // each step write out: // timeStep ...data... // currently, just writes the time step numbers! public void stepReport () { String s; if ( rDebug > 0 ) System.out.printf( "==> Model stepReport %.0f:\n", getTickCount() ); // set up a string with the values to write -- start with time step s = String.format( "%5.0f ", getTickCount() ); calcAvgAgentX(); s += String.format( "%.2f", avgAgentX ); // write it to the xml and plain text report files writeLineToReportFile ( "" + s + "" ); writeLineToPlaintextReportFile( s ); // flush the buffers so the data is not lost in a "crash" getReportFile().flush(); getPlaintextReportFile().flush(); } // calcAvgAgentX // calculate the average agent X location, store in iv. public double calcAvgAgentX () { avgAgentX = 0.0; for ( Agent a : agentList ) avgAgentX += a.getX(); if ( agentList.size() > 1 ) avgAgentX /= agentList.size(); if ( rDebug > 0 ) System.out.printf( "calcAvgAgentX at t=%.0f -> %.3f\n", getTickCount(), avgAgentX ); return avgAgentX; } // writeHeaderCommentsToReportFile // customize to match what you are writing to the report files in stepReport. public void writeHeaderCommentsToReportFile () { writeLineToReportFile( "" ); writeLineToReportFile( " " ); writeLineToReportFile( " time avgAgX " ); writeLineToReportFile( "" ); writeLineToPlaintextReportFile( "# avg " ); writeLineToPlaintextReportFile( "# time AngtX " ); } ////////////////////////////////////////////////////////////////////////////////// // printProjectHelp // this could be filled in with some help to get from running with -help parameter public void printProjectHelp() { // print project help System.out.printf( "\n%s -- RandomMoveInGrid \n", getName() ); System.out.printf( "\nAgents just move randomly in a 2D bounded discrte grid. \n" ); System.out.printf( "Each step, agents picks a random dx,dy move to make\n" ); System.out.printf( "within +1/-1 of its current location.\n" ); System.out.printf( "It tries to make the move, but may fail because:\n" ); System.out.printf( "- tried to move off edge of world\n" ); System.out.printf( "- tried to move to a cell with an agent in it\n" ); System.out.printf( "If it can't move, it does nothing that step.\n" ); System.out.printf( "\n" ); System.out.printf( "Settable Parameterts:\n" ); System.out.printf( " SizeX, SizeY -- world size\n" ); System.out.printf( " numAgents -- number of agents to create in that world.\n" ); System.out.printf( "\n" ); System.out.printf( "To compile: bin/compile.sh\n" ); System.out.printf( "or try this to get warnings:\n" ); System.out.printf( " bin/compile.sh -Xlint:unchecked\n" ); System.out.printf( "Note there are a lot from ModelParameters.java that are ok.\n" ); System.out.printf( "\n" ); System.out.printf( "To run:\n" ); System.out.printf( " bin/guirun.sh\n" ); System.out.printf( " bin/guirun.sh X=50 Y=50 nA=400\n" ); System.out.printf( " bin/batchrun.sh T=500 X=50 Y=50 nA=400\n" ); System.out.printf( "\n" ); printParametersMap(); System.exit( 0 ); } /////////////////////////////////////////////////////////////////////////////// // moveObjectInWorld // try to move object to the requested dx,dy . // note we must check to be sure the new location is "legal", // i.e., cell is empty and cell is not off the edge of the world. // NB: if either new* values is illegal, don't move. // If move is ok: // - tell the world the object is not where it was // - tell the world the object is now at the new* location // Return: null if not moved, otherwise return a Point object // with new x,y values. // public Point moveObjectInWorld ( Drawable obj, int dX, int dY ) { int newX = obj.getX() + dX; // get location it wants to move to int newY = obj.getY() + dY; // first check to be sure new location is in the world! if ( newX < 0 || newY < 0 || newX >= sizeX || newY >= sizeY ) { if ( rDebug > 0 ) System.out.printf( " - obj tried to move offworld (%d,%d).\n", newX, newY ); return null; } // see if new cell is empty. if ( world.getObjectAt( newX, newY ) != null ) { if ( rDebug > 0 ) System.out.printf( " - obj tried to move to occupied cell (%d,%d).\n", newX, newY ); return null; } // its ok to move, so tell the world and the object world.putObjectAt( obj.getX(), obj.getY(), null ); // old cell empty now world.putObjectAt( newX, newY, obj ); // obj in new cell now Point loc = new Point( newX, newY ); return loc; } ////////////////////////////////////////////////////////////////////////////// public Schedule getSchedule () { return schedule; } public String getName () { return "Model"; } // setters and getters // notes: // - we use the schedule != null to indicated model has been initialized // - some things can't be changed after model initialization // (which things just depends on how the model is implemented) // - if we set something after model initialization, // we need to write an change entry to the report file. // - some things need to send messages to update class variables. // // NOTE: if you want changes a user makes to parameter like numBugs // to be used after a restart (vs going back to defaults), // you probably have to change setup() to not reinitialize IVs. public int getNumAgents () { return numAgents; } public void setNumAgents (int numAgents) { this.numAgents = numAgents; if ( schedule != null ) { System.err.printf("\nCan't change numAgents mid-run.\n"); System.err.printf("\nChange will not take effect until re-init.\n"); } } public int getSizeX () { return sizeX; } public void setSizeX (int sizeX) { this.sizeX = sizeX; if ( schedule != null ) { System.err.printf("\nCan't change sizeX mid-run.\n"); System.err.printf( "\nChange will not take effect until re-init.\n" ); } } public int getSizeY () { return sizeY; } public void setSizeY (int sizeY) { this.sizeY = sizeY; if ( schedule != null ) { System.err.printf("\nCan't change sizeY mid-run.\n"); System.err.printf( "\nChange will not take effect until re-init.\n" ); } } ///////////////////////////////////////////////////////////////////////////// // processEndOfRun // called once, at end of run. // writes some final info, closes report files, etc. public void processEndOfRun ( ) { if ( rDebug > 0 ) System.out.printf("\n\n===== processEndOfRun =====\n\n" ); applyAnyStoredChanges(); endReportFile(); this.fireStopSim(); } }