/* MazeApplet.java 3.1 Written by Kevin N. Haw and JoAnn K. Haw, www.thehaws.org. Please email comments via the link at our website. All contents copyright 2000-2005 by Kevin N. Haw and JoAnn K. Haw. The authors grant permission to freely distribute and modify this program as long as this copyright notice and all copyright notices embedded in the program remain intact. This applet draws mazes based on various shaped tiles such as squares, hexagons, or triangles. A pulldown allows the user to select the shape and also turn on or off a solution path. The user can click his or her way through the maze to try to solve it against a timer. It requires the MazeTile class (distributed with this class or found at our website) to create the maze. The two classes are usually placed in a common .jar file to allow for ease of use. */ import java.awt.*; import java.awt.event.*; import java.applet.*; import java.util.Vector; /** */ public class MazeApplet extends Applet { // Copyright and version data public static String copyMsg = "MazeApplet: Copyright Kevin N. Haw and JoAnn K. Haw, 2000-2005."; public static String verMsg = "MazeApplet v 3.1"; public static int verno = 0x300100; // Byte0=revision, byte1= minor version, byte2= major version MazeControls controls; // The controls for drawing Mazes MazeCanvas canvas; // The drawing area to display Mazes public void init() { setLayout(new BorderLayout()); // Use the canvas that actually holds the maze. canvas = new MazeCanvas(); canvas.init(); // Put the canvas with the maze on top and the control panel on bottom. add("Center", canvas); add("South", controls = new MazeControls(canvas)); } public void destroy() { remove(controls); remove(canvas); } public void start() { controls.setEnabled(true); } public void stop() { controls.setEnabled(false); } public void processEvent(AWTEvent e) { if (e.getID() == Event.WINDOW_DESTROY) { System.exit(0); } } public static void main(String args[]) { Frame f = new Frame("MazeApplet"); MazeApplet MazeApplet = new MazeApplet(); MazeApplet.init(); MazeApplet.start(); f.add("Center", MazeApplet); f.setSize(300, 300); f.show(); } public String getAppletInfo() { return "An interactive test of the Graphics.drawMaze and \nGraphics.fillMaze routines. Can be run \neither as a standalone application by typing 'java MazeApplet' \nor as an applet in the AppletViewer."; } } // The MazeCanvas actually holds the maze made of MazeTiles and handles clicks as user tries // to navigate the maze. class MazeCanvas extends Panel implements MouseListener, MouseMotionListener { MazeTile firstTile; MazeTile startTile; MazeTile endTile; Vector theSolution; Color fgColor = Color.blue; // Color of maze walls (default blue) Color bgColor = Color.white; // Color for maze background (default white) Color solColor = Color.red; // Color for solution & labels (default red) Color pathColor = Color.pink; // Color of tiles the user is stepping through Color visitColor = Color.lightGray; // Color of tiles the user has visited boolean newMaze = false; // Flags request to make new maze boolean solveMaze = false; // Flags request to draw solution String mazeShape // Shape of the maze = new String("Square"); String oldMazeShape // Shape of last maze drawn = new String("Square"); Vector userPath; boolean thePath[]; // The path a user has navigated through the maze boolean visitedTiles[]; // All tiles a user has clicked on boolean mazeSolved = false; static long startTime, endTime; // Create an init() method to set up mouse listeners. public void init() { addMouseListener(this); addMouseMotionListener(this); } // Override the destroy() method to remove mouse listeners. public void destroy() { removeMouseListener(this); removeMouseMotionListener(this); } public void paint(Graphics g) { Rectangle r = getBounds(); int i, j; // Ubiquitous counter variables Point p1, p2; // Points for plotting maze solution boolean heterogenous = false; // Indicates heterogenous tile shapes Vector polyVector = new Vector(); // Vector of polygons for heterogenous tiles // See if a new maze is requested if(newMaze || firstTile == null) { Polygon tileShape = new Polygon(); // First, see if a new maze must be allocated if(firstTile == null || !oldMazeShape.equalsIgnoreCase(mazeShape)) { // New maze is requested - start making the new tile shape if (mazeShape == null || mazeShape.equalsIgnoreCase("square")) { // By default, make square shaped tiles tileShape.addPoint( 20, 20); // Northeast tileShape.addPoint(-20, 20); // Southeast tileShape.addPoint(-20,-20); // Southwest tileShape.addPoint( 20,-20); // Southeast } else if ( mazeShape.equalsIgnoreCase("small squares") ) { // Now, make a diamond shaped tile tileShape.addPoint( 10, 10); // Northeast tileShape.addPoint(-10, 10); // Southeast tileShape.addPoint(-10,-10); // Southwest tileShape.addPoint( 10,-10); // Southeast } else if ( mazeShape.equalsIgnoreCase("diamond") ) { // Now, make a diamond shaped tile tileShape.addPoint( 20, 0); // North tileShape.addPoint( 0, 20); // East tileShape.addPoint(-20, 0); // South tileShape.addPoint( 0,-20); // West } else if ( mazeShape.equalsIgnoreCase("hex") ) { // Make hex shaped tiles tileShape.addPoint( 17, 10); // Northeast tileShape.addPoint( 0, 20); // North tileShape.addPoint(-17, 10); // Northwest tileShape.addPoint(-17,-10); // Southwest tileShape.addPoint( 0,-20); // South tileShape.addPoint( 17,-10); // Southeast } else if ( mazeShape.equalsIgnoreCase("Butterfly") ) { // Make Butterfly shaped tiles tileShape.addPoint( 20, 20); // Northeast tileShape.addPoint( 0, 10); // North tileShape.addPoint(-20, 20); // Northwest tileShape.addPoint(-20,-20); // Southwest tileShape.addPoint( 0,-10); // South tileShape.addPoint( 20,-20); // Southeast } else if ( mazeShape.equalsIgnoreCase("Triangles") || mazeShape.equalsIgnoreCase("Small Triangles") ) { // Mark tiles as having different shapes or orientations heterogenous = true; int triangleWidth; int triangleHeight; if(mazeShape.equalsIgnoreCase("Small Triangles")) { triangleWidth=10; triangleHeight=17; } else { triangleWidth=20; triangleHeight=34; } // Because maze is heterogeneous, we can't just make one shape // and ask MazeTile to duplicate it. Instead, we need to make list // of all shapes and pass that to MazeTile. // Make maze containing triangle polygons. Create // two baseline triangles - one pointing up and the other down Polygon upTriangle = new Polygon(); upTriangle.addPoint(((r.x+r.width)/2), 0); // Top upTriangle.addPoint((((r.x+r.width)/2) - triangleWidth), triangleHeight); // Left upTriangle.addPoint((((r.x+r.width)/2) + triangleWidth), triangleHeight); // Right Polygon dnTriangle = new Polygon(); dnTriangle.addPoint(((r.x+r.width)/2), (triangleHeight*2)); // Bottom dnTriangle.addPoint((((r.x+r.width)/2) - triangleWidth), triangleHeight); // Left dnTriangle.addPoint((((r.x+r.width)/2) + triangleWidth), triangleHeight); // Right // Create triangles one row at a time boolean done = false; for(i=0; ;i++) { // t1 and t2 are working copies of upTriangle and dnTriangle, respectively Polygon t1 = new Polygon(upTriangle.xpoints, upTriangle.ypoints, upTriangle.npoints); t1.translate(-i*triangleWidth, i*triangleHeight); Polygon t2 = new Polygon(dnTriangle.xpoints, dnTriangle.ypoints, dnTriangle.npoints); t2.translate(-i*triangleWidth, i*triangleHeight); // Check to see if t1 and t2 fit inside bounding rectangle r. if( ((i+1)*triangleWidth*2) >= r.width ) break; // We've run out of width else if ( ((i+1)*triangleHeight) >= r.height ) break; // We've run out of height // Now, add each triangle to the list for the maze for(j=0; j