Table of Contents

Make A Maze World

Step 1

1. Make a new Java Project called MakeMaze and download its two classes: Cell.java an MakeMaze.java

Cell.java
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.util.ArrayList;
 
/**
 * @author Chris Thiel, OFMCap 
 * @version 16 May 2012
 */
 
public class Cell 
{
	public static final int GAP=10, SIZE=40, LEFT=40, TOP=60;
	public static final int NORTH=0, SOUTH=1, EAST=2, WEST=3;
 
	private int visits, row, col;
	private boolean[] wall;
	private Rectangle box;
 
	public Cell(int r, int c)
	{
		visits=-1;
		row=r;
		col=c;
		wall=new boolean[4];
		box = new Rectangle (LEFT+col*(SIZE+GAP), TOP+row*(SIZE+GAP), SIZE, SIZE);
		for (int i=0;i<4;i++)
			wall[i]=true;
	}
	/**
	 * 
	 * @return a random neighboring Cell, or null if all neighbors have been visited
	 */
	public Cell randomNeighbor(Cell[][] m){
		ArrayList<Cell> n = new ArrayList<Cell>();
		//NORTH
		if (row>0 && m[row-1][col].getVisits()<0)
			n.add(m[row-1][col]);
		//SOUTH
		if (row<m.length-1 && m[row+1][col].getVisits()<0)
			n.add(m[row+1][col]);
		//WEST
		if (col>0 && m[row][col-1].getVisits()<0)
			n.add(m[row][col-1]);
		//EAST
		if (col<m[0].length-1 && m[row][col+1].getVisits()<0)
			n.add(m[row][col+1]);
		if (n.size()<1)
			return null;
		return n.get((int)(n.size()*Math.random()));
	}
	public void draw(Graphics g, Color c)
	{
		Color oldColor=g.getColor();
		g.setColor(c);
 
		if (visits==1)
			g.setColor(Color.GREEN);
		if (visits>1)
			g.setColor(Color.RED);
 
		g.fillRect(box.x, box.y, box.width, box.height);
		if (!wall[SOUTH])
			g.fillRect(box.x, box.y+SIZE, box.width, GAP);
		if (!wall[EAST])
			g.fillRect(box.x+SIZE, box.y, GAP, box.width);
 
		g.setColor(oldColor);
	}
	public Rectangle getBox(){return box;}
	public int getRow(){return row;}
	public int getCol(){return col;}
	public int getVisits(){return visits;}
	public void setVisits(int i){visits=i;}
	public void incVisits(){visits++;}
	public void setWall(int direction, boolean value){
		wall[direction]=value;
	}
	/**
	 * removes the walls between this cell and the other cell
	 * @param other
	 */
	public void removeWall(Cell other) {
		if (other.getRow()>row){//other cell is below this one
			this.setWall(SOUTH, false);
			other.setWall(NORTH, false);
		}
		if (other.getRow()<row){//other cell is above this one
			this.setWall(NORTH, false);
			other.setWall(SOUTH, false);
		}
		if (other.getCol()>col){//other cell is east of this one
			this.setWall(EAST, false);
			other.setWall(WEST, false);
		}
		if (other.getCol()<col){//other cell is west this one
			this.setWall(WEST, false);
			other.setWall(EAST, false);
		}
 
 
	}
}
MakeMaze.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
 
/**
 * @author Chris Thiel, OFMCap 
 * @version 16 May 2012 (Applet)
 * @version 5 Sept 2021 (Application)
 */
 
public class MakeMaze extends JPanel implements MouseListener
{
    public static final int ROWS=6, COLS=6; 
    public static final int WIDTH=575, HEIGHT=620;
    private Cell[][] m;
    String message="Making Maze";
 
    public static void main(String[] args) {
        MakeMaze app= new MakeMaze();
        JFrame window = new JFrame("Make Maze");
        window.setSize(WIDTH, HEIGHT);
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.getContentPane().add(app);
        window.setVisible(true);
 
    }
 
    public MakeMaze()
    {
 
        message="Making First Maze";
        makeMaze();
        message="First Maze done.";
        this.addMouseListener(this);
    }
 
    public void makeMaze()
    {
        m = new Cell[ROWS][COLS];
        for (int r=0;r<ROWS;r++)
            for(int c=0;c<COLS;c++)
                m[r][c]=new Cell(r,c);
        Cell currentCell=m[ROWS-1][0];
        currentCell.incVisits();
        ArrayList<Cell> stack=new ArrayList<Cell>();
        while (unvisitedCells()){
            Cell choice=currentCell.randomNeighbor(m);
            if (choice!=null){
                stack.add(0, currentCell);
                currentCell.removeWall(choice);
                currentCell=choice;
                currentCell.incVisits();
            }else{
                stack.remove(0);
                currentCell=stack.get(0);
            }
            repaint();
        }
    }
 
    private boolean unvisitedCells(){
        int r=0;
        while(r<ROWS){
            int c=0;
            while(c<COLS)
                if(m[r][c].getVisits()<0){
                    return true;
                }else{
                    c++;
                }
            r++;
        }
        return false;
    }
 
    public void paintComponent(Graphics g)
    {
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, WIDTH, HEIGHT);
        g.setColor(Color.BLACK);
        g.drawString(message, 20, 20);
        int left = Cell.LEFT-Cell.GAP;
        int top = Cell.TOP-Cell.GAP;
        int width = COLS*(Cell.SIZE+Cell.GAP)+Cell.GAP;
        int height = ROWS*(Cell.SIZE+Cell.GAP)+Cell.GAP;
        g.fillRect(left, top, width,height );
        for (int r = 0; r < ROWS; r++)
            for(int c=0;c<COLS;c++)
                m[r][c].draw(g, Color.YELLOW);
        int bottom =    height;    
        int delta = Cell.SIZE+ 1*Cell.GAP;
        for(int r = 1; r <= ROWS; r++)
            g.drawString(""+r, 5, bottom - (r-1)*delta);
        for(int c = 1; c <= COLS; c++)
            g.drawString(""+c, c*delta + 30, height+delta + 15 );
    }
 
    public void update(Graphics g)
    {
        paint(g); 
    }
 
    @Override
    public void mouseClicked(MouseEvent e) {}
 
    @Override
    public void mouseEntered(MouseEvent e) {}
 
    @Override
    public void mouseExited(MouseEvent e) {}
 
    @Override
    public void mousePressed(MouseEvent e) {}
 
    @Override
    public void mouseReleased(MouseEvent e) {
        message="Making new Maze";
        makeMaze();
        message="Maze Done";
        repaint();
    }
 
}

Step 2

2. As written it will Make 10 rows and 10 columns, but feel free to change this.

Step 3

3. Keep clicking it until you have one you like, and take a screen shot with Coomand-Shift-4

Step 4

4. Look for it on your Desktop and rename it with your name (For example it might be called Screen Shot 2022-08-27 at 8.47.53 AM.png and if your name was Bob Smith, you might rename it BobS.png

Step 5

5. Next you are to use these commands to make a .kwld text file. Here is an example That Describes BobS.png:

BobS.txt
KarelWorld
streets 7
avenues 7
beepers 1 1 1
beepers 3 2 2
eastwestwalls 1 3 5
eastwestwalls 2 1 2
eastwestwalls 2 4 6
eastwestwalls 3 2 2
eastwestwalls 3 5 5
eastwestwalls 4 1 1
eastwestwalls 4 4 4
eastwestwalls 5 2 3
eastwestwalls 6 1 6
northsouthwalls 1 1 1
northsouthwalls 2 2 5
northsouthwalls 3 3 4
northsouthwalls 4 5 5
northsouthwalls 5 4 6
northsouthwalls 6 1 6

This is done by typing the list in TextEdit.app (on a mac. Use Notebook.exe on Windows), and saving it in the same Folder (directory) as your Java Project using the the .kwld extension (BobS.kwld is traditional, but BobS.txt would be fine too). There is 1 beeper at the intended beginning, and 2 beepers at the intended end.

To see your progress, you can put your text file in the same folder as the ShowWorld.java project. Remember to update the name of your text file.

ShowWorld.java
import java.awt.Color;
import kareltherobot.*;
public class ShowWorld implements Directions 
{
    public static void main(String[] args)
    {
 
        // change the file name to match the text file 
        // you made and put in the project folder:
 
        World.readWorld("BobS.txt"); 
        World.setBeeperColor(Color.BLUE);
        World.setVisible();
    }
}

Try removing or changing a wall in the BobS.txt file to get a feel of how the code changes the KarelWorld drawn by the ShowWorld main method.

Step 6

6. Now it is your turn. Make a new text file (or rename “BobS.txt” to your first anme and last initial, ending with “.txt”). Start with your first wall. See the result with ShowWorld.java, and fix it if necessary, Try the next wall.

When you are done, place 2 beepers in the best locations for the longest run for a MazeRunner robot.

For those will experience with placeEWWall and placeNEWall

For those who are used to the placeEWWall or placeNSWall methods, there is a difference that you may find confusing with the parameters. For eastwestwalls the three numbers are (street the wall goes on) (starting on avenue) (ending on ave). For the northsouthwalls: the three numbers are (Avenue the wal goes on) (Starting street) (Ending Street). If you already coding it with place walls you can convert it with this:

World.java
/**
 * This is a replacement for the World
 * found in karelworld.jar 
 * 
 * to help you convert your placeWall statements
 * with the format needed for a kwld text file format.
 *
 * @author Chris Thiel
 * @version Sept 4, 2022
 */
public class World
{
    public static void placeEWWall(int str, int ave, int len)
    {
        int end = ave + len - 1;
        String result = "eastwestwalls "+ str + " " +ave + " " + end;
        System.out.println(result);
    }
 
    public static void placeNSWall(int str, int ave, int len)
    {
        int end = str + len - 1;
        String result = "northsouthwalls " + ave + " " + str + " " + end;
        System.out.println(result);
    }
}

Alternatively your can use placeWall methods and save the world to file.

Links to Karel and KarelWorld Reference

Karel API

Show and Tell

Go to https:///www.mathorama.com/karel/maze/ To see other student's work