initial commit for labryinth project on git_hub.
Signed-off-by: philippe lhardy <philippe@pavilionartlogiciel>
This commit is contained in:
808
java/org/artisanlogiciel/games/LabyModel.java
Normal file
808
java/org/artisanlogiciel/games/LabyModel.java
Normal file
@@ -0,0 +1,808 @@
|
||||
package org.artisanlogiciel.games;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Collections;
|
||||
import java.util.Random;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
|
||||
/**
|
||||
Model of labyrinth storing only paths not walls. wall are regenerated later on based on adjacent paths.
|
||||
each position (x,y) stores what move can be done from here to go do deeper path.
|
||||
a node is tagged OPEN and contained in openList if all moves from its position have not been resolved
|
||||
a node is tagged CLOSED when fully processed
|
||||
**/
|
||||
public class LabyModel
|
||||
implements WallsProvider
|
||||
{
|
||||
|
||||
/** WARNING don't change those values, they are used as it is for optimisation */
|
||||
private final static short FLAGLENGTH=7;
|
||||
private final static short CLEAR=0; // mandatory 0 since array creation is initialized with 0.
|
||||
private final static short HORIZONTAL=1;
|
||||
private final static short VERTICAL=2;
|
||||
private final static short DIRECTION=4; // could we get rid of that to free one bit for other purpose ?
|
||||
private final static short POSITIVE=8;
|
||||
private final static short NEGATIVE=16;
|
||||
private final static short OPEN=32; // can be reused once generation is completed
|
||||
private final static short CLOSED=64; // can be reused once generation is completed
|
||||
private final static short LEFT=Brick.LEFT<<FLAGLENGTH|DIRECTION|HORIZONTAL|NEGATIVE;
|
||||
private final static short DOWN=Brick.DOWN<<FLAGLENGTH|DIRECTION|VERTICAL|POSITIVE;
|
||||
private final static short RIGHT=Brick.RIGHT<<FLAGLENGTH|DIRECTION|HORIZONTAL|POSITIVE;
|
||||
private final static short UP=Brick.UP<<FLAGLENGTH|DIRECTION|VERTICAL|NEGATIVE;
|
||||
private final static short ENTRY=Brick.ENTRY<<FLAGLENGTH; // flag when a wall should be open to access this.
|
||||
private final static short GOAL=Brick.GOAL<<FLAGLENGTH; // flag when a wall should be open to access this.
|
||||
private final static short SOLVED=64<<FLAGLENGTH; // flag when solution is on this path.
|
||||
private final static short FREE=128<<FLAGLENGTH; // free flag
|
||||
// remains 2 free bits ( keep one out for sign )
|
||||
|
||||
private static final short[] AllDirections = {LEFT,DOWN,RIGHT,UP};
|
||||
|
||||
private int width;
|
||||
private int height;
|
||||
private short [][] t;
|
||||
private int depth=0;
|
||||
/** will enforce maxdepth as maxium length of path in depth first.
|
||||
It means that after every maxdepth moves there should be crossing paths.
|
||||
I think that to shorter maxdepth is the harder the labyrinth is ...
|
||||
**/
|
||||
private int maxdepth=0;
|
||||
private int deepest=0; // longest path found
|
||||
private int linearwork=0;
|
||||
private Position deepestEnd = null;
|
||||
boolean maxreached = false;
|
||||
java.util.Random random;
|
||||
private final LinkedList<Position> openList = new LinkedList<Position>();
|
||||
//list of entries and exits.
|
||||
private final LinkedList<Position> entryExits = new LinkedList<Position>();
|
||||
private final Object coherentLock = new Object(); // before getting the lock and after lock release all is coherent ( ie check() is ok ),
|
||||
|
||||
MazeCreationListener listener = null;
|
||||
|
||||
|
||||
public LabyModel(int width, int height,int maxdepth, Random random){
|
||||
this.width=width;
|
||||
this.height=height;
|
||||
this.maxdepth=maxdepth;
|
||||
this.random = random;
|
||||
// CLEAR == 0 and array is initialized with 0s
|
||||
t= new short[width][height];
|
||||
}
|
||||
|
||||
public LabyModel(String pFormat, InputStream pIn)
|
||||
throws IOException
|
||||
{
|
||||
parseInputStream(pFormat, pIn);
|
||||
}
|
||||
|
||||
public void setMazeListener(MazeCreationListener listener)
|
||||
{
|
||||
this.listener=listener;
|
||||
}
|
||||
|
||||
// entry and exit can be outside the model boundaries a one x or one y out.
|
||||
public boolean addEntryOrExit(int x, int y)
|
||||
{
|
||||
entryExits.add(new Position(x,y));
|
||||
if (( x > 0 ) && ( x < width ) && ( y > 0 ) && ( y < height ))
|
||||
{
|
||||
t[x][y] |= ENTRY;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void debugOut()
|
||||
{
|
||||
for (int y=0; y < height; y++)
|
||||
{
|
||||
for (int x=0; x < width; x++)
|
||||
{
|
||||
out4XY(x,y);
|
||||
}
|
||||
System.out.print('\n');
|
||||
}
|
||||
}
|
||||
|
||||
public void out4XY(int x,int y)
|
||||
{
|
||||
int direction=t[x][y];
|
||||
if ( ( direction & OPEN ) == OPEN )
|
||||
{
|
||||
System.out.print("?");
|
||||
}
|
||||
else if ( ( direction & CLOSED ) == CLOSED )
|
||||
{
|
||||
System.out.print(".");
|
||||
}
|
||||
else {
|
||||
System.out.print(" ");
|
||||
}
|
||||
// don't display information about short.
|
||||
direction &= ~OPEN;
|
||||
direction &= ~GOAL;
|
||||
direction &= ~CLOSED;
|
||||
switch(direction){
|
||||
case LEFT: // left
|
||||
System.out.print("<-");
|
||||
break;
|
||||
case DOWN: // down
|
||||
System.out.print("vv");
|
||||
break;
|
||||
case RIGHT: // right
|
||||
System.out.print("->");
|
||||
break;
|
||||
case UP: // up
|
||||
System.out.print("^^");
|
||||
break;
|
||||
case HORIZONTAL: // -
|
||||
System.out.print("--");
|
||||
break;
|
||||
case VERTICAL: // |
|
||||
System.out.print("||");
|
||||
break;
|
||||
case CLEAR:
|
||||
System.out.print(" ");
|
||||
break;
|
||||
case CLOSED:
|
||||
System.out.print("00");
|
||||
break;
|
||||
case RIGHT|LEFT:
|
||||
System.out.print("--");
|
||||
break;
|
||||
case UP|DOWN:
|
||||
System.out.print("||");
|
||||
break;
|
||||
case RIGHT|UP:
|
||||
System.out.print("^>");
|
||||
break;
|
||||
case RIGHT|DOWN:
|
||||
System.out.print("v>");
|
||||
break;
|
||||
case LEFT|DOWN:
|
||||
System.out.print("<v");
|
||||
break;
|
||||
case LEFT|UP:
|
||||
System.out.print("<^");
|
||||
break;
|
||||
case LEFT|RIGHT|UP:
|
||||
System.out.print("LL");
|
||||
break;
|
||||
case LEFT|RIGHT|DOWN:
|
||||
System.out.print("TT");
|
||||
break;
|
||||
case LEFT|DOWN|UP:
|
||||
System.out.print("<|");
|
||||
break;
|
||||
case RIGHT|DOWN|UP:
|
||||
System.out.print("|>");
|
||||
break;
|
||||
case LEFT|RIGHT|UP|DOWN:
|
||||
System.out.print("++");
|
||||
break;
|
||||
case OPEN:
|
||||
System.out.print("??");
|
||||
break;
|
||||
case GOAL:
|
||||
System.out.print("**");
|
||||
break;
|
||||
default:
|
||||
System.out.print("..");
|
||||
}
|
||||
|
||||
if ( ( (t[x][y] & RIGHT) == RIGHT ) ||
|
||||
( ( x+ 1 < width) && ( ( t[x+1][y] & LEFT ) == LEFT ) ))
|
||||
{
|
||||
System.out.print("-");
|
||||
}
|
||||
else
|
||||
{
|
||||
System.out.print("H");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public String outHorizWall2XY(int x, int y)
|
||||
{
|
||||
String freeway= " ";
|
||||
if ( (t[x][y] & SOLVED) == SOLVED)
|
||||
{
|
||||
freeway="*";
|
||||
}
|
||||
if ( ( x < 0 ) || ( x >width ) )
|
||||
{
|
||||
return " H";
|
||||
}
|
||||
if ( ( y < 0 ) || ( y >= height ) )
|
||||
{
|
||||
return "HH";
|
||||
}
|
||||
|
||||
if ( ( (t[x][y] & DOWN) == DOWN ) || (( y+ 1 < height) && ( ( t[x][y+1] & UP ) == UP )))
|
||||
{
|
||||
return freeway + "H";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "HH";
|
||||
}
|
||||
}
|
||||
|
||||
public String out2XY(int x,int y)
|
||||
{
|
||||
// can check for entry exits.
|
||||
|
||||
if ( ( y < 0 ) || ( y >= height ) || ( x < 0 ) || ( x >width ) )
|
||||
{
|
||||
return " H";
|
||||
}
|
||||
String low="";
|
||||
int direction=t[x][y];
|
||||
String freeway= " ";
|
||||
if ( (t[x][y] & SOLVED) == SOLVED)
|
||||
{
|
||||
freeway="*";
|
||||
}
|
||||
// don't display information about short.
|
||||
direction &= ~OPEN;
|
||||
direction &= ~GOAL;
|
||||
direction &= ~CLOSED;
|
||||
direction &= ~SOLVED;
|
||||
switch(direction){
|
||||
case LEFT:
|
||||
case DOWN:
|
||||
case RIGHT:
|
||||
case UP:
|
||||
low=freeway;
|
||||
break;
|
||||
case HORIZONTAL: // -
|
||||
low=" ";
|
||||
break;
|
||||
case VERTICAL: // |
|
||||
low=" ";
|
||||
break;
|
||||
case CLEAR:
|
||||
low=" ";
|
||||
break;
|
||||
case CLOSED:
|
||||
low="0";
|
||||
break;
|
||||
case RIGHT|LEFT:
|
||||
case UP|DOWN:
|
||||
case RIGHT|UP:
|
||||
case RIGHT|DOWN:
|
||||
case LEFT|DOWN:
|
||||
case LEFT|UP:
|
||||
case LEFT|RIGHT|UP:
|
||||
case LEFT|RIGHT|DOWN:
|
||||
case LEFT|DOWN|UP:
|
||||
case RIGHT|DOWN|UP:
|
||||
case LEFT|RIGHT|UP|DOWN:
|
||||
low=".";
|
||||
break;
|
||||
case OPEN:
|
||||
low="?";
|
||||
break;
|
||||
case GOAL:
|
||||
low="*";
|
||||
break;
|
||||
default:
|
||||
low=".";
|
||||
}
|
||||
|
||||
|
||||
for ( Position exit: entryExits )
|
||||
{
|
||||
if ( ( exit.getX() == x + 1 ) && ( exit.getY() == y ))
|
||||
{
|
||||
low=low+">";
|
||||
return low;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ( (t[x][y] & RIGHT) == RIGHT ) ||
|
||||
( ( x+ 1 < width) && ( ( t[x+1][y] & LEFT ) == LEFT ) ))
|
||||
{
|
||||
low=low+freeway;
|
||||
}
|
||||
else
|
||||
{
|
||||
low=low+"H";
|
||||
}
|
||||
|
||||
return low;
|
||||
}
|
||||
|
||||
public LabyMap toLabyMap()
|
||||
{
|
||||
synchronized (coherentLock)
|
||||
{
|
||||
Brick[][] brickMap = new Brick[width][height];
|
||||
for (int y=0; y< height; y++)
|
||||
{
|
||||
for ( int x=0; x < width; x++)
|
||||
{
|
||||
brickMap[x][y]=new Brick(out2XY(x,y), outHorizWall2XY(x, y),getWalls(x,y));
|
||||
}
|
||||
}
|
||||
return new LabyMap(brickMap, (LinkedList<Position>) entryExits.clone());
|
||||
}
|
||||
}
|
||||
|
||||
public int getWidth(){
|
||||
return this.width;
|
||||
}
|
||||
|
||||
public int getHeight(){
|
||||
return this.height;
|
||||
}
|
||||
|
||||
public LinkedList<Position> getOpenList()
|
||||
{
|
||||
return openList;
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
depth = 0;
|
||||
computeOpenList();
|
||||
}
|
||||
|
||||
public void fullReset()
|
||||
{
|
||||
depth = 0;
|
||||
openList.clear();
|
||||
maxreached = false;
|
||||
deepest=0;
|
||||
deepestEnd=null;
|
||||
// clear open
|
||||
for (int y=0; y < height; y++)
|
||||
{
|
||||
for (int x=0; x < width; x++)
|
||||
{
|
||||
t[x][y] &= ~OPEN;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
check model coherency and fix
|
||||
if model needed a fix it means that algorithm has a problem
|
||||
|
||||
@return true if model is ok and no fix was applied.
|
||||
**/
|
||||
public boolean check()
|
||||
{
|
||||
boolean check = true;
|
||||
synchronized(coherentLock)
|
||||
{
|
||||
// node in OPEN should be tagged OPEN and not CLOSED.
|
||||
for ( Position p : openList)
|
||||
{
|
||||
int x = p.getX();
|
||||
int y = p.getY();
|
||||
if ( (t[x][y] & OPEN ) != OPEN )
|
||||
{
|
||||
check = false;
|
||||
t[x][y] |= OPEN;
|
||||
}
|
||||
if ( (t[x][y] & CLOSED ) == CLOSED )
|
||||
{
|
||||
check = false;
|
||||
t[x][y] &= ~CLOSED;
|
||||
}
|
||||
}
|
||||
// should do reverse : every node tagged OPEN should be in open list.
|
||||
// a little more cpu consuming...
|
||||
}
|
||||
return check;
|
||||
}
|
||||
|
||||
public void computeOpenList()
|
||||
{
|
||||
openList.clear();
|
||||
for (int y=0; y < height; y++)
|
||||
{
|
||||
for (int x=0; x < width; x++)
|
||||
{
|
||||
if ( (t[x][y] & CLOSED ) == CLOSED )
|
||||
{
|
||||
t[x][y] &= ~OPEN;
|
||||
}
|
||||
if ( ( (t[x][y] & OPEN) == OPEN ) || ( t[x][y] == CLEAR ))
|
||||
{
|
||||
openList.add(new Position(x,y));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void generateWithEntry(int x, int y){
|
||||
|
||||
openList.add(new Position(x,y));
|
||||
while ( ! openList.isEmpty() )
|
||||
{
|
||||
step(0); // fixme depth not set
|
||||
|
||||
synchronized(coherentLock)
|
||||
{
|
||||
linearwork ++;
|
||||
|
||||
if ( linearwork % maxdepth == 0 )
|
||||
{
|
||||
coherentLock.notifyAll();
|
||||
if (listener != null)
|
||||
{
|
||||
listener.changed(null,null,this);
|
||||
}
|
||||
// should not continue in depth first...
|
||||
if ( ! openList.isEmpty() )
|
||||
{
|
||||
// insert head as next position to pick up.
|
||||
Position current = openList.removeFirst();
|
||||
openList.add(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( deepestEnd != null )
|
||||
{
|
||||
t[deepestEnd.getX()][deepestEnd.getY()]|=GOAL;
|
||||
}
|
||||
}
|
||||
|
||||
public int getDepth()
|
||||
{
|
||||
return depth;
|
||||
}
|
||||
|
||||
public Position getDeepestEnd()
|
||||
{
|
||||
return deepestEnd;
|
||||
}
|
||||
|
||||
public int getDeepestPath()
|
||||
{
|
||||
return deepest;
|
||||
}
|
||||
|
||||
public boolean maxReached()
|
||||
{
|
||||
return maxreached;
|
||||
}
|
||||
|
||||
/**
|
||||
@param p Position
|
||||
@return true if newly added , false if already open.
|
||||
**/
|
||||
private boolean open(boolean first, Position p)
|
||||
{
|
||||
int x = p.getX();
|
||||
int y = p.getY();
|
||||
if ( ( t[x][y] & OPEN ) != OPEN )
|
||||
{
|
||||
t[x][y]|=OPEN;
|
||||
openList.addLast(p);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
resolve this labrynth using internal representation
|
||||
**/
|
||||
public LinkedList<Position> resolve(int x, int y, MazeResolutionListener rlistener)
|
||||
{
|
||||
int newx=x;
|
||||
int newy=y;
|
||||
LinkedList<Position> backpath = new LinkedList<Position>();
|
||||
|
||||
while ( ! (( newx == 0 ) && ( newy == 0 )))
|
||||
{
|
||||
Position found=null;
|
||||
x = newx;
|
||||
y = newy;
|
||||
backpath.addFirst( new Position(x,y));
|
||||
|
||||
// should find from all direction one that point to this.
|
||||
ArrayList<Short> freeDirection = new ArrayList<Short>();
|
||||
|
||||
for (int didx=0; didx < 4; didx ++ ) {
|
||||
int delta=0;
|
||||
short direction=AllDirections[didx];
|
||||
short reversedirection=AllDirections[(didx+2)%4];
|
||||
short pointingdirection=DIRECTION;
|
||||
|
||||
if ( ( direction & POSITIVE ) == POSITIVE ) { delta = 1; pointingdirection |= NEGATIVE ; }
|
||||
else { delta = -1; pointingdirection |= POSITIVE ;}
|
||||
|
||||
if ( ( direction & HORIZONTAL ) == HORIZONTAL ) { newx = x + delta; newy = y; pointingdirection |= HORIZONTAL; }
|
||||
else { newy = y + delta; newx = x; pointingdirection |= VERTICAL ;}
|
||||
|
||||
// internal GUARD.
|
||||
if ( (reversedirection & pointingdirection) != pointingdirection )
|
||||
{
|
||||
System.out.println("Internal ERROR. Please check AllDirections order " + ( reversedirection & pointingdirection ) + " " + pointingdirection );
|
||||
return backpath;
|
||||
}
|
||||
|
||||
if ( (newx >= 0) && ( newy >= 0 ) && (newx < width) && (newy < height) ) {
|
||||
if ( ( t[newx][newy] & reversedirection ) == reversedirection){
|
||||
if ( found != null ) {
|
||||
// could be a unique parent of two paths...
|
||||
// but search from other entry/exits than generated from
|
||||
// ie entry(0,0) exit(width-1,height-1) not yet implemented.
|
||||
if (rlistener != null)
|
||||
{
|
||||
rlistener.notifySearchError("Model Error : two parents " + found.toString() + " " + new Position(newx,newy).toString());
|
||||
}
|
||||
return backpath;
|
||||
}
|
||||
found = new Position(newx,newy);
|
||||
if (rlistener != null)
|
||||
{
|
||||
rlistener.notifySearch(found);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( found == null )
|
||||
{
|
||||
rlistener.notifySearchError("No path found !");
|
||||
break;
|
||||
}
|
||||
// System.out.println(found);
|
||||
newx=found.getX();
|
||||
newy=found.getY();
|
||||
t[newx][newy] |= SOLVED;
|
||||
}
|
||||
if (rlistener != null)
|
||||
{
|
||||
rlistener.notifyCompletion(backpath);
|
||||
}
|
||||
return backpath;
|
||||
}
|
||||
|
||||
/**
|
||||
@returns wheter process closed current node.
|
||||
**/
|
||||
public boolean step(int depth)
|
||||
{
|
||||
boolean complete = false;
|
||||
Position current = null;
|
||||
|
||||
synchronized(coherentLock)
|
||||
{
|
||||
|
||||
if ( ! openList.isEmpty() )
|
||||
{
|
||||
// last : in depth before.
|
||||
current = openList.getLast();
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( current != null )
|
||||
{
|
||||
int x = current.getX();
|
||||
int y = current.getY();
|
||||
|
||||
// should find all free positions...
|
||||
ArrayList<Short> freeDirection = new ArrayList<Short>();
|
||||
|
||||
for (short direction : AllDirections ) {
|
||||
int delta=0;
|
||||
int newx = -1;
|
||||
int newy = -1;
|
||||
|
||||
if ( ( direction & POSITIVE ) == POSITIVE ) { delta = 1; }
|
||||
else { delta = -1; }
|
||||
|
||||
if ( ( direction & HORIZONTAL ) == HORIZONTAL ) { newx = x + delta; newy = y; }
|
||||
else { newy = y + delta; newx = x; }
|
||||
|
||||
if ( (newx >= 0) && ( newy >= 0 ) && (newx < width) && (newy < height) ) {
|
||||
if( (t[newx][newy] ) == CLEAR){
|
||||
freeDirection.add(new Short(direction));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! freeDirection.isEmpty())
|
||||
{
|
||||
// control random using our own pseudorandom
|
||||
short direction = 0;
|
||||
if ( freeDirection.size() > 1 )
|
||||
{
|
||||
direction=freeDirection.get(random.nextInt(freeDirection.size()));
|
||||
}
|
||||
else
|
||||
{
|
||||
direction=freeDirection.get(0);
|
||||
Position last=openList.removeLast();
|
||||
if ( last != current )
|
||||
{
|
||||
// GUARD, should not happen ( or multi-thread access to model error )
|
||||
System.err.println("INTERNAL ERROR 3");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int delta=0;
|
||||
int newx = -1;
|
||||
int newy = -1;
|
||||
|
||||
if ( ( direction & POSITIVE ) == POSITIVE ) { delta = 1; }
|
||||
else { delta = -1; }
|
||||
|
||||
if ( ( direction & HORIZONTAL ) == HORIZONTAL ) { newx = x + delta; newy = y; }
|
||||
else { newy = y + delta; newx = x; }
|
||||
|
||||
Position target = new Position(newx,newy,current.getDepth()+1);
|
||||
open(false,target);
|
||||
if (( t[x][y] & DIRECTION ) == DIRECTION ) { t[x][y] |= direction; }
|
||||
else { t[x][y] = direction; } // not a 'direction' ... is it necessary to check ?
|
||||
if ( freeDirection.size() > 1 )
|
||||
{
|
||||
// keep it open at the very same place, previous open did add another node to inspect.
|
||||
return false;
|
||||
}
|
||||
// else this was the unique direction , object already removed ( since if we try to remove it now it is not the last )
|
||||
|
||||
// can proceed to close
|
||||
}
|
||||
else {
|
||||
// no free direction remaining => closing
|
||||
Position last=openList.removeLast();
|
||||
if ( last != current )
|
||||
{
|
||||
// GUARD, should not happen.
|
||||
System.err.println("INTERNAL ERROR 3");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
complete = true;
|
||||
t[x][y]&=~OPEN;
|
||||
t[x][y]|=CLOSED;
|
||||
if ( current.getDepth() > deepest )
|
||||
{
|
||||
deepest = depth;
|
||||
deepestEnd = current;
|
||||
}
|
||||
} // current != null;
|
||||
} // synchronized
|
||||
return complete;
|
||||
}
|
||||
|
||||
public short getWalls(int x, int y)
|
||||
{
|
||||
short walls=0;
|
||||
for (short direction: AllDirections)
|
||||
{
|
||||
if (hasWallInDirection(x,y,direction))
|
||||
{
|
||||
walls |= (direction>>FLAGLENGTH);
|
||||
}
|
||||
}
|
||||
return walls;
|
||||
}
|
||||
|
||||
/** is there a wall in that direction ?
|
||||
**/
|
||||
public boolean hasWallInDirection(int x, int y, short direction)
|
||||
{
|
||||
int newx=0;
|
||||
int newy=0;
|
||||
int delta=0;
|
||||
// best way to find reversedirection ?
|
||||
int reversedirection=0;
|
||||
|
||||
// is this direction on the path ? yes => no wall
|
||||
if ( ( t[x][y] & direction ) == direction )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// is adjacent tile in direction pointing in reverse direction ? yes => no wall
|
||||
if ( ( direction & POSITIVE ) == POSITIVE ) { delta = 1; }
|
||||
else { delta = -1; }
|
||||
|
||||
if ( ( direction & HORIZONTAL ) == HORIZONTAL ) {
|
||||
newx = x + delta;
|
||||
newy = y;
|
||||
reversedirection = (direction == RIGHT) ? LEFT : RIGHT;
|
||||
}
|
||||
else {
|
||||
newy = y + delta;
|
||||
newx = x;
|
||||
reversedirection = (direction == UP) ? DOWN : UP;
|
||||
}
|
||||
|
||||
if ( (newx >= 0) && ( newy >= 0 ) && (newx < width) && (newy < height) ) {
|
||||
return ( (t[newx][newy]&reversedirection) != reversedirection );
|
||||
}
|
||||
else {
|
||||
// outside boundaries.
|
||||
// TODO CHECK exits.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void streamOut( String pFormat, OutputStream pOut)
|
||||
throws IOException
|
||||
{
|
||||
if ((pFormat == null ) || (pFormat.equals("raw")))
|
||||
{
|
||||
// first raw format, not smart.
|
||||
DataOutputStream dataOut = new DataOutputStream(pOut);
|
||||
// should dump this to stream.
|
||||
dataOut.write( new byte[] { (byte) 'L', (byte) 'A', (byte) 'B', (byte) '0' });
|
||||
dataOut.writeInt(getWidth());
|
||||
dataOut.writeInt(getHeight());
|
||||
dataOut.flush();
|
||||
for (int y = 0; y < getHeight(); y++)
|
||||
{
|
||||
for (int x = 0 ; x < getWidth() ; x++)
|
||||
{
|
||||
dataOut.writeShort(t[x][y]);
|
||||
}
|
||||
}
|
||||
dataOut.flush();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IOException("Format " + pFormat + " Not yet implemented.");
|
||||
}
|
||||
}
|
||||
|
||||
private void streamIn( String pFormat, InputStream pIn)
|
||||
throws IOException
|
||||
{
|
||||
throw new IOException("Use correct constructor.");
|
||||
}
|
||||
|
||||
private void parseInputStream( String pFormat, InputStream pIn)
|
||||
throws IOException
|
||||
{
|
||||
if (( pFormat == null) || ( pFormat.equals("raw") ))
|
||||
{
|
||||
byte[] header = new byte[4];
|
||||
DataInputStream in = new DataInputStream(pIn);
|
||||
in.read(header);
|
||||
int rwidth = in.readInt();
|
||||
int rheight = in.readInt();
|
||||
width=rwidth;
|
||||
height=rheight;
|
||||
maxdepth=maxdepth;
|
||||
random = null;
|
||||
// SHOULD CHECK max width and max height...
|
||||
// CLEAR == 0 and array is initialized with 0s
|
||||
t= new short[width][height];
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
for (int x = 0 ; x < width ; x++)
|
||||
{
|
||||
t[x][y] = in.readShort();
|
||||
}
|
||||
}
|
||||
// should be at end of stream ? Not necessary can stream multiple labs ( or tiling ).
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IOException("Format " + pFormat + " Not yet implemented.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user