public class Maze implements Cloneable
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: }