/*
* Created on 2005-1-20
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
package com.savorjava.game.savormaze;
import java.util.Random;
import java.util.Stack;
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Graphics;
import com.savorjava.game.Action;
import com.savorjava.game.CoreCanvas;
import com.savorjava.game.Utility;
/**
* @author Colin
*
* The third phase: this action include all the game content, generating maze,
* controlling the robot, responsing the gamer and level checking.
*/
public class MazeRunAction extends Action {
public final byte INITIAL = 0;
public final byte RUN = 1;
public final byte PAUSE = 2;
public final byte STOP = 3;
public final byte PASS = 4;
public final byte EAST = 0x01;
public final byte SOUTH = 0x02;
public final byte WEST = 0x04;
public final byte NORTH = 0x08;
private byte status = INITIAL;
private short grid = 11;
private short maxGrid = 11;
private byte gridSize = 4;
// seed of random number.
private Random random = new Random(System.currentTimeMillis());
// this flag decide if the robot is running.
private boolean runingFlag = false;
// this flag decide if the robot should run in this game.
private boolean robotRun = false;
private short level = 1;
private Command nextCommand = new Command("Next", Command.SCREEN, 1);
private Command exitCommand = new Command("Exit", Command.EXIT, 1);
/**
* in java, a integer have 32 bits.
* 4 bits: robot solutions,
* 2 bits: keep, 1 bit: robot visited, 1 bit: visited,
* 4 bits: solutions,
* 4 bits: borders,
* 4 bits: walls
*/
private int[][] rooms = new int[0][0];
/**
* current location of room which gamer step to.
*/
private short[] hacker = {0, 0};
/**
* robot footprint: x, y, go to direction, come from direction.
*/
private short[] robot = {0, 0, EAST, WEST};
private Stack robotMemory = new Stack();
/**
* record the rooms which be drawn after gamer click direction button.
*/
private Stack roomsNeedDraw = new Stack();
public MazeRunAction(CoreCanvas cc)
{
super(cc);
}
/**
* initial all rooms in the maze according to size of maze,
* walls and borders will be up which present by 1.
*/
private void initialRooms()
{
int xSize = canvas.getWidth();
int ySize = canvas.getHeight();
short minSize = (short)(Utility.min(xSize, ySize));
maxGrid = (short)((minSize - 1) / gridSize);
rooms = new int[grid][grid];
// initial all the rooms: no visited and all the wall up.
for(int i = 0; i < grid; i++)
for(int j = 0; j < grid; j++)
{
rooms[i][j] = 0x000F;
}
// add border for the rooms which on the four sides.
for(int i = 0; i < grid; i++)
{
rooms[0][i] |= 0x0040;
rooms[grid - 1][i] |= 0x0010;
rooms[i][0] |= 0x0080;
rooms[i][grid - 1] |= 0x0020;
}
hacker[0] = 0;
hacker[1] = 0;
roomsNeedDraw.removeAllElements();
robot[0] = 0;
robot[1] = 0;
robot[2] = EAST;
robot[3] = WEST;
robotMemory.removeAllElements();
System.gc();
}
/**
* Game's status processor, creating random maze when status is INITIAL;
* drawing room which need be drawn after gamer click direction button as status
* is RUN; cleaning the maze and go to INITIAL when the status is PASS; if gamer
* arrived destination, PASS status will be set.
*/
public void perform(Graphics g)
{
if(status == INITIAL)
{
Stack stack = new Stack();
int totalRooms = grid * grid;
int visitedRooms = 1;
// room location: 1:x 2:y
int[] roomL = new int[2];
roomL[0] = random.nextInt() % grid;
roomL[1] = random.nextInt() % grid;
if(roomL[0] < 0)
{
roomL[0] = - roomL[0];
}
if(roomL[1] < 0)
{
roomL[1] = - roomL[1];
}
// set room to be visited by gamer.
rooms[roomL[0]][roomL[1]] |= 0x1000;
while(visitedRooms < totalRooms)
{
int[] neighbor = getRandomNeighbor(rooms, roomL[0], roomL[1]);
if(neighbor == null)
{
roomL = (int[])stack.pop();
}else
{
stack.push(neighbor);
rooms[neighbor[0]][neighbor[1]] |= 0x1000;
visitedRooms ++;
roomL = neighbor;
}
}
g.setColor(0xFFFFFF);
g.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());
drawMaze(g);
status = RUN;
}else if(status == RUN)
{
drawRoomsNeedDraw(g);
}else if(status == PASS)
{
grid += 2;
if(grid > maxGrid)
{
if(level == 0)
{
grid = 5;
}else if(level == 1)
{
grid = 11;
}else if(level == 2)
{
grid = 25;
}
}
initialRooms();
runingFlag = false;
status = INITIAL;
}
System.gc();
if(hacker[0] == grid - 1 && hacker[1] == grid - 1)
{
status = PASS;
}
}
/**
* just drawing the room which need be drawn after gamer click the buttons.
* @param g
*/
private void drawRoomsNeedDraw(Graphics g)
{
int increaseX = (canvas.getWidth() - grid * gridSize) / 2;
int increaseY = (canvas.getHeight() - grid * gridSize) / 2;
while(!roomsNeedDraw.empty())
{
int[] location = (int[])roomsNeedDraw.pop();
int dx = increaseX + location[0] * gridSize;
int dy = increaseY + location[1] * gridSize;
// repaint the room with withe exception four corner point.
g.setColor(0xFFFFFF);
g.fillRect(dx + 1, dy, gridSize - 1, gridSize);
g.fillRect(dx, dy + 1, gridSize, gridSize - 1);
drawRoom(g, rooms[location[0]][location[1]], dx, dy);
}
g.setColor(0x00FF00);
g.fillRect((grid - 1) * gridSize + 1 + increaseX,
(grid - 1) * gridSize + 1 + increaseY,
gridSize - 1,
gridSize - 1);
g.setColor(0x6666FF);
g.fillRect(robot[0] * gridSize + 1 + increaseX,
robot[1] * gridSize + 1 + increaseY,
gridSize - 1,
gridSize - 1);
g.setColor(0xFF0000);
g.fillRect(hacker[0] * gridSize + 1 + increaseX,
hacker[1] * gridSize + 1 + increaseY,
gridSize - 1,
gridSize - 1);
}
/**
* drawing whole initial random maze, including every room.
* @param g
*/
private void drawMaze(Graphics g)
{
// draw rooms.
int increaseX = (canvas.getWidth() - grid * gridSize) / 2;
int increaseY = (canvas.getHeight() - grid * gridSize) / 2;
for(int i = 0; i < grid; i++)
{
int dx = increaseX + i * gridSize;
for(int j = 0; j < grid; j++)
{
int dy = increaseY + j * gridSize;
drawRoom(g, rooms[i][j], dx, dy);
}
}
g.setColor(0x00FF00);
g.fillRect((grid - 1) * gridSize + 1 + increaseX,
(grid - 1) * gridSize + 1 + increaseY,
gridSize - 1,
gridSize - 1);
g.setColor(0xFF0000);
g.fillRect(hacker[0] * gridSize + 1 + increaseX,
hacker[1] * gridSize + 1 + increaseY,
gridSize - 1,
gridSize - 1);
}
/**
* just drawing a room, this method be invoked by other methods.
* @param g
* @param room
* @param dx
* @param dy
*/
private void drawRoom(Graphics g, int room, int dx, int dy)
{
// draw walls of rooms.
g.setColor(0x000000);
if((room & EAST) != 0)
{
g.drawLine(dx + gridSize, dy, dx + gridSize, dy + gridSize);
}
if((room & SOUTH) != 0)
{
g.drawLine(dx, dy + gridSize, dx + gridSize, dy + gridSize);
}
if((room & WEST) != 0)
{
g.drawLine(dx, dy, dx, dy + gridSize);
}
if((room & NORTH) != 0)
{
g.drawLine(dx, dy, dx + gridSize, dy);
}
// draw robot solution rooms.
g.setColor(0x6666FF);
if((room & 0x10000) != 0)
{
g.drawLine(dx + gridSize / 2, dy + gridSize / 2, dx + gridSize, dy + gridSize / 2);
}
if((room & 0x20000) != 0)
{
g.drawLine(dx + gridSize / 2, dy + gridSize / 2, dx + gridSize / 2, dy + gridS