import java.awt.*; import java.awt.event.*; import java.awt.Graphics; import javax.swing.*; /** *

Superclass of maze generation/solution assignments for CSC17.

* * Protected fields, except the 2D array {@link M}, can be modified by * overriding the {@link customize} function in a subclass. *
* This class does not contain a main, which should be supplied in a subclass. *
* @author Chuck Liang * */ public class mazebase extends JFrame implements KeyListener { /** The number of rows of the maze 2D array. * This number should be odd in order for the maze to have a border. The default value is 41. */ protected int mheight = 41; /** The number of columns of the maze 2D array. * This number should be odd in order for the maze to have a border. The default value is 41. */ protected int mwidth = 41; /** The array for the maze is declared and initialized in the superclass. This variable should be not set in {@link customize} */ protected int[][] M; // the array for the maze /* public static final int SOUTH = 0; public static final int EAST = 1; public static final int NORTH = 2; public static final int WEST = 3; */ /** If set to true, the {@link drawblock} function will display the values of the maze matrix that are non-zero */ protected boolean showvalue = false; // affects drawblock /** If set to true, will automatically delay by value {@link dtime} at end of calls to {@link drawdot} */ protected boolean autodelay = false; //delays automatically between drawdot /** If set to true, will try to load animated gif from filename {@link gifname}, which will be displayed by {@link drawdot} */ protected boolean usegif = false; // affects drawdot // graphical properties: /** the height in pixels of graphical square representing a maze coordinate */ protected int bh = 20; // height of a graphical block /** * the width in pixels of graphical square representing a maze coordinate */ protected int bw = 20; // width of a graphical block private int ah, aw; // height and width of graphical maze (don't change) /** "y-offset", which is required on some systems that automatically displays a title bar for every window. */ protected int yoff = 40; // init y-cord of maze private Image screen1; // static background buffer private Image screen2; // animation frame buffer private Graphics g; // draw to screen1 /** returns java.awt.Graphics object that allows drawing to animation buffer: nothing will be displayed, however, until {@link nextframe} is called. */ protected Graphics Graphics() {return g;} private Graphics g2; // draw to screen2 private Graphics dg; // draw to actual display /** The approximate number of milliseconds delayed in calls to {@link drawdot} if {@link autodelay} is set to true */ protected int dtime = 30; // ms delay time (for autodelay) /** The color of maze "walls", or M[row][column] values that are zero */ protected Color wallcolor = Color.green; /** The color of maze "paths", or M[row][column] values that are non-zero */ protected Color pathcolor = Color.black; /** The color of the graphical circle drawn by default by {@link drawdot} */ protected Color dotcolor = Color.red; /** The color of text messages that are displayed on the maze by {@link drawMessage}*/ protected Color pencolor = Color.yellow; private Image animatedgif; /** The path-name of the gif/jpeg file that replaces a circle if {@link usegif} is set to true */ protected String gifname = "miner.gif"; /** Starting x coordinate of maze */ protected int startdigx = 1; // initial coordinates, first call to digout /** Starting y coordinate of maze: the mazebase superclass will call {@code digout(startdigy,startdigx)} */ protected int startdigy = 1; /** constructor calls customize first, then creates the matrix M */ public mazebase() { // bh = bw = bh0; mheight = mh0; mwidth = mw0; customize(); // optional startupcode - change all vars here ah = bh*mheight; aw = bw*mwidth; M = new int[mheight][mwidth]; // initialize maze (all 0's - walls). this.setBounds(0,0,aw+10,10+ah+yoff); this.setVisible(true); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.addKeyListener(this); try{Thread.sleep(500);} catch(Exception e) {} // Synch with system screen1 = createImage(aw+10,10+ah+yoff); screen2 = createImage(aw+10,10+ah+yoff); g = screen1.getGraphics(); g2 = screen2.getGraphics(); dg = getGraphics(); //g.setColor(Color.red); setup(); } /** utility to load animated gif, called from setup after customize() */ protected void loadgif(String filename) { try { animatedgif = Toolkit.getDefaultToolkit().getImage(filename); prepareImage(animatedgif,this); Thread.sleep(100); // Synch with system } catch(Exception e) {animatedgif=null; usegif=false;} }//loadgif /** this function overrides automatic repaint: do not change */ @Override public void paint(Graphics g) {} // override automatic repaint private void setup() { g.setColor(wallcolor); g.fill3DRect(0,yoff,aw,ah,true); // fill raised rectangle g.setColor(pathcolor); try { g.setFont(new Font("Serif",Font.BOLD,bh*3/4)); // might not work } catch(Exception gfe) {} /*if (usegif)*/ loadgif(gifname); // placed here so user can define gif usage // showStatus("Generating maze..."); //digout(mheight-2,mwidth-2); // start digging! (lab 2) digout(startdigy,startdigx); // draw to screen clear(); refresh(); /* // digout exit square (if digout complete, works for odd dimensions) if (M[mheight-2][mwidth-2]!=0) { //M[mheight-1][mwidth-2] = M[mheight-2][mwidth-1] = 1; drawblock(mheight-2,mwidth-1); } */ solve(); // this is the function to @Override for lab 3, part 1 trace(); // for part 2 play(); // for part 3 } protected void clear() { g2.drawImage(screen1,0,0,this); //draw to screen2 } protected void refresh() { dg.drawImage(screen2,0,0,this); } /** redraws animation buffer without delay */ public void nextframe() { clear(); refresh(); } /** redraws animation buffer after specified delay * @param msdelay The approximate number of milliseconds to delay */ public void nextframe(int msdelay) // with delay time in ms { delay(msdelay); clear(); refresh(); } /** delays current thread by approximately ms milliseconds. This function is non-blocking. */ public void delay(int ms) { try {Thread.sleep(ms);} catch(Exception e) {} } /** draws a graphical square of color pathcolor corresponding to matrix coordinates row y, column x. */ public void drawblock(int y, int x) { drawblock(g,y,x); } private void drawblock(Graphics g,int y, int x) { g.setColor(pathcolor); g.fillRect(x*bw,yoff+(y*bh),bw,bh); g.setColor(pencolor); // following line displays value of M[y][x] in the graphical maze: if (showvalue) g.drawString(""+M[y][x],(x*bw)+(bw/2-4),yoff+(y*bh)+(bh/2+6)); } /** draws a solid circle of color {@link dotcolor} corresponding to matrix coordinates y,x, unless {@link usegif} is set true, in which case it will draw a gif as indicated by {@link gifname} */ public void drawdot(int y, int x) { drawdot(g,y,x); } protected void drawdot2(int y, int x) {drawdot(g2,y,x);} private void drawdot(Graphics g, int y, int x) { if (usegif && animatedgif!=null) { g.drawImage(animatedgif,x*bw,yoff+(y*bh),bw,bh,null); } else { g.setColor(dotcolor); g.fillOval(x*bw,yoff+(y*bh),bw,bh); } if (autodelay) try{Thread.sleep(dtime);} catch(Exception e) {} } /** draw default gif */ public void drawgif(int y, int x) { drawgif(g2,animatedgif,y,x); } //alias /** draw a specific Image (such as animated gif) */ protected void drawgif2(int y,Image gif,int x) { drawgif(g2,gif,y,x);} private void drawgif(Graphics g, Image gif, int y, int x) { g.drawImage(gif,x*bw,yoff+(y*bh),bw,bh,null); } /** displays string message m at top row of maze */ public void drawMessage(String m) { g.setColor(wallcolor); g.fillRect(0,yoff,bw*mwidth,bh); g.setColor(pencolor); // erase line g.drawString(m,10,yoff+bh-4); } ////// the following functions are to be overriden in subclass: /** User-defined initialization code. This function can be overridden in a subclass. The default, base class version does nothing. This function is called by the constructor of base class */ public void customize() // user-defined initialization code {} // this is called before digout /* function to generate random maze */ /** This function must be override in a subclass to generate a random maze. The default, base-class version does nothing. */ public void digout(int y, int x) // override for lab 2 (maze generation) { // generates maze - code in subclass } // digout /** Override this function in a subclass to solve the maze. Start at coordinates x=1, y=1, and stop at coordinates x=mwidth-1, y=mheight-2. */ public void solve() // override for lab 3 part 1 { int x=1, y=1; // drawdot(y,x); // drawblock(y,x) will erase the dot // modify this function to move the dot to the end of the maze. That // is, when the dot reaches y==mheight-2, x==mwidth-2 } // solve /** Override this function to trace the optimal solution path of the maze. */ public void trace() // override for lab 3 part 2, { // draw a dot (without erasing it) along the OPTIMAL path } /////////////////////////////////////////////////////////////// /// For part three (save a copy of part 2 version first!), you // need to implement the KeyListener interface. /** Optional function to override to set up an interactive game */ public void play() // override for lab 3, final part { // code to setup game } // for this part you may also define some other instance vars outside of // the play function. // skeleton implementation of KeyListener interface public void keyReleased(KeyEvent e) {} public void keyTyped(KeyEvent e) {} /** Override this function to respond to keyboard events. The default function prints the numerical value corresponding to the key pressed */ public void keyPressed(KeyEvent e) // override for key event handling { int key = e.getKeyCode(); // code for key pressed System.out.println("YOU JUST PRESSED KEY "+key); } /* // main: public static void main(String[] args) throws Exception { int n = args.length; if (n==1 || n==4) subclass = args[0]; int blocksize = bh, mh = 45, mw = 45; // width/height need to be odd if (n==4 || n==3) { mh=Integer.parseInt(args[n-3]); mw=Integer.parseInt(args[n-2]); blocksize=Integer.parseInt(args[n-1]); } // mazebase W = new mymazecode(blocksize,mh,mw); }//main */ // main should be in subclass } // mazebase