// Mr. Mazer // Tod Semple (tsemple@hmc.edu) // Copyright 1996 // // maze.java // 3/26/96 // import java.awt.*; import java.applet.*; import java.io.*; import java.net.*; import java.lang.*; /** * This is the canvas the has the count down timer */ class CTimer extends Canvas { long StartTime; // in ms Thread paintTimerThread; maze theMaze; int level; public int timeLeft; CTimer(maze maze_arg,int level_arg) { StartTime=0; theMaze = maze_arg; level = level_arg; } /** * This is used by the add() function so it knows what size to start at. */ public Dimension minimumSize() { return new Dimension(100,20); } /** * This is used by the add() function so it knows what size to start at. */ public Dimension preferredSize() { return new Dimension(100,20); } /** * Start the timer. */ public void Start() { StartTime=System.currentTimeMillis(); repaint(); // Make the thread that tell this canvas to paint // itself ever second. paintTimerThread = new Thread(new PaintTimer(this)); paintTimerThread.start(); } public void paint(Graphics g) { // Clear the canvas g.setColor(Color.white); g.fillRect(0,0,size().width,size().height); // has timer not starter yet? if (StartTime==0) return; // Determin the time left and display it. long EllapseTime = System.currentTimeMillis() - StartTime; timeLeft = (int)(theMaze.getMazeSize() + level*2 - EllapseTime/1000); if (timeLeft<0) timeLeft=0; g.setColor(Color.black); String message = "Level:" + level + " Time Left: " + timeLeft + " Seconds"; g.drawString(message, size().width/2-60,size().height-5); // are we out of time? if (timeLeft==0) { // Player Loses theMaze.setState(theMaze.state_Lost); } } protected void finalize() { paintTimerThread.stop(); } } /** * This thread just sends paint messages to the timer canvas. */ class PaintTimer implements Runnable { PaintTimer(Canvas canvas_arg) { can=canvas_arg; } Canvas can; public void run() { // Send paint messages to the timer canvas while (true) { try { Thread.sleep(1000); can.repaint(); } catch (InterruptedException e) { return; } } } } /** * A wall class */ class CWall { boolean Down; boolean Right; } /** * This is the maze canvas */ class CMaze extends Canvas { protected int MazeWidth = 0; protected int MazeHeight = 0; protected boolean MadeItYet = false; // Location of starting position in maze int startX = 0; int startY = 0; // Location of the exit int endX = 0; int endY = 0; static protected Image imageMazer; static protected Image imageExit; protected maze App; protected boolean thinWalls; CMaze(maze app_arg, int Width,int Height) { App = app_arg; MazeWidth = Width; MazeHeight = Height; // Change the wall thickness if there are a lot // of walls for visibility if (Width>=46 || Height>46) thinWalls=true; else thinWalls=false; // java has too many bugs to use images right now... /*if (imageMazer==null) imageMazer = App.getImage(App.getCodeBase(),"person.gif"); if (imageExit==null) imageExit = App.getImage(App.getCodeBase(),"coffee.gif");*/ } // Array of all the walls (note that there are walls // on the bottom and right that are never turned on) CWall Walls[][]; /** * Make the maze */ public void Make() { int x,y; // Make a new wall double array. Walls = new CWall[MazeWidth][MazeHeight]; for (x=0;x0) { // Start at upper left corner x=1; y=1; // Find a random empty corner (in line O(# corners) time) int skip = (int)(Math.random() * nCorners) + 1; while (skip>0) { x++; if (x==MazeWidth-1) { x=1; y++; if (y==MazeHeight-1) y=1; } if (WallAt(x,y)) continue; skip--; } // Pick a random direction from the empty corner and // draw a line until we hit another wall. boolean keepgoing; int WallDirection=(int)(Math.random() * 4); switch (WallDirection) { case 0: // go right do { keepgoing = !WallAt(x+1,y); nCorners--; Walls[x][y].Right=true; DrawWall(g,x,y,WALL_RIGHT); x++; } while (keepgoing); break; case 1: // go left do { keepgoing = !WallAt(x-1,y); nCorners--; Walls[x-1][y].Right=true; DrawWall(g,x-1,y,WALL_RIGHT); x--; } while (keepgoing); break; case 2: // down do { keepgoing = !WallAt(x,y+1); nCorners--; Walls[x][y].Down=true; DrawWall(g,x,y,WALL_DOWN); y++; } while (keepgoing); break; case 3: // up do { keepgoing = !WallAt(x,y-1); nCorners--; Walls[x][y-1].Down=true; DrawWall(g,x,y-1,WALL_DOWN); y--; } while (keepgoing); break; } } // Make Starting and Ending positions startX = (int)(Math.random() * (MazeWidth-1)); startY = (int)(Math.random() * (MazeHeight-1)); while (!isAlley(startX,startY)) { startX++; if (startX==MazeWidth-1) { startX=1; startY++; if (startY==MazeHeight-1) startY=1; } } endX = (int)(Math.random() * (MazeWidth-1)); endY = (int)(Math.random() * (MazeHeight-1)); while (!isAlley(endX,endY) || (endX==startX && endY==startY)) { endX++; if (endX==MazeWidth-1) { endX=1; endY++; if (endY==MazeHeight-1) endY=1; } } } /** * Puts a start or ending alley (place with only one way out). */ boolean isAlley(int x,int y) { int numWalls=0; int NewCorners=0; if (Walls[x+1][y].Down==true) // right numWalls++; if (Walls[x][y].Down==true) // left numWalls++; if (Walls[x][y].Right==true) // up numWalls++; if (Walls[x][y+1].Right==true) // down numWalls++; return numWalls>=3; } /** * Is there a wall coming into (x,y)? */ boolean WallAt(int x,int y) { if (Walls[x][y].Right || Walls[x][y].Down) return true; if (x>0 && Walls[x-1][y].Right) return true; if (y>0 && Walls[x][y-1].Down) return true; return false; } /** * Moves the player down one place */ public void moveDown() { Graphics g=getGraphics(); showMazer(g,false); if (Walls[startX][startY+1].Right==false) startY++; showMazer(g,true); } /** * Moves the player up one place */ public void moveUp() { Graphics g=getGraphics(); showMazer(g,false); if (Walls[startX][startY].Right==false) startY--; showMazer(g,true); } /** * Moves the player left one place */ public void moveLeft() { Graphics g=getGraphics(); showMazer(g,false); if (Walls[startX][startY].Down==false) startX--; showMazer(g,true); } /** * Moves the player right one place */ public void moveRight() { Graphics g=getGraphics(); showMazer(g,false); if (Walls[startX+1][startY].Down==false) startX++; showMazer(g,true); } /** * Is the playing in the exit? */ public boolean solved() { if (startX==endX && startY==endY) return true; return false; } /** * Flash the player and the exit so the user may see them easily */ public void flash() { Graphics g=getGraphics(); showMazer(g,true); showExit(g,true); App.delay(100); showMazer(g,false); showExit(g,false); App.delay(100); } } /** * The maze applet */ public class maze extends java.applet.Applet implements Runnable { protected int State = 0; final int StartWidth = 400; final int StartHeight = 400; protected int MazeSize; protected int level; protected int score; protected int timeLeft; protected CMaze Maze; protected CTimer Timer; /** * Initialize the applet. Resize and load images. */ public void init() { int x,y; resize(StartWidth,StartHeight); } /** * Returns the number of spaces on a size of the maze */ public int getMazeSize() { return MazeSize; } /** * Paint the screen. */ public void paint(Graphics g) { int x; switch (State) { case state_Welcome: g.setFont(new java.awt.Font("Times", Font.PLAIN, 25)); g.setColor(Color.blue); g.drawString("Welcome to Mr. Mazer", size().width/2-120,size().height/3); drawPressAKey(g); break; case state_Playing: break; case state_Won: g.setFont(new java.awt.Font("", Font.PLAIN, 25)); g.setColor(new Color(0,0,127)); x = size().width/2-60; g.drawString("Whahoo!!!!!", x-20,50); g.setFont(new java.awt.Font("", Font.PLAIN, 15)); g.drawString("Level: "+level, x,80); g.drawString("Time Left: "+timeLeft, x,110); g.drawString("Score This Level: "+timeLeft+" * "+level*100+ " = "+(timeLeft*level*100), x,140); g.drawString("Total Score: "+score, x,170); drawPressAKey(g); break; case state_Lost: g.setFont(new java.awt.Font("", Font.PLAIN, 25)); g.setColor(Color.red); x = size().width/2-60; g.drawString("Game Over!!!!!", x-20,50); g.setFont(new java.awt.Font("", Font.PLAIN, 15)); g.drawString("Level: "+level, x,80); g.drawString("Final Score: "+score, x,110); drawPressAKey(g); break; } } /** * Draws "press a key" as the bottom of the screen */ void drawPressAKey(Graphics g) { g.setColor(Color.black); g.setFont(new java.awt.Font("Times", Font.PLAIN, 12)); g.drawString("Press a key to continue...", size().width/2-100,size().height-5); } public void update(Graphics g) { g.clearRect(0, 0, size().width, size().height); paintAll(g); } public boolean keyDown(java.awt.Event evt, int key) { if (State==state_Playing) { if (key == evt.DOWN) Maze.moveDown(); if (key == evt.UP) Maze.moveUp(); if (key == evt.LEFT) Maze.moveLeft(); if (key == evt.RIGHT) Maze.moveRight(); if (Maze.solved()) setState(state_Won); } else { // Continue with user presses a non-arrow key if (key != evt.DOWN && key != evt.UP && key != evt.LEFT && key != evt.RIGHT) { nextState(); } } return true; } long LastTime = 0; // last time user clicked mouse public boolean mouseDown(java.awt.Event evt, int x, int y) { // This is a fix for a java problem in windows 95. It sends // two mouse down message sometime when there should be only // one. long NowTime = System.currentTimeMillis(); if (NowTime-LastTime < 300) return true; // throw out quick double click LastTime = NowTime; if (State!=state_Playing) nextState(); return true; } /** * Goto the next state */ protected void nextState() { switch(State) { case state_Welcome: setState(state_Playing);break; case state_Playing: setState(state_Won);break; case state_Won: setState(state_Playing);break; case state_Lost: setState(state_Welcome);break; } } public final int state_Welcome = 0; public final int state_Playing = 1; public final int state_Won = 2; public final int state_Lost = 3; /** * Set the state */ protected void setState(int newState) { // Get rid of old components removeAll(); State=newState; switch(State) { case state_Welcome: MazeSize = 16; level=0; score=0; repaint(); break; case state_Playing: MazeSize+=2; level++; setLayout(new BorderLayout(10,10)); Maze=new CMaze(this,MazeSize,MazeSize); Timer=new CTimer(this,level); add("South",Timer); add("Center",Maze); repaint(); break; case state_Won: timeLeft = Timer.timeLeft; score += timeLeft*level*100; removeAll(); repaint(); break; case state_Lost: removeAll(); repaint(); break; } } /** * Flash the mazer then start the clock */ public void StartMaze() { delay(800); for (int i=0;i<6;i++) Maze.flash(); Timer.Start(); } /** * Start the applet. */ public void start() { setState(state_Welcome); requestFocus(); } public String getAppletInfo() { return "_____Mr. Mazer_____\n" + "___by Tod Semple___\n" + "_(tsemple@hmc.edu)_\n" + "_____3/26/95_______\n"; } public void run() {} /** * Shortcut for sleeping for a while */ void delay(int ms) { try { Thread.sleep(ms); } catch (InterruptedException e) { return; } } }