001    package aima.gui.applications.search.map;
002    
003    import java.util.ArrayList;
004    
005    import aima.gui.framework.AgentAppController;
006    import aima.gui.framework.AgentAppFrame;
007    import aima.gui.framework.AgentAppModel;
008    import aima.gui.framework.SimpleAgentAppDemo;
009    import aima.search.framework.SearchFactory;
010    import aima.search.map.AdaptableHeuristicFunction;
011    import aima.search.map.ExtendableMap;
012    import aima.search.map.MapAgent;
013    import aima.search.map.MapEnvironment;
014    import aima.search.map.Point2D;
015    import aima.search.map.Scenario;
016    import aima.search.map.SimplifiedRoadMapOfAustralia;
017    import aima.search.map.SimplifiedRoadMapOfPartOfRomania;
018    
019    /**
020     * Demo example of a route planning agent application with GUI. The main method
021     * starts a map agent frame and supports runtime experiments. This
022     * implementation is based on the {@link aima.search.map.MapAgent} and the
023     * {@link aima.search.map.MapEnvironment}. It can be used
024     * as a code template for creating new applications with different specialized
025     * kinds of agents and environments.
026     * 
027     * @author R. Lunde
028     */
029    public class RoutePlanningAgentAppDemo extends SimpleAgentAppDemo {
030    
031            /** Creates a <code>MapAgentModel</code>. */
032            @Override
033            public AgentAppModel createModel() {
034                    return new MapAgentModel();
035            }
036    
037            /** Creates and configures a <code>RoutePlanningAgentFrame</code>. */
038            @Override
039            public AgentAppFrame createFrame() {
040                    return new RoutePlanningAgentFrame();
041            }
042    
043            /** Creates a <code>RoutePlanningAgentController</code>. */
044            @Override
045            public AgentAppController createController() {
046                    return new RoutePlanningAgentController();
047            }
048    
049            // //////////////////////////////////////////////////////////
050            // local classes
051    
052            /** Frame for a graphical route planning agent application. */
053            protected static class RoutePlanningAgentFrame extends MapAgentFrame {
054                    public static enum MapType {
055                            ROMANIA, AUSTRALIA
056                    };
057    
058                    private MapType usedMap = null;
059                    private static String[] ROMANIA_DESTS = new String[] {
060                                    "D1 (to Bucharest)", "D2 (to Eforie)", "D3 (to Neamt)",
061                                    "D4 (to random)" };
062                    private static String[] AUSTRALIA_DESTS = new String[] {
063                                    "D1 (to Port Hedland)", "D2 (to Albany)", "D3 (to Melbourne)",
064                                    "D4 (to random)" };
065    
066                    /** Creates a new frame. */
067                    public RoutePlanningAgentFrame() {
068                            setTitle("RPA - the Route Planning Agent");
069                            setSelectorItems(SCENARIO_SEL, new String[] {
070                                            "S1 (Romania, from Arad)", "S2 (Romania, from Lugoj)",
071                                            "S3 (Romania, from Fagaras)",
072                                            "S4 (Australia, from Sydney)",
073                                            "S4 (Australia, from Random)" }, 0);
074                            setSelectorItems(SEARCH_MODE_SEL, SearchFactory.getInstance()
075                                            .getSearchModeNames(), 1); // change the default!
076                            setSelectorItems(HEURISTIC_SEL, new String[] { "H1 (=0)",
077                                            "H2 (sld to goal)" }, 1);
078                    }
079    
080                    /**
081                     * Changes the destination selector items depending on the scenario
082                     * selection if necessary, and calls the super class implementation
083                     * afterwards.
084                     */
085                    @Override
086                    protected void selectionChanged() {
087                            SelectionState state = getSelection();
088                            int scenarioIdx = state.getValue(MapAgentFrame.SCENARIO_SEL);
089                            RoutePlanningAgentFrame.MapType mtype = (scenarioIdx < 3) ? MapType.ROMANIA
090                                            : MapType.AUSTRALIA;
091                            if (mtype != usedMap) {
092                                    usedMap = mtype;
093                                    String[] items = null;
094                                    switch (mtype) {
095                                    case ROMANIA:
096                                            items = ROMANIA_DESTS;
097                                            break;
098                                    case AUSTRALIA:
099                                            items = AUSTRALIA_DESTS;
100                                            break;
101                                    }
102                                    setSelectorItems(DESTINATION_SEL, items, 0);
103                            }
104                            super.selectionChanged();
105                    }
106            }
107    
108            /** Controller for a graphical route planning agent application. */
109            protected static class RoutePlanningAgentController extends
110                            AbstractMapAgentController {
111                    /**
112                     * Configures a scenario and a list of destinations. Note that for route
113                     * planning problems, the size of the list needs to be 1.
114                     */
115                    @Override
116                    protected void selectScenarioAndDest(int scenarioIdx, int destIdx) {
117                            ExtendableMap map = new ExtendableMap();
118                            MapEnvironment env = new MapEnvironment(map);
119                            String agentLoc = null;
120                            switch (scenarioIdx) {
121                            case 0:
122                                    SimplifiedRoadMapOfPartOfRomania.initMap(map);
123                                    agentLoc = SimplifiedRoadMapOfPartOfRomania.ARAD;
124                                    break;
125                            case 1:
126                                    SimplifiedRoadMapOfPartOfRomania.initMap(map);
127                                    agentLoc = SimplifiedRoadMapOfPartOfRomania.LUGOJ;
128                                    break;
129                            case 2:
130                                    SimplifiedRoadMapOfPartOfRomania.initMap(map);
131                                    agentLoc = SimplifiedRoadMapOfPartOfRomania.FAGARAS;
132                                    break;
133                            case 3:
134                                    SimplifiedRoadMapOfAustralia.initMap(map);
135                                    agentLoc = SimplifiedRoadMapOfAustralia.SYDNEY;
136                                    break;
137                            case 4:
138                                    SimplifiedRoadMapOfAustralia.initMap(map);
139                                    agentLoc = map.randomlyGenerateDestination();
140                                    break;
141                            }
142                            scenario = new Scenario(env, map, agentLoc);
143    
144                            destinations = new ArrayList<String>();
145                            if (scenarioIdx < 3) {
146                                    switch (destIdx) {
147                                    case 0:
148                                            destinations
149                                                            .add(SimplifiedRoadMapOfPartOfRomania.BUCHAREST);
150                                            break;
151                                    case 1:
152                                            destinations.add(SimplifiedRoadMapOfPartOfRomania.EFORIE);
153                                            break;
154                                    case 2:
155                                            destinations.add(SimplifiedRoadMapOfPartOfRomania.NEAMT);
156                                            break;
157                                    case 3:
158                                            destinations.add(map.randomlyGenerateDestination());
159                                            break;
160                                    }
161                            } else {
162                                    switch (destIdx) {
163                                    case 0:
164                                            destinations.add(SimplifiedRoadMapOfAustralia.PORT_HEDLAND);
165                                            break;
166                                    case 1:
167                                            destinations.add(SimplifiedRoadMapOfAustralia.ALBANY);
168                                            break;
169                                    case 2:
170                                            destinations.add(SimplifiedRoadMapOfAustralia.MELBOURNE);
171                                            break;
172                                    case 3:
173                                            destinations.add(map.randomlyGenerateDestination());
174                                            break;
175                                    }
176                            }
177                    }
178    
179                    /**
180                     * Prepares the model for the previously specified scenario and
181                     * destinations.
182                     */
183                    @Override
184                    protected void prepareModel() {
185                            ((MapAgentModel) model).prepare(scenario, destinations);
186                    }
187    
188                    /**
189                     * Returns the trivial zero function or a simple heuristic which is
190                     * based on straight-line distance computation.
191                     */
192                    @Override
193                    protected AdaptableHeuristicFunction createHeuristic(int heuIdx) {
194                            switch (heuIdx) {
195                            case 0:
196                                    return new H1();
197                            default:
198                                    return new H2();
199                            }
200                    }
201    
202                    /**
203                     * Creates environment and agent, starts the agent and initiates some
204                     * text outputs describing the state of the agent.
205                     */
206                    @Override
207                    protected void startAgent() {
208                            if (destinations.size() != 1) {
209                                    frame.logMessage("Error: This agent requires exact one destination.");
210                                    return;
211                            }
212                            frame.logMessage("<route-planning-simulation-protocol>");
213                            frame.logMessage("search: " + search.getClass().getName());
214                            MapEnvironment env = scenario.getEnv();
215                            String goal = destinations.get(0);
216                            MapAgent agent = new MapAgent(env, search, new String[] { goal });
217                            if (heuristic != null) {
218                                    frame
219                                                    .logMessage("heuristic: "
220                                                                    + heuristic.getClass().getName());
221                                    agent.setHeuristicFunction(heuristic.getAdaptation(goal,
222                                                    scenario.getAgentMap()));
223                            }
224                            env.addAgent(agent, scenario.getInitAgentLocation());
225                            env.stepUntilDone();
226                            frame.logMessage("</route-planning-simulation-protocol>\n");
227                    }
228            }
229    
230            /**
231             * Returns always the heuristic value 0.
232             */
233            static class H1 extends AdaptableHeuristicFunction {
234    
235                    public double getHeuristicValue(Object state) {
236                            return 0.0;
237                    }
238            }
239    
240            /**
241             * A simple heuristic which interprets <code>state</code> and
242             * {@link #goal} as location names and uses the straight-line distance
243             * between them as heuristic value.
244             */
245            static class H2 extends AdaptableHeuristicFunction {
246    
247                    public double getHeuristicValue(Object state) {
248                            double result = 0.0;
249                            Point2D pt1 = map.getPosition((String) state);
250                            Point2D pt2 = map.getPosition((String) goal);
251                            if (pt1 != null && pt2 != null)
252                                    result = pt1.distance(pt2);
253                            return result;
254                    }
255            }
256    
257            // //////////////////////////////////////////////////////////
258            // starter method
259    
260            /** Application starter. */
261            public static void main(String args[]) {
262                    new RoutePlanningAgentAppDemo().startApplication();
263            }
264    }