/**
* Maze.java - Cory J. Goldfuss - 12 Feb 2001
* Program builds a maze made with labels and recursivley finds
* the solution (exit).
* User can change layout of maze by altering the 15 element string array; Using
* capital letters, where W represents a wall and S is the starting location.
* Note: The maze cannot exceed 15 elments by 15 elements. (0-14 by 0-14)
*/
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class Maze extends JApplet implements ActionListener, ItemListener
{
private ButtonGroup radioGroup;
private int xStart, yStart; // store start location
private int xIndex = -1, yIndex = -1, counter = -1; // used for animation (note starting at -1)
private static int mazeSize = 15;
private JLabel mazeArray[][] = new JLabel[mazeSize][mazeSize];
private boolean breadCrumbs = false; // show recursion or not
private int animateXarray[] = new int[225]; // store values for animation
private int animateYarray[] = new int[225];
private boolean haveWall[][] = new boolean[mazeSize][mazeSize];
private boolean haveChecked[][] = new boolean[mazeSize][mazeSize];
private boolean startLocation[][] = new boolean[mazeSize][mazeSize];
private Timer animate; // Swing timer for "animating" the maze
private final String[] Map = {"WWWWWWWWWWWWWWW",
"W W W W",
"W W WWWWW WWW W",
"W W W W W",
"W W W W WWW W W",
"W W W W W W W",
"W WWWWW W WWW W",
"W W SW W W",
"W W WWW WWW W W",
"W W W W W",
"W WWW WWWWW W W",
"W W W W",
"W W WWWWW WWWWW",
"W W W W",
"WWWWWWW WWWWWWW"};
// Images for GUI
private ImageIcon wallIcon;
private ImageIcon theta;
private ImageIcon xImage;
// Neat way to show my authorship - start called upon applet start, Applet does not run until "Ok" is clicked
public void start(){ JOptionPane.showMessageDialog( null, "Maze 1.0 by Cory J. Goldfuss", "Maze 1.0a", JOptionPane.INFORMATION_MESSAGE, null);}
public void init()
{
// This line prevents the "Swing: checked access to system event queue" message seen in some browsers.
getRootPane().putClientProperty("defeatSystemEventQueueCheck", Boolean.TRUE);
// This code is automatically generated by Visual Cafe when you add
// components to the visual environment. It instantiates and initializes
// the components. To modify the code, only use code syntax that matches
// what Visual Cafe can generate, or Visual Cafe may be unable to back
// parse your Java file into its visual environment.
//{{INIT_CONTROLS
getContentPane().setLayout(null);
setSize(500,512);
mazePanel.setToolTipText("Maze appears here.");
mazePanel.setLayout(new GridLayout(15,15,0,0));
getContentPane().add(mazePanel);
mazePanel.setBackground(java.awt.Color.black);
mazePanel.setBounds(12,12,450,450);
JstartBtn.setText("Go!");
JstartBtn.setActionCommand("Go!");
JstartBtn.setNextFocusableComponent(JstopBtn);
JstartBtn.setSelected(true);
JstartBtn.setToolTipText("Start Solving");
JstartBtn.setFocusPainted(false);
JstartBtn.setMnemonic((int)'G');
getContentPane().add(JstartBtn);
JstartBtn.setBounds(36,468,78,32);
JstopBtn.setRequestFocusEnabled(false);
JstopBtn.setText("Stop");
JstopBtn.setActionCommand("Stop");
JstopBtn.setNextFocusableComponent(JresetBtn);
JstopBtn.setToolTipText("Stop Solving");
JstopBtn.setFocusPainted(false);
JstopBtn.setMnemonic((int)'S');
getContentPane().add(JstopBtn);
JstopBtn.setBounds(132,468,78,32);
JstopBtn.setVisible(false);
JresetBtn.setRequestFocusEnabled(false);
JresetBtn.setToolTipText("Start Over");
JresetBtn.setFocusPainted(false);
JresetBtn.setText("Reset");
JresetBtn.setActionCommand("Reset");
JresetBtn.setNextFocusableComponent(JstartBtn);
JresetBtn.setMnemonic((int)'R');
getContentPane().add(JresetBtn);
JresetBtn.setBounds(228,468,78,32);
JresetBtn.setVisible(false);
JsimpleRadio.setText("Simple Solve");
JsimpleRadio.setSelected(true);
getContentPane().add(JsimpleRadio);
JsimpleRadio.setBounds(324,468,108,12);
JrecursiveRadio.setText("Show Recursive Solve");
getContentPane().add(JrecursiveRadio);
JrecursiveRadio.setBounds(324,492,156,12);
//}}
// Button Group
radioGroup = new ButtonGroup();
radioGroup.add( JrecursiveRadio );
radioGroup.add( JsimpleRadio );
// create images
wallIcon = new ImageIcon( getImage( getCodeBase(), "brick.gif" ));
theta = new ImageIcon( getImage( getCodeBase(), "theta.gif" ));
xImage = new ImageIcon( getImage( getCodeBase(), "xpic.gif" ));
animate = new Timer( 250, this );
JstartBtn.grabFocus(); //get focus so mnemonics work when applet starts
// Gather info about layout of maze - from Map[].
for (int i = 0; i < mazeSize; i++){
for ( int j = 0; j < mazeSize; j++){
if (Map[i].charAt(j) == 'W'){
haveWall[i][j] = true;
}
else if (Map[i].charAt(j) == 'S'){
startLocation[i][j] = true;
}
else{
haveWall[i][j] = false;
startLocation[i][j] = false;
}
}
}
// Create maze from boolean arrays used when reading in Map[].
for (int i = 0; i < mazeSize; i++){
for (int j = 0; j < mazeSize; j++){
mazeArray[i][j] = new JLabel();
mazeArray[i][j].setForeground( Color.green );
mazeArray[i][j].setOpaque( true );
mazeArray[i][j].setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
mazePanel.add( mazeArray[i][j] );
if ( haveWall[i][j] ){
mazeArray[i][j].setIcon( wallIcon );
}
else if ( startLocation[i][j] ){
mazeArray[i][j].setIcon( theta );
xStart = i;
yStart = j;
}
else{
mazeArray[i][j].setBackground( Color.black );
}
}
}
JstartBtn.addActionListener( this );
JstopBtn.addActionListener( this );
JresetBtn.addActionListener( this );
JrecursiveRadio.addItemListener( this );
JsimpleRadio.addItemListener( this );
}
//{{DECLARE_CONTROLS
javax.swing.JPanel mazePanel = new javax.swing.JPanel();
javax.swing.JButton JstartBtn = new javax.swing.JButton();
javax.swing.JButton JstopBtn = new javax.swing.JButton();
javax.swing.JButton JresetBtn = new javax.swing.JButton();
javax.swing.JRadioButton JsimpleRadio = new javax.swing.JRadioButton();
javax.swing.JRadioButton JrecursiveRadio = new javax.swing.JRadioButton();
//}}
public void actionPerformed( ActionEvent e ){
if ( e.getSource() == JstartBtn ){
JstopBtn.setVisible( true );
exitTheseus( xStart, yStart );
animate.start();
JstartBtn.setEnabled( false );
JsimpleRadio.setEnabled( false );
JrecursiveRadio.setEnabled( false );
}
if ( e.getSource() == JstopBtn ){
JstopBtn.setVisible( false );
animate.stop();
JresetBtn.setVisible( true );
}
if ( e.getSource() == JresetBtn ){
JstartBtn.setEnabled( true );
JresetBtn.setVisible( false );
resetMaze(); // calls function that resets all arrays and icons
}
if ( e.getSource() == animate ){
if ( xIndex < counter ){
xIndex++;
yIndex++;
mazeArray[animateXarray[xIndex]][animateYarray[yIndex]].setVisible( true );
}
else{
animate.stop();
JstopBtn.setVisible( false );
JresetBtn.setVisible( true );
}
}
}// end action Performed
public void itemStateChanged( ItemEvent e ) {
if ( e.getSource() == JrecursiveRadio )
breadCrumbs = true;
if ( e.getSource() == JsimpleRadio )
breadCrumbs = false;
}
// solves maze - called exitTheseus for historical factors
public boolean exitTheseus(int x, int y){
if ( x <= 0 || y <= 0 || x >= mazeSize - 1 || y >= mazeSize - 1){
mazeArray[x][y].setVisible( false );
animateLater( x,y );
mazeArray[x][y].setText("Exit!!");
return true;
}
if ( haveChecked[x][y] ){
return false;
}
haveChecked[x][y] = true;
mazeArray[x][y].setVisible( false );
animateLater( x, y );
mazeArray[x][y].setIcon( theta );
// can we move north?
if ( !haveWall[x-1][y] ){
if ( exitTheseus( x - 1, y )){
return true;
}
}
// south?
if ( !haveWall[x+1][y] ){
if ( exitTheseus( x + 1, y )){
return true;
}
}
// west?
if ( !haveWall[x][y-1] ){
if ( exitTheseus( x, y - 1 )){
return true;
}
}
// east?
if ( !haveWall[x][y+1] ){
if ( exitTheseus( x, y + 1 )){
return true;
}
}
mazeArray[x][y].setVisible( false );
if( breadCrumbs ){
animateLater( x, y );
mazeArray[x][y].setIcon( xImage );
}
else{
mazeArray[x][y].setIcon(null);
}
return false;
}// end exitTheseus
// method resets maze
public void resetMaze(){
for (int i = 0; i < mazeSize; i++){
for (int j = 0; j < mazeSize; j++){
if ( haveWall[i][j] ){
mazeArray[i][j].setIcon( wallIcon );
}
else if ( startLocation[i][j] ){
mazeArray[i][j].setIcon( theta );
xStart = i;
yStart = j;
}
else{
mazeArray[i][j].setBackground( Color.black );
mazeArray[i][j].setText("");
mazeArray[i][j].setIcon( null );
}
haveChecked[i][j] = false;
counter = -1;
xIndex = -1;
yIndex = -1;
JsimpleRadio.setEnabled( true );
JrecursiveRadio.setEnabled( true );
}
}
}// end resetMaze
/* Due to the recursive fuction, we must store values for later reference
* Function reads in the current x and y values (from the 2-D mazeArray)
*/
private void animateLater( int x, int y ){
counter++;
animateXarray[counter] = x;
animateYarray[counter] = y;
}
}