I am working on this algorithm and cant figure out why I am always getting a null return. The code adds to two arrays fx, fy it collects the x and y positions that will complete the maze with the shortest path. The issue is that nothing is being added to the array. Any suggestions?
public class Maze {
public List<Integer> fx;
public List<Integer> fy;
public int listSize;
public Point p;
public int[][] cells;
public Maze(int x, int y, int[][] cells) {
p = getPathBFS(x, y, cells);
this.cells = cells;
fx = new ArrayList<>();
fy = new ArrayList<>();
addPoint();
}
private static class Point {
int x;
int y;
Point parent;
public Point(int x, int y, Point parent) {
this.x = x;
this.y = y;
this.parent = parent;
}
public Point getParent() {
return this.parent;
}
}
public static Queue<Point> q = new LinkedList<>();
public Point getPathBFS(int x, int y, int[][] cells) {
q.add(new Point(x, y, null));
while (!q.isEmpty()) {
Point p = q.remove();
if (cells[p.x][p.y] == 9) {
return p;
}
if (isFree(p.x + 1, p.y, cells.length, cells)) {
cells[p.x][p.y] = 2;
Point nextP = new Point(p.x + 1, p.y, p);
q.add(nextP);
}
if (isFree(p.x - 1, p.y, cells.length, cells)) {
cells[p.x][p.y] = 2;
Point nextP = new Point(p.x - 1, p.y, p);
q.add(nextP);
}
if (isFree(p.x, p.y + 1, cells.length, cells)) {
cells[p.x][p.y] = 2;
Point nextP = new Point(p.x, p.y + 1, p);
q.add(nextP);
}
if (isFree(p.x, p.y - 1, cells.length, cells)) {
cells[p.x][p.y] = 2;
Point nextP = new Point(p.x, p.y - 1, p);
q.add(nextP);
}
}
return null;
}
public static boolean isFree(int x, int y, int cellLength, int[][] cells) {
if ((x >= 0 && x < cellLength) && (y >= 0 && y < cells[x].length) && (cells[x][y] == 0 || cells[x][y] == 9)) {
return true;
}
return false;
}
public synchronized void addPoint() {
System.out.println(p);
while ((p != null)) {
System.out.println("x is " + p.x + " - y is " + p.y);
fy.add(p.x);
fx.add(p.y);
p = p.getParent();
}
}
int getListSize() {
listSize = fx.size() - 1;
return listSize;
}
}
I am trying to make a path finding program to play snake and I have ran into a problem. I made this class to use the A* algorithm. It accumulates more cells than are on the board and never finds the target.
import java.awt.Color;
import java.util.Collections;
import java.util.LinkedList;
public class AStar {
public static class Cell implements Comparable<Cell> {
public int F, H, G, x, y;
public Cell parent;
public Cell(int x, int y) {
this.x = x;
this.y = y;
}
#Override
public int compareTo(Cell o) {
return F < o.F ? -1 : F > o.F ? 1 : 0;
}
}
public static boolean at(int x, int y, LinkedList<Block> l) {
for (int i = 0; i < l.size(); i++) {
Block b = l.get(i);
if (b != null && b.getX() == x && b.getY() == y) {
return true;
}
}
return false;
}
public static LinkedList<Block> compute(int x, int y, Block t, LinkedList<Block> s, int w, int h) {
LinkedList<Block> path = new LinkedList<Block>();
LinkedList<Cell> open = new LinkedList<Cell>();
LinkedList<Cell> closed = new LinkedList<Cell>();
Cell current = getCell(s.getFirst().getX(), s.getFirst().getY(), t, null);
current.F = 0;
open.add(current);
while (true) {
current = open.poll();
System.out.println("X=" + current.x + " Y=" + current.y + " FOODX=" + t.getX() + " FOODY=" + t.getY());
closed.add(current);
if (current.x == t.getX() && current.y == t.getY()) {
break;
}
Cell c = getCell(current.x + 20, current.y, t, current);
if (!at(c.x, c.y, s) && !closed.contains(c) && !(c.x > w)) {
if (c.F < current.F || !open.contains(c)) {
open.add(c);
}
}
c = getCell(current.x - 20, current.y, t, current);
if (!at(c.x, c.y, s) && !closed.contains(c) && !(c.x < 0)) {
if (c.F < current.F || !open.contains(c)) {
open.add(c);
}
}
c = getCell(current.x, current.y + 20, t, current);
if (!at(c.x, c.y, s) && !closed.contains(c) && !(c.y > h)) {
if (c.F < current.F || !open.contains(c)) {
open.add(c);
}
}
c = getCell(current.x, current.y - 20, t, current);
if (!at(c.x, c.y, s) && !closed.contains(c) && !(c.y < 0)) {
if (c.F < current.F || !open.contains(c)) {
open.add(c);
}
}
Collections.sort(open);
System.out.println("" + open.size());
}
while (current.parent != null) {
path.add(new Block(current.parent.x, current.parent.y, Color.blue));
current = current.parent;
}
return path;
}
public static Cell getCell(int x, int y, Block t, Cell parent) {
Cell cell = new Cell(x, y);
cell.H = Math.abs(x - t.getX()) + Math.abs(y - t.getY());
if (parent != null) {
cell.parent = parent;
cell.G = 20 + parent.G;
}
cell.F = cell.G + cell.H;
return cell;
}
}
Help would be greatly appreciated, Thanks.
Currently i'm using LWJGL to make a 2D game. But I've run into an issue. I am trying to make an "infinite world" but an issue comes up because if I create a lot of objects the frames drop and I believe it has to do with the amount of textures being loaded to objects.
Currently I'm creating my world in a grid fashion like this
for(int x = -WORLDWIDTH; x < WORLDWIDTH; x+= BW)
{
for(int y = -WORLDHEIGHT; y < WORLDHEIGHT; y += BH)
{
Tile newTile = new Tile(x,y,BW,BH,TileType.Grass);
tiles.add(newTile);
}
}
Where BW and BH are the block width and height. I try to keep texture loading to only objects on screen using this if statement
if(x >= 0-BW && x + width < WIDTH+BW && y >= 0-BH && y+ height < HEIGHT+BH)
{
DrawQuadTexRotate(getTexture(), getX(), getY(), getWidth(),getHeight(),angle);
}
To load textures I do this
public static void DrawQuadTexRotate(Texture tex, float x, float y, float width, float height, float angle)
{
tex.bind();
glTranslatef(x + width / 2, y + height / 2, 0);
glRotatef(angle, 0 ,0 , 1);
glTranslatef(- width / 2, - height / 2, 0);
glBegin(GL_QUADS);
glTexCoord2f(0,0);
glVertex2f(0,0);
glTexCoord2f(1,0);
glVertex2f(width,0);
glTexCoord2f(1,1);
glVertex2f(width,height);
glTexCoord2f(0,1);
glVertex2f(0,height);
glEnd();
glLoadIdentity();
}
public static Texture LoadTexture(String path, String fileType)
{
Texture tex = null;
InputStream in = ResourceLoader.getResourceAsStream(path);
try {
tex = TextureLoader.getTexture(fileType, in);
} catch (IOException e) {
e.printStackTrace();
}
return tex;
}
The Tile class basically has methods to do certain things based on what type it is. It holds the width, height, x, y and texture which my DrawQuadTex method uses
Here is the tile class
public class Tile {
public float x, y, width, height, angle;
private Texture texture;
private TileType type;
public long timeStart = 0;
public int filled = 1;
public int power = 0;
public int transmitPower = 0;
int connected = 0;
public boolean moveRight,moveLeft,moveUp,moveDown,moveAngle;
public Tile(float x, float y, float width, float height,TileType type)
{
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.type = type;
this.texture = QuickLoad(type.textureName);
timeStart = Timer.getTime();
updateType();
updateFill();
}
public void draw()
{
if(x >= 0-BW && x + width < WIDTH+BW && y >= 0-BH && y+ height < HEIGHT+BH)
{
DrawQuadTexRotate(getTexture(), getX(), getY(), getWidth(),getHeight(),angle);
}
}
public void addFood()
{
if(this.type == TileType.Farm && filled == 1)
{
long timing = Timer.getTime();
if(timing >= (timeStart + 10000))
{
Values.food += (1+Artist.riverAmount);
timeStart = timing;
}
}
}
public void mineOre()
{
if(this.type == TileType.Mine && filled == 1)
{
long timing = Timer.getTime();
if(timing >= (timeStart + 20000))
{
for(int i = 0; i < tiles.size();i++)
{
if(tiles.get(i).getType() == TileType.Ore)
{
tiles.get(i).setType(TileType.LandTile);
Values.oreAmount += 1;
timeStart = timing;
break;
}
}
}
}
}
public void move()
{
if(moveRight == true)
{
x -= 10;
}
if(moveLeft == true)
{
x += 10;
}
if(moveUp == true)
{
y += 10;
}
if(moveDown == true)
{
y -= 10;
}
}
public void testPower()
{
for(int i = 0; i < tiles.size(); i++)
{
if(tiles.get(i).x >= x - BW && tiles.get(i).x <= x + BW && tiles.get(i).y >= y - BH && tiles.get(i).y <= y + BH && tiles.get(i).getType() == TileType.Wire && tiles.get(i).transmitPower == 1 && type == TileType.HomeBasic)
{
power = 1;
break;
}
else
{
power = 0;
}
if(tiles.get(i).x >= x - BW && tiles.get(i).x <= x + BW && tiles.get(i).y >= y - BH && tiles.get(i).y <= y + BH && (tiles.get(i).transmitPower == 1 || tiles.get(i).type == TileType.PowerPlant) && type == TileType.Wire)
{
transmitPower = 1;
break;
}
else if(tiles.get(i).type == TileType.Wire && tiles.get(i).transmitPower == 0)
{
transmitPower = 0;
}
else
{
transmitPower = 0;
}
}
}
public void updateFill()
{
if(type == TileType.HomeBasic || type == TileType.Farm || type == TileType.Mine)
{
filled = 0;
}
}
public void stats()
{
if(type == TileType.HomeBasic)
{
//wt.drawString((int)x, (int)(y-25), Integer.toString(filled), Color.white);
}
}
public float getX() {
return x;
}
public void setX(float x) {
this.x = x;
}
public float getY() {
return y;
}
public void setY(float y) {
this.y = y;
}
public float getWidth() {
return width;
}
public void setWidth(float width) {
this.width = width;
}
public float getHeight() {
return height;
}
public void setHeight(float height) {
this.height = height;
}
public Texture getTexture() {
return texture;
}
public void setTexture(Texture texture) {
this.texture = texture;
}
public TileType getType() {
return type;
}
public void setType(TileType type) {
this.type = type;
updateType();
}
public void updateType()
{
this.texture = QuickLoad(type.textureName);
timeStart = Timer.getTime();
updateFill();
}
}
public static Texture QuickLoad(String name)
{
Texture tex = null;
tex = LoadTexture("res/" + name + ".png", "PNG");
return tex;
}
So how would I go about trying to fix this?
So I have code that runs, but I need to write the test for one of the classes (Cells) and I'm not sure how to go about this.
Typically, I'd have a helper class at the start of CellsTest, which would encapsulate the constructor call, which relies on the specific class name of the class that implements the overall program. This helper class would return an instance of that program.
So, what I'd think is that I'd need to have something like:
private Maze createMaze() {
return new Maze();
}
But then, my test methods can't access the Cell methods, just the Maze methods...So I'm guessing that that is wrong, and I'm not sure how I should actually be doing this.
//Maze.java
package falstad;
import java.awt.*;
import java.util.ArrayList;
import java.util.Iterator;
/**
* Class handles the user interaction for the maze.
*/
//public class Maze extends Panel {
public class Maze {
final private ArrayList<Viewer> views = new ArrayList<Viewer>() ;
MazePanel panel ; // graphics to draw on, shared by all views
private int state;
private int percentdone = 0;
private boolean showMaze;
private boolean showSolution;
private boolean solving;
private boolean mapMode;
//static final int viewz = 50;
int viewx, viewy, angle;
int dx, dy;
int px, py ;
int walkStep;
int viewdx, viewdy;
boolean deepdebug = false;
boolean allVisible = false;
boolean newGame = false;
int mazew; // width
int mazeh; // height
Cells mazecells ;
Distance mazedists ;
Cells seencells ;
BSPNode rootnode ;
// Mazebuilder is used to calculate a new maze together with a solution
// The maze is computed in a separate thread. It is started in the local Build method.
MazeBuilder mazebuilder;
final int ESCAPE = 27;
int method = 0 ; // 0 : default method, Falstad's original code
int zscale = Constants.VIEW_HEIGHT/2;
private RangeSet rset;
//Constructor
public Maze() {
super() ;
panel = new MazePanel() ;
}
//selects a generation method
public Maze(int method)
{
super() ;
if (1 == method)
this.method = 1 ;
panel = new MazePanel() ;
}
public void init() {
state = Constants.STATE_TITLE;
rset = new RangeSet();
panel.initBufferImage() ;
addView(new MazeView(this)) ;
notifyViewerRedraw() ;
}
// Method obtains a new Mazebuilder and computes new maze
private void build(int skill) {
state = Constants.STATE_GENERATING;
percentdone = 0;
notifyViewerRedraw() ;
// select generation method
switch(method){
case 1 : mazebuilder = new MazeBuilderPrim();
break ;
case 0:
default : mazebuilder = new MazeBuilder();
break ;
}
mazew = Constants.SKILL_X[skill];
mazeh = Constants.SKILL_Y[skill];
mazebuilder.build(this, mazew, mazeh, Constants.SKILL_ROOMS[skill], Constants.SKILL_PARTCT[skill]);
}
//Call back method for MazeBuilder to communicate newly generated maze
public void newMaze(BSPNode root, Cells c, Distance dists, int startx, int starty) {
if (Cells.deepdebugWall)
{
c.saveLogFile(Cells.deepedebugWallFileName);
}
showMaze = showSolution = solving = false;
mazecells = c ;
mazedists = dists;
seencells = new Cells(mazew+1,mazeh+1) ;
rootnode = root ;
setCurrentDirection(1, 0) ;
setCurrentPosition(startx,starty) ;
walkStep = 0;
viewdx = dx<<16;
viewdy = dy<<16;
angle = 0;
mapMode = false;
state = Constants.STATE_PLAY;
cleanViews() ;
addView(new FirstPersonDrawer(Constants.VIEW_WIDTH,Constants.VIEW_HEIGHT,
Constants.MAP_UNIT,Constants.STEP_SIZE, mazecells, seencells, 10, mazedists.getDists(), mazew, mazeh, root, this)) ;
addView(new MapDrawer(Constants.VIEW_WIDTH,Constants.VIEW_HEIGHT,Constants.MAP_UNIT,Constants.STEP_SIZE, mazecells, seencells, 10, mazedists.getDists(), mazew, mazeh, this)) ;
notifyViewerRedraw() ;
}
public void addView(Viewer view) {
views.add(view) ;
}
public void removeView(Viewer view) {
views.remove(view) ;
}
private void cleanViews() {
Iterator<Viewer> it = views.iterator() ;
while (it.hasNext())
{
Viewer v = it.next() ;
if ((v instanceof FirstPersonDrawer)||(v instanceof MapDrawer))
{
//System.out.println("Removing " + v);
it.remove() ;
}
}
}
private void notifyViewerRedraw() {
Iterator<Viewer> it = views.iterator() ;
while (it.hasNext())
{
Viewer v = it.next() ;
v.redraw(panel.getBufferGraphics(), state, px, py, viewdx, viewdy, walkStep, Constants.VIEW_OFFSET, rset, angle) ;
}
panel.update() ;
}
private void notifyViewerIncrementMapScale() {
Iterator<Viewer> it = views.iterator() ;
while (it.hasNext())
{
Viewer v = it.next() ;
v.incrementMapScale() ;
}
panel.update() ;
}
private void notifyViewerDecrementMapScale() {
Iterator<Viewer> it = views.iterator() ;
while (it.hasNext())
{
Viewer v = it.next() ;
v.decrementMapScale() ;
}
panel.update() ;
}
boolean isInMapMode() {
return mapMode ;
}
boolean isInShowMazeMode() {
return showMaze ;
}
boolean isInShowSolutionMode() {
return showSolution ;
}
public String getPercentDone(){
return String.valueOf(percentdone) ;
}
public Panel getPanel() {
return panel ;
}
private void setCurrentPosition(int x, int y)
{
px = x ;
py = y ;
}
private void setCurrentDirection(int x, int y)
{
dx = x ;
dy = y ;
}
void buildInterrupted() {
state = Constants.STATE_TITLE;
notifyViewerRedraw() ;
mazebuilder = null;
}
final double radify(int x) {
return x*Math.PI/180;
}
public boolean increasePercentage(int pc) {
if (percentdone < pc && pc < 100) {
percentdone = pc;
if (state == Constants.STATE_GENERATING)
{
notifyViewerRedraw() ;
}
else
dbg("Warning: Receiving update request for increasePercentage while not in generating state, skip redraw.") ;
return true ;
}
return false ;
}
private void dbg(String str) {
//System.out.println(str);
}
private void logPosition() {
if (!deepdebug)
return;
dbg("x="+viewx/Constants.MAP_UNIT+" ("+
viewx+") y="+viewy/Constants.MAP_UNIT+" ("+viewy+") ang="+
angle+" dx="+dx+" dy="+dy+" "+viewdx+" "+viewdy);
}
private boolean checkMove(int dir) {
int a = angle/90;
if (dir == -1)
a = (a+2) & 3;
return mazecells.hasMaskedBitsFalse(px, py, Constants.MASKS[a]) ;
}
private void rotateStep() {
angle = (angle+1800) % 360;
viewdx = (int) (Math.cos(radify(angle))*(1<<16));
viewdy = (int) (Math.sin(radify(angle))*(1<<16));
moveStep();
}
private void moveStep() {
notifyViewerRedraw() ;
try {
Thread.currentThread().sleep(25);
} catch (Exception e) { }
}
private void rotateFinish() {
setCurrentDirection((int) Math.cos(radify(angle)), (int) Math.sin(radify(angle))) ;
logPosition();
}
private void walkFinish(int dir) {
setCurrentPosition(px + dir*dx, py + dir*dy) ;
if (isEndPosition(px,py)) {
state = Constants.STATE_FINISH;
notifyViewerRedraw() ;
}
walkStep = 0;
logPosition();
}
private boolean isEndPosition(int x, int y) {
return x < 0 || y < 0 || x >= mazew || y >= mazeh;
}
synchronized private void walk(int dir) {
if (!checkMove(dir))
return;
for (int step = 0; step != 4; step++) {
walkStep += dir;
moveStep();
}
walkFinish(dir);
}
synchronized private void rotate(int dir) {
final int originalAngle = angle;
final int steps = 4;
for (int i = 0; i != steps; i++) {
angle = originalAngle + dir*(90*(i+1))/steps;
rotateStep();
}
rotateFinish();
}
//CLASS CONTROLLING PLAYER MOVEMENTS, REMOVED FOR CHARACTER COUNT
}
}
//Cells.java
package falstad;
import java.io.BufferedWriter;
import java.io.FileWriter;
//This class encapsulates all access to a grid of cells
public class Cells {
private int width;
private int height ;
private int[][] cells;
public Cells(int w, int h) {
width = w ;
height = h ;
cells = new int[w][h];
}
public Cells(int[][] target){
this(target.length, target[0].length);
for (int i=0; i<width; i++)
for (int j=0; j<height; j++)
this.cells[i][j]=target[i][j];
}
public int getCells( int x, int y )
{
return cells[x][y] ;
}
static public int[] getMasks() {
return Constants.MASKS ;
}
public boolean canGo(int x, int y, int dx, int dy) {
if (hasMaskedBitsTrue(x, y, (getBit(dx, dy) << Constants.CW_BOUND_SHIFT)))
return false;
return isFirstVisit(x+dx, y+dy);
}
private int getBit(int dx, int dy) {
int bit = 0;
switch (dx + dy * 2) {
case 1: bit = Constants.CW_RIGHT; break;
case -1: bit = Constants.CW_LEFT; break;
case 2: bit = Constants.CW_BOT; break;
case -2: bit = Constants.CW_TOP; break;
default: dbg("getBit problem "+dx+" "+dy); break;
}
return bit;
}
//CLASSES FOR BITWISE ADJUSTMENTS, REMOVED FOR CHARACTER COUNT
public void initialize() {
int x, y;
for (x = 0; x != width; x++) {
for (y = 0; y != height; y++) {
setBitToOne(x, y, (Constants.CW_VISITED | Constants.CW_ALL));
}
setBitToOne(x, 0, Constants.CW_TOP_BOUND);
setBitToOne(x, height-1, Constants.CW_BOT_BOUND);
}
for (y = 0; y != height; y++) {
setBitToOne(0, y, Constants.CW_LEFT_BOUND);
setBitToOne(width-1, y, Constants.CW_RIGHT_BOUND);
}
}
public boolean areaOverlapsWithRoom(int rx, int ry, int rxl, int ryl) {
int x, y;
for (x = rx-1; x <= rxl+1; x++)
{
for (y = ry-1; y <= ryl+1; y++)
{
if (isInRoom(x, y))
return true ;
}
}
return false ;
}
private void deleteBound(int x, int y, int dx, int dy) {
setBoundToZero(x, y, dx, dy);
setBoundToZero(x+dx, y+dy, -dx, -dy) ;
}
public void addBoundWall(int x, int y, int dx, int dy) {
setBoundAndWallToOne(x, y, dx, dy);
setBoundAndWallToOne(x+dx, y+dy, -dx, -dy);
}
public void deleteWall(int x, int y, int dx, int dy) {
setWallToZero(x, y, dx, dy);
setWallToZero(x+dx, y+dy, -dx, -dy);
if (deepdebugWall)
logWall( x, y, dx, dy);
public void markAreaAsRoom(int rw, int rh, int rx, int ry, int rxl, int ryl) {
int x;
int y;
for (x = rx; x <= rxl; x++)
for (y = ry; y <= ryl; y++) {
setAllToZero(x, y);
setInRoomToOne(x, y);
}
for (x = rx; x <= rxl; x++) {
addBoundWall(x, ry, 0, -1);
addBoundWall(x, ryl, 0, 1);
}
for (y = ry; y <= ryl; y++) {
addBoundWall(rx, y, -1, 0);
addBoundWall(rxl, y, 1, 0);
}
int wallct = (rw+rh)*2;
SingleRandom random = SingleRandom.getRandom() ;
for (int ct = 0; ct != 5; ct++) {
int door = random.nextIntWithinInterval(0, wallct-1);
int dx, dy;
if (door < rw*2) {
y = (door < rw) ? 0 : rh-1;
dy = (door < rw) ? -1 : 1;
x = door % rw;
dx = 0;
} else {
door -= rw*2;
x = (door < rh) ? 0 : rw-1;
dx = (door < rh) ? -1 : 1;
y = door % rh;
dy = 0;
}
deleteBound(x+rx, y+ry, dx, dy);
}
}
public boolean hasMaskedBitsTrue(int x, int y, int bitmask) {
return (cells[x][y] & bitmask) != 0;
}
public boolean isInRoom(int x, int y) {
return hasMaskedBitsTrue(x, y, Constants.CW_IN_ROOM);
}
private boolean isFirstVisit(int x, int y) {
return hasMaskedBitsTrue(x, y, Constants.CW_VISITED);
}
public boolean hasWallOnRight(int x, int y) {
return hasMaskedBitsTrue(x, y, Constants.CW_RIGHT);
}
public boolean hasWallOnLeft(int x, int y) {
return hasMaskedBitsTrue(x, y, Constants.CW_LEFT);
}
public boolean hasWallOnTop(int x, int y) {
return hasMaskedBitsTrue(x, y, Constants.CW_TOP);
}
public boolean hasWallOnBottom(int x, int y) {
return hasMaskedBitsTrue(x, y, Constants.CW_BOT);
}
public boolean hasNoWallOnBottom(int x, int y) {
return !hasMaskedBitsTrue(x, y, Constants.CW_BOT);
}
public boolean hasNoWallOnTop(int x, int y) {
return !hasMaskedBitsTrue(x, y, Constants.CW_TOP);
}
public boolean hasNoWallOnLeft(int x, int y) {
return !hasMaskedBitsTrue(x, y, Constants.CW_LEFT);
}
public boolean hasNoWallOnRight(int x, int y) {
return !hasMaskedBitsTrue(x, y, Constants.CW_RIGHT);
}
public boolean hasMaskedBitsFalse(int x, int y, int bitmask) {
return (cells[x][y] & bitmask) == 0;
}
public boolean hasMaskedBitsGTZero(int x, int y, int bitmask) {
return (cells[x][y] & bitmask) > 0;
}
private void dbg(String str) {
System.out.println("Cells: "+str);
}
public String toString() {
String s = "" ;
for (int i = 0 ; i < width ; i++)
{
for (int j = 0 ; j < height ; j++)
s += " i:" + i + " j:" + j + "=" + cells[i][j] ;
s += "\n" ;
}
return s ;
}
static boolean deepdebugWall = false;
static final String deepedebugWallFileName = "logDeletedWalls.txt" ;
StringBuffer traceWall = (deepdebugWall) ? new StringBuffer("x y dx dy\n") : null ;
private void logWall(int x, int y, int dx, int dy) {
if (null != traceWall)
{
traceWall.append(x + " " + y + " " + dx + " " + dy + "\n");
}
}
public void saveLogFile( String filename )
{
try {
BufferedWriter out = new BufferedWriter(new FileWriter(filename));
out.write(traceWall.toString());
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
//MazeBuilder.java
package falstad;
public class MazeBuilder implements Runnable {
protected int width, height ;
Maze maze;
private int rooms;
int expectedPartiters;
protected int startx, starty ;
protected Cells cells;
protected Distance dists ;
protected SingleRandom random ;
Thread buildThread;
public MazeBuilder(){
random = SingleRandom.getRandom();
}
public MazeBuilder(boolean deterministic){
if (true == deterministic)
{
System.out.println("Project 2: functionality to make maze generation deterministic not implemented yet! Fix this!");
}
random = SingleRandom.getRandom();
}
static int getSign(int num) {
return (num < 0) ? -1 : (num > 0) ? 1 : 0;
}
protected void generate() {
generatePathways();
final int[] remote = dists.computeDistances(cells) ;
final int[] pos = dists.getStartPosition();
startx = pos[0] ;
starty = pos[1] ;
setExitPosition(remote[0], remote[1]);
}
protected void generatePathways() {
int[][] origdirs = new int[width][height] ;
int x = random.nextIntWithinInterval(0, width-1) ;
int y = 0;
final int firstx = x ;
final int firsty = y ;
int dir = 0;
int origdir = dir;
cells.setVisitedFlagToZero(x, y);
while (true) {
int dx = Constants.DIRS_X[dir];
int dy = Constants.DIRS_Y[dir];
if (!cells.canGo(x, y, dx, dy)) {
dir = (dir+1) & 3;
if (origdir == dir) {
if (x == firstx && y == firsty)
break;
int odr = origdirs[x][y];
dx = Constants.DIRS_X[odr];
dy = Constants.DIRS_Y[odr];
x -= dx;
y -= dy;
origdir = dir = random.nextIntWithinInterval(0, 3);
}
} else {
cells.deleteWall(x, y, dx, dy);
x += dx;
y += dy;
cells.setVisitedFlagToZero(x, y);
origdirs[x][y] = dir;
origdir = dir = random.nextIntWithinInterval(0, 3);
}
}
}
protected void setExitPosition(int remotex, int remotey) {
int bit = 0;
if (remotex == 0)
bit = Constants.CW_LEFT;
else if (remotex == width-1)
bit = Constants.CW_RIGHT;
else if (remotey == 0)
bit = Constants.CW_TOP;
else if (remotey == height-1)
bit = Constants.CW_BOT;
else
dbg("Generate 1");
cells.setBitToZero(remotex, remotey, bit);
//System.out.println("exit position set to zero: " + remotex + " " + remotey + " " + bit + ":" + cells.hasMaskedBitsFalse(remotex, remotey, bit)
// + ", Corner case: " + ((0 == remotex && 0 == remotey) || (0 == remotex && height-1 == remotey) || (width-1 == remotex && 0 == remotey) || (width-1 == remotex && height-1 == remotey)));
}
static final int MIN_ROOM_DIMENSION = 3 ;
static final int MAX_ROOM_DIMENSION = 8 ;
private boolean placeRoom() {
final int rw = random.nextIntWithinInterval(MIN_ROOM_DIMENSION, MAX_ROOM_DIMENSION);
if (rw >= width-4)
return false;
final int rh = random.nextIntWithinInterval(MIN_ROOM_DIMENSION, MAX_ROOM_DIMENSION);
if (rh >= height-4)
return false;
final int rx = random.nextIntWithinInterval(1, width-rw-1);
final int ry = random.nextIntWithinInterval(1, height-rh-1);
final int rxl = rx+rw-1;
final int ryl = ry+rh-1;
if (cells.areaOverlapsWithRoom(rx, ry, rxl, ryl))
return false ;
cells.markAreaAsRoom(rw, rh, rx, ry, rxl, ryl);
return true;
}
static void dbg(String str) {
System.out.println("MazeBuilder: "+str);
}
public void build(Maze mz, int w, int h, int roomct, int pc) {
init(mz, w, h, roomct, pc);
buildThread = new Thread(this);
buildThread.start();
}
private void init(Maze mz, int w, int h, int roomct, int pc) {
maze = mz;
width = w;
height = h;
rooms = roomct;
expectedPartiters = pc;
cells = new Cells(w,h) ;
dists = new Distance(w,h) ;
//colchange = random.nextIntWithinInterval(0, 255);
}
static final long SLEEP_INTERVAL = 100 ;
try {
cells.initialize();
// rooms into maze
generateRooms();
Thread.sleep(SLEEP_INTERVAL) ;
// pathways into the maze,
generate();
Thread.sleep(SLEEP_INTERVAL) ;
final int colchange = random.nextIntWithinInterval(0, 255);
final BSPBuilder b = new BSPBuilder(maze, dists, cells, width, height, colchange, expectedPartiters) ;
BSPNode root = b.generateBSPNodes();
Thread.sleep(SLEEP_INTERVAL) ;
// dbg("partiters = "+partiters);
maze.newMaze(root, cells, dists, startx, starty);
}
catch (InterruptedException ex) {
// dbg("Catching signal to stop") ;
}
}
static final int MAX_TRIES = 250 ;
private int generateRooms() {
int tries = 0 ;
int result = 0 ;
while (tries < MAX_TRIES && result <= rooms) {
if (placeRoom())
result++ ;
else
tries++ ;
}
return result ;
}
public void interrupt() {
buildThread.interrupt() ;
}
}
Obviously, I'm not asking for someone to write a test for me - not that any of you would, as this is fairly obviously a homework assignment - but I'd like some help getting started on this. So if anyone could clue me into the surely obvious trick that I'm missing, that would be wonderful!
A unit test for Cells class can look like the below:
While you unit test the Cells class you might not need the Maze or MazeBuilder, you only need an instance of Cells class and call its methods in order to check that they work correctly isolated from the rest of the application.
Also take a look at this: Unit testing in Java - what is it? as it provides a good reference.
import org.junit.Assert;
import org.junit.Test;
public class CellsTest {
#Test
void testHasWallOnRight() {
//setup
int[][] target = new int[][] { { 0, 0, 0, 0 },
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 } };
Cells a = new Cells(target);
//act
boolean result = a.hasWallOnRight(1,1);
//assert
Assert.assertFalse(result);
}
}