Source of Maze.java


  1: 
  2: package maze; 
  3: 
  4: import java.util.Stack;
  5: import java.util.List;
  6: import java.util.ArrayList;
  7: import java.awt.*;
  8: import java.awt.event.*;
  9: import javax.swing.*;
 10: 
 11: public class Maze implements Cloneable { 
 12: 
 13:   public Object clone() throws CloneNotSupportedException { 
 14:     return super.clone();
 15:   }
 16: 
 17:   public void addRoom(Room room) { 
 18:     if (room != null) { 
 19:       rooms.add(room); 
 20:     }
 21:   }
 22: 
 23:   public Room findRoom(int roomNumber) { 
 24:     for (int i = 0; i < rooms.size(); i++) { 
 25:       Room room = (Room) rooms.get(i);
 26:       if (roomNumber == room.getRoomNumber()) { 
 27:         return room; 
 28:       }
 29:     }
 30:     return null;
 31:   }
 32: 
 33:   public void setCurrentRoom(int roomNumber) { 
 34:     Room room = findRoom(roomNumber);
 35:     setCurrentRoom(room);
 36:   }
 37: 
 38:   public void setCurrentRoom(Room room) {     
 39:     if (room != curRoom) { 
 40:       if (curRoom != null) { 
 41:         curRoom.setInRoom(false);
 42:       }
 43:       if (room != null) {       
 44:         room.setInRoom(true);
 45:         curRoom = room;
 46:       }
 47:       if (view != null) { 
 48:         view.repaint();
 49:       }
 50:     }
 51:   }
 52: 
 53:   public Room getCurrentRoom() {
 54:     return curRoom; 
 55:   }
 56:   
 57:   public void move(Direction direction) {
 58:     if (curRoom != null) { 
 59:       MapSite side = curRoom.getSide(direction); 
 60:       if (side != null) {
 61:         side.enter(this); 
 62:       }
 63:     }
 64:   }
 65: 
 66:   public void draw(Graphics g) { 
 67:     if (dim == null) { 
 68:       calculateDimension(); 
 69:     }    
 70:     int dx = MARGIN + -offset.x * ROOM_SIZE; 
 71:     int dy = MARGIN + -offset.y * ROOM_SIZE; 
 72: 
 73:     if (debug) { 
 74:       System.out.println("Maze.Draw(): offset=" + offset.x + ", " + offset.y);
 75:     }
 76: 
 77:     // draw rooms first
 78:     for (int i = 0; i < rooms.size(); i++) { 
 79:       Room room = (Room) rooms.get(i);
 80:       if (room != null) { 
 81:         Point location = room.getLocation(); 
 82:         if (location != null) { 
 83: 
 84:           if (debug) { 
 85:             System.out.println("Maze.Draw(): Room " + room.getRoomNumber() + 
 86:                                " location: " + location.x + ", " + location.y); 
 87:           }
 88: 
 89:           room.draw(g,
 90:                     dx + location.x * ROOM_SIZE,
 91:                     dy + location.y * ROOM_SIZE, 
 92:                     ROOM_SIZE, ROOM_SIZE);
 93:         }
 94:       }
 95:     }
 96:     // draw walls and doors
 97:     for (int i = 0; i < rooms.size(); i++) { 
 98:       Room room = (Room) rooms.get(i);
 99:       if (room != null) { 
100:         Point location = room.getLocation(); 
101:         if (location != null) {
102:           for (Direction dir = Direction.first(); dir != null; dir = dir.next()) { 
103:             MapSite side = room.getSide(dir); 
104:             if (side != null) { 
105:               if (dir == Direction.NORTH) {
106:                 side.draw(g,
107:                           dx + location.x * ROOM_SIZE - WALL_THICKNESS / 2,
108:                           dy + location.y * ROOM_SIZE - WALL_THICKNESS / 2,
109:                           ROOM_SIZE + WALL_THICKNESS, 
110:                           WALL_THICKNESS); 
111:               } else if (dir == Direction.EAST) { 
112:                 side.draw(g,
113:                           dx + location.x * ROOM_SIZE + ROOM_SIZE - WALL_THICKNESS / 2,
114:                           dy + location.y * ROOM_SIZE - WALL_THICKNESS / 2,
115:                           WALL_THICKNESS, 
116:                           ROOM_SIZE + WALL_THICKNESS); 
117:               } else if (dir == Direction.SOUTH) { 
118:                 side.draw(g,
119:                           dx + location.x * ROOM_SIZE - WALL_THICKNESS / 2,
120:                           dy + location.y * ROOM_SIZE + ROOM_SIZE - WALL_THICKNESS / 2,
121:                           ROOM_SIZE + WALL_THICKNESS, 
122:                           WALL_THICKNESS); 
123:               } else {
124:                 side.draw(g,
125:                           dx + location.x * ROOM_SIZE - WALL_THICKNESS / 2,
126:                           dy + location.y * ROOM_SIZE - WALL_THICKNESS / 2,
127:                           WALL_THICKNESS, 
128:                           ROOM_SIZE + WALL_THICKNESS); 
129:               }
130:             }
131:           }
132:         }
133:       } 
134:     }
135:   }
136: 
137:   public Dimension getDimension() { 
138:     if (dim == null) { 
139:       calculateDimension(); 
140:     }
141:     return dim; 
142:   }
143: 
144:   protected void calculateDimension() {
145:     if (rooms.size() > 0) { 
146:       int minX = 0, maxX = 0, minY = 0, maxY = 0; 
147:       Room room = (Room) rooms.get(0); 
148:       room.setLocation(new Point(0, 0)); 
149:       boolean changed = true; 
150:       while (changed && 
151:              !isAllRoomsSet()) { 
152:         changed = false; 
153:         for (int i = 0; i < rooms.size(); i++) { 
154:           room = (Room) rooms.get(i);
155:           Point location = room.getLocation();
156:           if (location != null) {
157:             for (Direction dir = Direction.first(); dir != null; dir = dir.next()) { 
158:               MapSite side = room.getSide(dir); 
159:               if (side instanceof Door) { 
160:                 Door door = (Door) side;
161:                 Room otherSide = door.otherSideFrom(room); 
162:                 if (otherSide != null && 
163:                     otherSide.getLocation() == null) { 
164:                   if (dir == Direction.NORTH) {                 
165:                     otherSide.setLocation(new Point(location.x, location.y - 1)); 
166:                     minY = Math.min(minY, location.y - 1);
167:                   } else if (dir == Direction.EAST) { 
168:                     otherSide.setLocation(new Point(location.x + 1, location.y)); 
169:                     maxX = Math.max(maxX, location.x + 1);
170:                   } else if (dir == Direction.SOUTH) { 
171:                     otherSide.setLocation(new Point(location.x, location.y + 1)); 
172:                     maxY = Math.max(maxY, location.y + 1);
173:                   } else {
174:                     otherSide.setLocation(new Point(location.x - 1, location.y)); 
175:                     minX = Math.min(minX, location.x - 1);
176:                   }
177:                   changed = true; 
178:                 }
179:               }
180:             }
181:           }
182:         }
183:       }
184:       offset = new Point(minX, minY); 
185:       dim = new Dimension(maxX - minX + 1, maxY - minY + 1); 
186:     } else { 
187:       offset = new Point(0, 0); 
188:       dim = new Dimension(0, 0); 
189:     }
190:   }
191: 
192:   protected boolean isAllRoomsSet() { 
193:     for (int i = 0; i < rooms.size(); i++) { 
194:       Room room = (Room) rooms.get(i);
195:       if (room.getLocation() == null) { 
196:         return false; 
197:       }
198:     }
199:     return true; 
200:   }
201: 
202:   protected void setView(Component view) { 
203:     this.view = view; 
204:   }
205: 
206:   protected void doCommand(Command command) { 
207:     if (command != null) { 
208:       moves.push(command); 
209:       command.execute();  
210:     }   
211:   }
212: 
213:   protected void undoCommand() { 
214:     if (!moves.empty()) { 
215:       Object top = moves.peek(); // looking at the top element without popping it
216:       if (top instanceof UndoableCommand) { 
217:         moves.pop();
218:         UndoableCommand undoableCommand = (UndoableCommand) top; 
219:         undoableCommand.undo();
220:       }    
221:     }
222:   }
223:   
224:   protected List rooms = new ArrayList(); 
225:   protected Dimension dim;  
226:   protected Point offset; 
227:   protected Room curRoom = null; 
228:   protected Stack moves = new Stack(); 
229: 
230:   protected Component view; 
231: 
232:   private static final int ROOM_SIZE = 40;
233:   private static final int WALL_THICKNESS = 6;
234:   private static final int MARGIN = 20; 
235: 
236:   private static final boolean debug = true; 
237: 
238:   protected void showFrame(String frameTitle) { 
239:     JFrame frame;    
240:     frame = new JFrame(frameTitle);
241:     frame.setContentPane(new Maze.MazePanel(this)); 
242:     frame.pack();
243:     Dimension frameDim = frame.getSize(); 
244:     Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
245:     frame.setLocation(screenSize.width / 2 - frameDim.width / 2, 
246:                       screenSize.height / 2 - frameDim.height / 2);    
247:     frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
248:     frame.setVisible(true);
249:   }
250: 
251:   public static class MazePanel extends JPanel { 
252:     
253:     public MazePanel(Maze maze) { 
254:       this.maze = maze; 
255:       if (maze != null) { 
256:         maze.setView(this); 
257:         Dimension d = maze.getDimension();
258:         if (d != null) { 
259:           dim = new Dimension(d.width * ROOM_SIZE + 2 * MARGIN, 
260:                               d.height * ROOM_SIZE + 2 * MARGIN);
261:         }
262:         addKeyListener(new MazeKeyListener(maze));
263:       }
264:     }
265: 
266:     public void paint(Graphics g) { 
267:       Dimension d = getSize();
268:       g.setColor(Color.white);
269:       g.fillRect(0, 0, d.width, d.height); 
270:       if (maze != null) { 
271:         maze.draw(g); 
272:       }
273:       requestFocus();
274:     }
275: 
276:     //public boolean isFocusTraversable() { // pre 1.4
277:     public boolean isFocusable() { // 1.4
278:       return true; 
279:     }
280: 
281:     public Dimension getPreferredSize() { 
282:       return dim; 
283:     }
284:   
285:     public Dimension getMinimumSize() { 
286:       return dim;
287:     }
288: 
289:     private Maze maze; 
290:     private Dimension dim; 
291:     
292:   }
293: 
294:   static class MazeKeyListener extends KeyAdapter { 
295: 
296:     MazeKeyListener(Maze maze) {
297:       this.maze = maze; 
298:     }
299: 
300:     public void keyPressed(KeyEvent e) {
301:       System.out.println("Key pressed");
302:       Command command = null; 
303:       int code = e.getKeyCode();
304:       switch (code) { 
305:       case KeyEvent.VK_UP:
306:         System.out.println("Up key");
307:         command = new MazeMoveCommand(maze, Direction.NORTH);
308:         break; 
309:       case KeyEvent.VK_DOWN:
310:         System.out.println("Down key");
311:         command = new MazeMoveCommand(maze, Direction.SOUTH);
312:         maze.move(Direction.SOUTH); 
313:         break; 
314:       case KeyEvent.VK_LEFT:
315:         System.out.println("Left key");
316:         command = new MazeMoveCommand(maze, Direction.WEST);
317:         break; 
318:       case KeyEvent.VK_RIGHT:
319:         System.out.println("Right key");
320:         command = new MazeMoveCommand(maze, Direction.EAST);
321:         break; 
322:       default:
323:         System.out.println("Key press ignored");
324:       }            
325:       if (command != null) {
326:         maze.doCommand(command);
327:       }
328:     }
329: 
330:     Maze maze; 
331:   }
332: 
333: }