Jump to content


Check out our Community Blogs

mr mike

Member Since 23 Aug 2010
Offline Last Active Sep 20 2011 11:39 AM
-----

#600529 Maze Tutorial

Posted by mr mike on 20 May 2011 - 07:54 AM

LETS THINK ABOUT A MAZE
A Maze can be thought of a series of rooms that has four walls that are either opened exposing the next room or are blocking the view of the next room. In short a room(Vertex) has four walls(edges) that are either there or not(boolean). The openings are determined by sets.

LET'S BEGIN
First we will create a room class. The variables that will be needed initially are four walls, a thought of a matrix(x and y), an adjacency list, a room name consisting of a number(ie. 0, 1, 2, 3,...,n), and a pointer to the previous room.

Room Class
import java.util.*;
public class Room{
   // represent four walls
   public Wall north, east, south, west; // the wall class will be created next
   public int x, y; // represent the row and column of the maze
   public List<Room> adj; // adjacency list using linked list
   public int roomName; // for this the room will be a number
   public Room prev; // last room pointer

   // now we code the constructer 
   public Room(int x, int y){
      this.x = x;// row
      this.y = y;// column
      adj = new LinkedList<Room>();
      prev = null;// we have not progressed, so prev is nothing
      roomName = 0;// we will use the concept of arrays start 0
   }// end of constructor

   // we have to increment the room name so lets do it
   public int getRoomName(){
      return roomName++;
   }// end of getRoomName()

}// end of 
Wall Class
public class Wall{
   
   public Room currentRoom, nextRoom;// room in now, next room 
   public boolean isGone = false;// is the wall there

   // Two constructors will be created
   // which will account for walls with or 
   // without neighbors

   // with a neighbor 
   public Wall(Room a, Room b){
      currentRoom = a;
      nextRoom = b;
   }

   // without a neighbor
   public Wall(Room r){
      currentRoom = r;
      nextRoom = null;
   }
}// end of Wall class
I will explain how disjoint sets work in a future tut, but a quick explanation:
Disjoint sets are sets whose intersect is the null set. We will use this notion to join the sets or room names and create the maze by unionizing the rooms.

JoinRoom class
public class JoinRoom{
   private int[] set; // this is an array to store a set of rooms
   public JoinRoom(int elem){
      set = new int[e];
      // initialize every element in the set
      for(int i = 0; i < set.length; i++){
         set[i] = -1;
      }
   }// end of constructor

   // find using compression
   public int find(int r){
      if(set[r] < 0){
         return r;
      } else {
         return set[r] = find(set[r]);
      }
  }// end of find

  public void unionRooms(int roomA, int roomB){
      if(set[roomB] < set[roomA]){
          set[roomA] = roomB;
      } else {
         if(set[roomA] == set[roomB]){
            set[roomA]--;
         }
         set[roomB] = roomA;
     }
 }// end of union rooms

}// end of joinRoom class
NOW WE CREATE OUR MAIN CLASS TO GENERATE THE MAZE

We will create the class and have it extend JPanel for our artwork. We have to think of private variables that will be needed.
public class Maze extends JPanel{
    // the maze can be seen as a matrix of squares so well use a multidimensional array of the room 
    // class
    private Room[][] rooms;// the maze can be seen as a matrix of squares so well use
    private ArrayList<Wall> walls; // List of walls
    private Random rand;// We are going to have to randomize the rooms chosen to unionize
    private int height;// users desired height of matrix 
    private int width;// users desired width of matrix
    private int num;// we will have to increment a few times so lets just use num as an incrementor
    private JoinRooms ds;// we are going to join rooms so well label the variable ds for disjoint set

    // we are going to need variables for our panel 
    private int x_cord; // x-axis rep
    private int y_cord;// y-axis rep
    private int roomSize;
    private int randomWall;

}// end of class

Now we need the constructor. We want the constructor to take height and width of the matrix. We also want the constructor to initialize our multidimensional room array and our arraylist of walls(the bottom right will always be the exit). We will also call the generate the random maze which will initialize the maze to be a matrix of squares. Finally we will set the size of our panel.

    public Maze(int height, int width) {
        this.height = height;
        this.width = width;
        rooms = new Room[height][width];
        walls = new ArrayList<Wall>((height - 1) * (width - 1));
        generateRandomMaze();
        setPreferredSize(new Dimension(800, 700));
   }

To generate the random maze we will first have to create a initial multidimensional array of rooms with the walls intact except for the top left and bottom right room. We will now initialize our JoinRooms class to be essentialy a array of rooms. We also have to initialize our random room generator and use our incrementer(num) to decrement.

   private void generateRandomMaze() {
        generateInitialRooms();// see next method
        ds = new JoinRoom(width * height);
        rand = new Random(); // here is the random room generator
        num = width * height;

        while (num > 1) {
           // when we pick a random wall we want to avoid the borders getting eliminated
            randomWall = rand.nextInt(walls.size());
            Wall temp = walls.get(randomWall);
            // we will pick two rooms randomly 
            int roomA = temp.currentRoom.y + temp.currentRoom.x * width;
            int roomB = temp.nextRoom.y + temp.nextRoom.x * width;

            // check roomA and roomB to see if they are already members 
            if (ds.find(roomA) != ds.find(roomB)) {
                walls.remove(randomWall);
                ds.unionRooms(ds.find(roomA), ds.find(roomB));
                temp.isGone = true;
                temp.currentRoom.adj.add(temp.nextRoom);
                temp.nextRoom.adj.add(temp.currentRoom);
                num--;
            }// end of if
        }// end of while
    }


     // name the room to display
    private int roomNumber = 0;
    /**
     * Sets the grid of rooms to be initially boxes
     * This is self explanitory, we are only creating an reverse L for all
     * The rooms and there is an L for the border
     */
    private void generateInitialRooms() {
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                // create north walls
                rooms[i][j] = new Room(i, j);
                if (i == 0) {
                    rooms[i][j].north = new Wall(rooms[i][j]);
                } else {
                    rooms[i][j].north = new Wall(rooms[i - 1][j], rooms[i][j]);
                    walls.add(rooms[i][j].north);
                }
                if (i == height - 1) {
                    rooms[i][j].south = new Wall(rooms[i][j]);
                }
                if (j == 0) {
                    rooms[i][j].west = new Wall(rooms[i][j]);
                } else {
                    rooms[i][j].west = new Wall(rooms[i][j - 1], rooms[i][j]);
                    walls.add(rooms[i][j].west);
                }
                if (j == width - 1) {
                    rooms[i][j].east = new Wall(rooms[i][j]);
                }
                rooms[i][j].roomName = roomNumber++;// we will name the rooms
            }
        }
        // initalize entrance and exit
        rooms[0][0].west.isGone = true;// you can replace .west.isGone with .north.isGone
        // this is just saying the roomName for top left is 0 
        rooms[0][0].roomName = 0;
        // we will remove the south wall of the last room
        rooms[height - 1][width - 1].south.isGone = true;
        // this is just saying the roomName for bottom right is the last element in the mxn room matrix
        rooms[height - 1][width - 1].roomName = (height * width);
    }

Voila, the initialization and the maze is joined with only one path from start to finish lets display it on our panel(I like to call this my art canvas).

   // The code will display the maze
   // I urge you to play with the variable 
   // values to see how this portion of the 
   // code works and changes
   public void paintComponent(Graphics g) {
        x_cord = 40;
        y_cord = 40;
        // could have taken height as well as width
        // just need something to base the roomsize
        roomSize = (width - x_cord) / width + 7;

        // temp variables used for painting
        int x = x_cord;
        int y = y_cord;

        for (int i = 0; i <= height - 1; i++) {
            for (int j = 0; j <= width - 1; j++) {
                if (!(rooms[i][j].north.isGone)) {
                    g.drawLine(x, y, x + roomSize, y);
                }//end of north if
                // west wall not there draw the line
                if (rooms[i][j].west.isGone == false) {
                    g.drawLine(x, y, x, y + roomSize);
                }// end of west if
                if ((i == height - 1) && rooms[i][j].south.isGone == false) {
                    g.drawLine(x, y + roomSize, x + roomSize,
                            y + roomSize);
                }// end of south if
                if ((j == width - 1) && rooms[i][j].east.isGone == false) {
                    g.drawLine(x + roomSize, y, x + roomSize,
                            y + roomSize);
                }// end of east if
                x += roomSize;// change the horizontal
            }// end of inner for loop
            x = x_cord;
            y += roomSize;
        }// end of outer for loop
   }

Finally, we can create the main method for our code. This should be very clear and doesnt need detail(If not ask in comments).
   public static void main(String[] args) {
        // we will use the scanner for userInput
        Scanner userInput = new Scanner(System.in);
        int m, n;// these are variables for the size of maze (m x n)
        System.out.print("Enter the size of your maze: ");
        // store the input
        m = userInput.nextInt();
        n = userInput.nextInt();
        // use JFrame to put the created panel on
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(500, 800);
        frame.getContentPane().add(new Maze(m, n));
        frame.pack();
        frame.setVisible(true);
    }// end of main

Here is the complete code from our main class
import java.awt.Dimension;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;

import javax.swing.JFrame;
import javax.swing.JPanel;


public class Maze extends JPanel {

    private Room[][] rooms;// m x n matrix of rooms
    private ArrayList<Wall> walls; // List of walls
    private Random rand;// for random wall
    private int height;// height of matrix
    private int width;// width of matrix
    private int num;// incrementor
    private JoinRoom ds;// union paths

    // paint methods //
    private int x_cord; // x-axis rep
    private int y_cord;// y-axis rep
    private int roomSize;
    private int randomWall;
	
    public Maze(int height, int width) {
        this.height = height;
        this.width = width;
        rooms = new Room[height][width];
        walls = new ArrayList<Wall>((height - 1) * (width - 1));
        generateRandomMaze();
        setPreferredSize(new Dimension(800, 700));
   }
    private void generateRandomMaze() {
        generateInitialRooms();// see next method
        ds = new JoinRoom(width * height);
        rand = new Random(); // here is the random room generator
        num = width * height;

        while (num > 1) {
           // when we pick a random wall we want to avoid the borders getting eliminated
            randomWall = rand.nextInt(walls.size());
            Wall temp = walls.get(randomWall);
            // we will pick two rooms randomly 
            int roomA = temp.currentRoom.y + temp.currentRoom.x * width;
            int roomB = temp.nextRoom.y + temp.nextRoom.x * width;

            // check roomA and roomB to see if they are already members 
            if (ds.find(roomA) != ds.find(roomB)) {
                walls.remove(randomWall);
                ds.unionRooms(ds.find(roomA), ds.find(roomB));
                temp.isGone = true;
                temp.currentRoom.adj.add(temp.nextRoom);
                temp.nextRoom.adj.add(temp.currentRoom);
                num--;
            }// end of if
        }// end of while
    }

     // name the room to display
    private int roomNumber = 0;
    /**
     * Sets the grid of rooms to be initially boxes
     * This is self explanitory, we are only creating an reverse L for all
     * The rooms and there is an L for the border
     */
    private void generateInitialRooms() {
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                // create north walls
                rooms[i][j] = new Room(i, j);
                if (i == 0) {
                    rooms[i][j].north = new Wall(rooms[i][j]);
                } else {
                    rooms[i][j].north = new Wall(rooms[i - 1][j], rooms[i][j]);
                    walls.add(rooms[i][j].north);
                }
                if (i == height - 1) {
                    rooms[i][j].south = new Wall(rooms[i][j]);
                }
                if (j == 0) {
                    rooms[i][j].west = new Wall(rooms[i][j]);
                } else {
                    rooms[i][j].west = new Wall(rooms[i][j - 1], rooms[i][j]);
                    walls.add(rooms[i][j].west);
                }
                if (j == width - 1) {
                    rooms[i][j].east = new Wall(rooms[i][j]);
                }
                rooms[i][j].roomName = roomNumber++;// we will name the rooms
            }
        }
        // initalize entrance and exit
        rooms[0][0].west.isGone = true;// you can replace .west.isGone with .north.isGone
        // this is just saying the roomName for top left is 0 
        rooms[0][0].roomName = 0;
        // we will remove the south wall of the last room
        rooms[height - 1][width - 1].south.isGone = true;
        // this is just saying the roomName for bottom right is the last element in the mxn room matrix
        rooms[height - 1][width - 1].roomName = (height * width);
    }
	
	 public void paintComponent(Graphics g) {
        x_cord = 40;
        y_cord = 40;
        // could have taken height as well as width
        // just need something to base the roomsize
        roomSize = (width - x_cord) / width + 7;

        // temp variables used for painting
        int x = x_cord;
        int y = y_cord;

        for (int i = 0; i <= height - 1; i++) {
            for (int j = 0; j <= width - 1; j++) {
                if (!(rooms[i][j].north.isGone)) {
                    g.drawLine(x, y, x + roomSize, y);
                }//end of north if
                // west wall not there draw the line
                if (rooms[i][j].west.isGone == false) {
                    g.drawLine(x, y, x, y + roomSize);
                }// end of west if
                if ((i == height - 1) && rooms[i][j].south.isGone == false) {
                    g.drawLine(x, y + roomSize, x + roomSize,
                            y + roomSize);
                }// end of south if
                if ((j == width - 1) && rooms[i][j].east.isGone == false) {
                    g.drawLine(x + roomSize, y, x + roomSize,
                            y + roomSize);
                }// end of east if
                x += roomSize;// change the horizontal
            }// end of inner for loop
            x = x_cord;
            y += roomSize;
        }// end of outer for loop
   }
   
   public static void main(String[] args) {
        // we will use the scanner for userInput
        Scanner userInput = new Scanner(System.in);
        int m, n;// these are variables for the size of maze (m x n)
        System.out.print("Enter the size of your maze: ");
        // store the input
        m = userInput.nextInt();
        n = userInput.nextInt();
        // use JFrame to put the created panel on
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(500, 800);
        frame.getContentPane().add(new Maze(m, n));
        frame.pack();
        frame.setVisible(true);
    }// end of main
}// END OF CLASS 

That concludes the tutorial on maze creation. Enjoy.

Optional things you should try with this maze program:
1. Print the maze to a txt file
2. Accept a text file to generate maze
3. Display the solution to the maze(hint: add dijkstra(), leftHand(), or anotherAlgorithm(search for path) and dont forget to modify paintComponent() method when solved
  • 4


#590276 Tutorial: The Beauty of Ruby with strings

Posted by mr mike on 04 February 2011 - 10:35 AM

@John
You are correct, however using '5' + '6' is only temporary. Let's assume you assigned '5' to a string.
str = '5'
str + '6' # produces the string "56" or using interactive ruby 
#=>"56"  
# now type str and the result is 5
str

# using irb you can test this the result will look like:
# => "5"

#If you wand to assign the 6 to 5 use <<
'5' << '6' # this makes the string "56"
#similarly, adding it to the variable can be typed 
str <<  '6'

# now type str
str
#=> "56" will be the result


  • 1


#586394 Installing Ruby

Posted by mr mike on 05 January 2011 - 08:35 PM

The purpose of this tutorial is straight forward, and the most important, install ruby on your system. Lets begin our journey into learning a fun language.

WINDOWS- The hardest, but not really

First download the ruby installer...
Second install...
Third, you now have a couple things after the install...

1. Use the tools in the start menu folder:

a. click ruby
b. use interactive ruby
type:
puts "Welcome to the World of Ruby"

displays:
Welcome to the World of Ruby
=> nil

or

a. open ruby with command prompt
b. use txt editor and start coding(I use notepad++)
just type:
puts "Welcome to the World of Ruby"
save as welcome.rb
c. run your .rb file
C:\"path"\> ruby welcome.rb

2. Set your class path to run from command prompt if not recognized initially
a. Long way

- search: view advanced system settings and select

- click environment variables

- Check PATHEXT has the following %PATHE%;.RB;.RBW
if this is not there edit it
enter: %PATHEXT%;.RB;.RBW

- edit Path
enter: C:\Ruby192\bin

note: C:\Rubyxxx\bin where xxx is the version ie. if 1.8
C:\Ruby18\bin (to know which version open your C:\ folder
the folder to enter will be there

Now you can open command prompt and type irb for interactive ruby or run a .rb file by using
the command ruby "file".rb
... time to play!

LINUX is even simpler

Fedora example
yum install ruby(version)-full
yum install ruby-full

Now open your command prompt and type:
irb or ruby "file".rb
... time to play!

Take a look at the other three tutorials for an idea of the language. The api can be found here.

Also, thanks to Roger and the rest of codecall.net for the addition of this section.
  • 3


#584938 Question Regarding Best Hardware Specs For Programming.

Posted by mr mike on 23 December 2010 - 06:46 PM

Unless you do work for massive dynamic(Fringe reference) any computer will work for programming. I use a dell inspiron n4010 for programming laptop(only $600).
  • -1


#584819 Win7 CHKDSK Freezes and can not be skipped

Posted by mr mike on 22 December 2010 - 04:58 PM

I suggest using a linux live disk such as knoppix to access all of your files you need to save.
Then reinstall windows.
  • 1


#571640 Java Game Ideas

Posted by mr mike on 28 August 2010 - 07:44 AM

You should start by make a 2D game,
using timer and paint. Something similar to
space invaders or another retro
game, pitfall (but with a gun).
If you want to create a pitfall like game,
i will contribute! Just design the game first before
coding. Think of the actions of everything(characters,
weapons, ect.)
  • 1


Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download