package aima.gui.swing.applications.agent.map;
import java.text.DecimalFormat;
import java.util.List;
import aima.core.agent.Agent;
import aima.core.environment.map.MapEnvironment;
import aima.core.environment.map.Scenario;
import aima.core.search.framework.SearchForActions;
import aima.core.search.framework.evalfunc.HeuristicFunction;
import aima.gui.swing.framework.AgentAppController;
import aima.gui.swing.framework.MessageLogger;
import aima.gui.swing.framework.SimulationThread;
import aima.gui.util.SearchFactory;
/**
* Provides a useful base class for agent application controller implementations
* in the context of route finding agent application development. To get it
* ready to work, all you need to do is, to provide implementations for the four
* abstract methods. See {@link RouteFindingAgentApp} for an example.
*
* @author Ruediger Lunde
*/
public abstract class AbstractMapAgentController extends AgentAppController {
/** A scenario. */
protected Scenario scenario;
/**
* Some location names. For route finding problems, only one location
* should be specified.
*/
protected List<String> destinations;
/** Search method to be used. */
protected SearchForActions search;
/** Heuristic function to be used when performing informed search. */
protected HeuristicFunction heuristic;
/** Is the scenario up to date? */
protected boolean isPrepared;
/** Sleep time between two steps during simulation in msec. */
protected long sleepTime = 500l;
/** Clears all tracks and prepares simulation if necessary. */
@Override
public void clear() {
((MapAgentView) frame.getEnvView()).clearTracks();
if (!isPrepared())
prepare(null);
}
/**
* Template method, which performs necessary preparations for running the
* agent. The behavior is strongly influenced by the primitive operations
* {@link #selectScenarioAndDest(int, int)}, {@link #prepareView()} and
* {@link #createHeuristic(int)}.
*/
@Override
public void prepare(String changedSelectors) {
MapAgentFrame.SelectionState state = frame.getSelection();
selectScenarioAndDest(state.getIndex(MapAgentFrame.SCENARIO_SEL), state
.getIndex(MapAgentFrame.DESTINATION_SEL));
prepareView();
heuristic = createHeuristic(state.getIndex(MapAgentFrame.HEURISTIC_SEL));
search = SearchFactory.getInstance().createSearch(
state.getIndex(MapAgentFrame.SEARCH_SEL),
state.getIndex(MapAgentFrame.Q_SEARCH_IMPL_SEL), heuristic);
isPrepared = true;
}
/**
* Checks whether the current scenario contains an environment which is
* ready for simulation (no agents or not done).
*/
public boolean isPrepared() {
return isPrepared && (scenario.getEnv().getAgents().isEmpty()
|| !scenario.getEnv().isDone());
}
/**
* Calls {@link #initAgents(MessageLogger)} if necessary and
* then starts simulation until done.
*/
public void run(MessageLogger logger) {
logger.log("<simulation-protocol>");
logger.log("search: " + search.getClass().getName());
if (heuristic != null)
logger.log("heuristic: " + heuristic.getClass().getName());
MapEnvironment env = scenario.getEnv();
if (env.getAgents().isEmpty())
initAgents(logger);
try {
while (!env.isDone() && !frame.simulationPaused()) {
Thread.sleep(sleepTime);
env.step();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.log("</simulation-protocol>\n");
}
/**
* Calls {@link #initAgents(MessageLogger)} if necessary and
* then executes one simulation step.
*/
@Override
public void step(MessageLogger logger) {
MapEnvironment env = scenario.getEnv();
if (env.getAgents().isEmpty())
initAgents(logger);
env.step();
}
/** Updates the status of the frame. */
public void update(SimulationThread simulationThread) {
if (simulationThread.isCanceled()) {
frame.setStatus("Task canceled.");
isPrepared = false;
} else if (frame.simulationPaused()){
frame.setStatus("Task paused.");
} else {
StringBuffer statusMsg = new StringBuffer();
statusMsg.append("Task completed");
List<Agent> agents = scenario.getEnv().getAgents();
if (agents.size() == 1) {
Double travelDistance = scenario.getEnv().getAgentTravelDistance(
agents.get(0));
if (travelDistance != null) {
DecimalFormat f = new DecimalFormat("#0.0");
statusMsg.append("; travel distance: "
+ f.format(travelDistance));
}
}
statusMsg.append(".");
frame.setStatus(statusMsg.toString());
}
}
/////////////////////////////////////////////////////////////////
// abstract methods
/**
* Primitive operation, responsible for assigning values to attributes
* {@link #scenario} and {@link #destinations}.
*/
abstract protected void selectScenarioAndDest(int scenarioIdx, int destIdx);
/**
* Primitive operation, responsible for preparing the view. Scenario and
* destinations are already selected when this method is called.
*/
abstract protected void prepareView();
/**
* Factory method, responsible for creating a heuristic function.
*/
abstract protected HeuristicFunction createHeuristic(int heuIdx);
/**
* Primitive operation, responsible for creating new agents and adding
* them to the current environment.
*/
protected abstract void initAgents(MessageLogger logger);
}