package aima.gui.swing.applications.agent.map; import java.awt.Color; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; import aima.core.agent.Action; import aima.core.agent.Agent; import aima.core.agent.Environment; import aima.core.agent.Percept; import aima.core.environment.map.Map; import aima.core.environment.map.MapEnvironment; import aima.core.util.math.geom.shapes.Point2D; import aima.gui.swing.framework.EmptyEnvironmentView; /** * General graphical environment view implementation for map agent applications. * This view requires the used environment to be of type {@link MapEnvironment}. * All agents are tracked but only the track of the first agent is shown. * * @author Ruediger Lunde */ public class MapAgentView extends EmptyEnvironmentView { private static final long serialVersionUID = 1L; /** Stores for each agent the locations, it has already visited. */ private final Hashtable<Agent, List<String>> agentTracks = new Hashtable<Agent, List<String>>(); protected MapEnvironment getMapEnv() { return (MapEnvironment) env; } /** Returns a list of all already visited agent locations. */ public List<String> getTrack(Agent agent) { return agentTracks.get(agent); } /** Clears the list of already visited locations. */ public void clearTracks() { agentTracks.clear(); } /** * Reacts on environment changes and updates the agent tracks. */ @Override public void agentAdded(Agent agent, Environment source) { updateTracks(); super.agentAdded(agent, source); } /** * Reacts on environment changes and updates the agent tracks. The command * is always send to the message logger as string. */ @Override public void agentActed(Agent agent, Percept percept, Action command, Environment source) { MapEnvironment mEnv = getMapEnv(); String msg = ""; if (mEnv.getAgents().size() > 1) msg = "A" + mEnv.getAgents().indexOf(agent) + ": "; notify(msg + command.toString()); updateTracks(); repaint(); } /** * Clears the panel, displays the map, the current agent locations, and the * track of the first agent. */ @Override public void paintComponent(java.awt.Graphics g) { super.paintComponent(g); if (env != null) { Map map = getMapEnv().getMap(); if (!map.getLocations().isEmpty()) { updateTracks(); // safety first! java.awt.Graphics2D g2 = (java.awt.Graphics2D) g; adjustTransformation(); paintMap(g2); for (Agent a : env.getAgents()) paintTrack(g2, a); for (String loc : map.getLocations()) paintLoc(g2, loc); } } } /** Updates all tracks with respect to the current agent locations. */ protected void updateTracks() { MapEnvironment mEnv = getMapEnv(); if (mEnv != null) for (Agent a : mEnv.getAgents()) { List<String> aTrack = getTrack(a); String aLoc = mEnv.getAgentLocation(a); if (aTrack == null) { aTrack = new ArrayList<String>(); agentTracks.put(a, aTrack); } if (aTrack.isEmpty() || !aTrack.get(aTrack.size() - 1).equals(aLoc)) aTrack.add(aLoc); } } /** Returns the locations of all agents. */ protected List<String> getAgentLocs() { List<String> result = new ArrayList<String>(); MapEnvironment mEnv = getMapEnv(); for (Agent a : mEnv.getAgents()) result.add(mEnv.getAgentLocation(a)); return result; } /** * Adjusts offsets and scale so that the whole map fits on the view without * scrolling. */ private void adjustTransformation() { Map map = getMapEnv().getMap(); List<String> locs = map.getLocations(); // adjust coordinates relative to the left upper corner of the graph // area double minX = Double.POSITIVE_INFINITY; double minY = Double.POSITIVE_INFINITY; double maxX = Double.NEGATIVE_INFINITY; double maxY = Double.NEGATIVE_INFINITY; for (String loc : locs) { Point2D xy = map.getPosition(loc); if (xy.getX() < minX) minX = xy.getX(); if (xy.getY() < minY) minY = xy.getY(); if (xy.getX() > maxX) maxX = xy.getX(); if (xy.getY() > maxY) maxY = xy.getY(); } this.setBorder(20, 20, 20, 100); adjustTransformation(minX, minY, maxX, maxY); } /** * Represents roads by lines and locations by name-labeled points. */ protected void paintMap(java.awt.Graphics2D g2) { Map envMap = getMapEnv().getMap(); for (String l1 : envMap.getLocations()) { Point2D pt1 = envMap.getPosition(l1); List<String> linkedLocs = envMap.getPossibleNextLocations(l1); for (String l2 : linkedLocs) { Point2D pt2 = envMap.getPosition(l2); g2.setColor(Color.lightGray); g2.drawLine(x(pt1), y(pt1), x(pt2), y(pt2)); } } } /** The track of the agent is visualized with red lines. */ private void paintTrack(java.awt.Graphics2D g2, Agent a) { Map map = getMapEnv().getMap(); Point2D lastPt = null; g2.setColor(Color.red); for (String loc : getTrack(a)) { Point2D pt = map.getPosition(loc); if (pt != null && lastPt != null) { g2.drawLine(x(pt), y(pt), x(lastPt), y(lastPt)); } lastPt = pt; } } protected void paintLoc(java.awt.Graphics2D g2, String loc) { Map map = getMapEnv().getMap(); Point2D pt = map.getPosition(loc); if (pt != null) { int x = x(pt); int y = y(pt); String info = ""; List<String> track = new ArrayList<String>(); if (!env.getAgents().isEmpty()) // show details only for track of first agent... track = getTrack(env.getAgents().get(0)); ArrayList<Integer> list = new ArrayList<Integer>(); for (int i = 0; i < track.size(); i++) if (track.get(i).equals(loc)) list.add(i + 1); if (!list.isEmpty()) info = list.toString(); if (getAgentLocs().contains(loc)) { g2.setColor(Color.red); g2.fillOval(x - 4, y - 4, 8, 8); } if (track.contains(loc)) g2.setColor(Color.black); else g2.setColor(Color.gray); g2.drawString(loc + info, x, y); } } }