我收到错误:
java.lang.ArrayIndexOutOfBoundsException: 0
at tesseract.BlockMaze.generate(BlockMaze.java:128)
at tesseract.MazeMap.<init>(MazeMap.java:17)
at tesseract.main.init(main.java:29)
at sun.applet.AppletPanel.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
以下是部分:
第29行:
map = new MazeMap(mwidth, mheight);
MazeMap第17行:
generate(false);
BlockMaze第128行:
maze[startX = 0][startY = rint(mzHyt - 2) + 1] = FLOOR;
我正在使用Vector类型,我想知道是否可能是我遇到的问题。 Vector是不推荐使用的类型,是否有替代品。还有一个替代方案,因为我尝试使用ArrayList,但我不完全确定它是否会做同样的事情。
这是BlockMaze:
package tesseract;
import java.awt.Color;
import java.util.Vector;
public class BlockMaze extends Maze{
private static final long serialVersionUID = -4392133669361871887L;
public static final byte WALL = 0, FLOOR = 1;
private Vector pending; // list of available Sqr objects
private int strt = 70; // prob of exploring from same sqr
private int sdir = 60; // prob of exploring in same dir (if possible)
private int thru = 90; // prob of blocking thru loops
private int side = 60; // prob of blocking wide areas
private int diag = 100; // prob of blocking diag connections
private int dens = 15; // prob of leaving areas unexplored
public BlockMaze () {
setBackground(Color.black);
}
protected byte initSq () { return (byte) (WALL | DIRTY); }
protected void drawSquare (int xx, int yy) {
offscr.setColor(maze[xx][yy] == WALL ? Color.gray : Color.white);
offscr.fillRect(leftOffset + (xx * sqWid), topOffset + (yy * sqHyt), sqWid, sqHyt);
}
public boolean isOpen (int x, int y) {
return inBounds(x, y) && sqr(x, y) == FLOOR;
}
private boolean isOpen (int x, int y, int allowProb) {
return prob(allowProb) && isOpen(x, y);
}
private boolean blocked (int x, int y) {
return inBounds(x, y) && sqr(x, y) == WALL;
}
private boolean noDiag (int x, int y, int dx, int dy) {
return blocked(x + dx, y) && blocked(x, y + dy) && isOpen(x + dx, y + dy, diag);
}
private boolean tryDir (int x, int y, int dir) {
// Step #7 - check if the adjacent square in direction 'dir' should be
added to the maze
// Currently I disallow any move that would create a loop or a path width
// greater than one square. However, I believe I can get more interesting
// mazes if I use probability to selectively allow this.
switch (dir) {
case TOP:
y--;
if (isOpen(x, y - 1, thru) ||
isOpen(x - 1, y, side) || isOpen(x + 1, y, side) ||
noDiag(x, y, -1, -1) || noDiag(x, y, 1, -1))
return false;
break;
case BOTTOM:
y++;
if (isOpen(x, y + 1, thru) ||
isOpen(x - 1, y, side) || isOpen(x + 1, y, side) ||
noDiag(x, y, -1, 1) || noDiag(x, y, 1, 1))
return false;
break;
case LEFT:
x--;
if (isOpen(x - 1, y, thru) ||
isOpen(x, y - 1, side) || isOpen(x, y + 1, side) ||
noDiag(x, y, -1, -1) || noDiag(x, y, -1, 1))
return false;
break;
case RIGHT:
x++;
if (isOpen(x + 1, y, thru) ||
isOpen(x, y - 1, side) || isOpen(x, y + 1, side) ||
noDiag(x, y, 1, -1) || noDiag(x, y, 1, 1))
return false;
break;
}
if (finishX < 0 && x == mzWid - 1) {
finishX = x; finishY = y; // found exit
}
else if (x <= 0 || x >= mzWid - 1 || y <= 0 || y >= mzHyt - 1)
return false; // square on border or out of bounds
else {
Sqr sq = new Sqr(x, y, dir, blocked(x, y-1), blocked(x, y+1),
blocked(x-1, y), blocked(x+1, y));
// if pruning density, replace last pending Sqr
if (pending.size() > 10 && prob(dens))
pending.setElementAt(sq, pending.size() - 1);
else // not pruning, add pending Sqr to list
pending.addElement(sq);
}
maze[x][y] = FLOOR;
dirtySquare(x, y);
return true;
}
/* Here are the steps generate() uses to generate a maze:
* 1. Set all the squares in the maze grid to WALL.
* 2. Randomly select a non-corner square on the left edge of the maze,
* set the square to FLOOR. Create a Sqr object with the RIGHT direction
* unexplored and add it to the list of available squares.
* 3. If the list of available squares is empty, then you're done.
* 4. Select a square to explore from the list of available squares.
* 5. If less than two directions remain to be explored from the square,
* remove the square from the list of available squares. You remove
* the square from the list because no directions will be left to
* explore after you process the square.
* 6. Select a direction to explore from the square and mark the direction
* as explored.
* 7. Check to see if you should add the square in the selected direction
* to the maze grid. If the answer is ÔyesÕ, then add the square to the
* maze and to the list of available squares.
* 8. Goto step 3.
*/
public synchronized void generate (boolean displayConstruction) {
int free, idx;
// Step #1 - initialize the maze
clearMaze();
if (displayConstruction)
showMaze(true);
// Step #2 - select and set the starting square
pending = new Vector();
maze[startX = 0][startY = rint(mzHyt - 2) + 1] = FLOOR;
dirtySquare(startX, startY);
pending.addElement(new Sqr(startX, startY, RIGHT, false, false, false, true));
// Step #3 - loop until list of squares is empty
while (!pending.isEmpty()) {
// Step #4 - select a square to explore
// You can vary the "character" of the generated maze by adjusting how
frequently
// the algorithm chooses to continue expanding from the current square vs. how
// frequently it randomly picks another queue square.
if (prob(strt))
idx = pending.size() - 1;
else
idx = rint(pending.size());
Sqr next = (Sqr) pending.elementAt(idx);
// Step #5 - remove the square if this is the last side to explore
// Also randomly remove squares to reduce maze density.
if ((free = next.open()) <= 1 || (pending.size() > 10 && prob(dens)))
pending.removeElementAt(idx);
if (free > 0) {
// Step #6a - select a direction to explore
// You can also vary the character of the maze by altering the probability
that
// Sqr.select() will be asked to try to continue to expand the next square
in the
// same direction we entered the square being expanded. This tends to
reduce
// the zig-zag nature that results from straight random
selection of direction.
if (tryDir(next.x, next.y, next.select(rint(free), prob(sdir))))
if (displayConstruction)
showMaze(false);
}
// Step #8 - explore another square
}
if (!displayConstruction)
repaint();
}
public synchronized boolean traverse (int sx, int sy, int fx, int fy, boolean
displaySearch) {
if (!inBounds(sx, sy) || !inBounds(fx, fy))
return false;
int dir, xx = sx, yy = sy, count = 0;
int qhead, qtail, qsize = (mzWid + mzHyt - 1) * 2;
short[][] queue = new short[qsize][2]; // 0 = x, 1 = y
byte[][] graph = new byte[mzWid][mzHyt];
boolean solve = (xx == startX && yy == startY && fx == finishX && fy ==finishY);
if (displaySearch) {
resetPath();
if (solve) {
path[sx][sy] = LEFT;
dirtySquare(sx, sy);
}
showMaze(false);
}
graph[xx][yy] = -1;
queue[0][0] = (short)xx; queue[0][1] = (short)yy;
qtail = 0; qhead = 1;
TRAVERSE:
for (;;) {
if (qhead == qtail) { // queue is empty: unsolvable maze
resetPath();
if (displayPath)
repaint();
return false;
}
xx = queue[qtail][0]; yy = queue[qtail][1];
qtail = (qtail + 1) % qsize;
int qstart = qhead;
for (dir = TOP; dir <= LEFT; dir <<= 1) {
int ndir = 0, nx = xx, ny = yy;
switch (dir) {
case TOP: ny--; ndir = BOTTOM; break;
case RIGHT: nx++; ndir = LEFT; break;
case BOTTOM: ny++; ndir = TOP; break;
case LEFT: nx--; ndir = RIGHT; break;
}
if (inBounds(nx, ny) && graph[nx][ny] == 0 && sqr(nx, ny) == FLOOR) {
// extend the search path in direction <dir>
graph[nx][ny] = (byte)ndir; // point to previous square
if (displaySearch) {
path[xx][yy] |= dir;
dirtySquare(xx, yy);
path[nx][ny] |= ndir;
dirtySquare(nx, ny);
}
if (nx == fx && ny == fy) // found solution
break TRAVERSE;
queue[qhead][0] = (short)nx; queue[qhead][1] = (short)ny;
qhead = (qhead + 1) % qsize;
}
}
if (displaySearch) {
if (qhead == qstart) { // dead end, backtrack
while (path[xx][yy] == graph[xx][yy]) {
path[xx][yy] = 0;
dirtySquare(xx, yy);
switch (graph[xx][yy]) {
case TOP: path[xx][--yy] &= (byte)~BOTTOM; break;
case RIGHT: path[++xx][yy] &= (byte)~LEFT; break;
case BOTTOM: path[xx][++yy] &= (byte)~TOP; break;
case LEFT: path[--xx][yy] &= (byte)~RIGHT; break;
}
dirtySquare(xx, yy);
}
}
showMaze(false);
}
else if ((++count & 0xFF) == 0)
Thread.yield();
}
if (displaySearch) {
if (solve) {
path[xx][yy] |= RIGHT;
dirtySquare(xx, yy);
}
showMaze(false);
}
// reconstruct path by following graph from finish to start
resetPath();
if (solve)
path[fx][fy] = RIGHT;
while ((dir = graph[fx][fy]) != -1) {
path[fx][fy] |= (byte)dir;
switch (dir) {
case TOP: path[fx][--fy] = BOTTOM; break;
case RIGHT: path[++fx][fy] = LEFT; break;
case BOTTOM: path[fx][++fy] = TOP; break;
case LEFT: path[--fx][fy] = RIGHT; break;
}
}
if (solve)
path[fx][fy] |= LEFT;
if (displayPath)
repaint();
return true;
}
} // public class BlockMaze
class Sqr {
private boolean t, b, l, r; // top, bottom, left, right
private int dir; // direction square entered
int x, y; // coordinates of square
Sqr (int x, int y, int dir, boolean t, boolean b, boolean l, boolean r) {
this.x = x; this.y = y;
this.dir = dir;
this.t = t; this.b = b; this.l = l; this.r = r;
}
// open() returns a count of the unexplored directions
int open () {
return (t ? 1 : 0) + (b ? 1 : 0) + (r ? 1 : 0) + (l ? 1 : 0);
}
int select (int n, boolean sameDir) {
// Step #6b - select a direction to explore and mark the direction as explored
if (sameDir) // try to expand in same direction the square was entered from
switch (dir) {
case Maze.TOP: if (t) { t = false; return dir; } break;
case Maze.BOTTOM: if (b) { b = false; return dir; } break;
case Maze.LEFT: if (l) { l = false; return dir; } break;
case Maze.RIGHT: if (r) { r = false; return dir; } break;
}
// return the 'n'th unexplored direction
if (t && --n < 0) { t = false; return Maze.TOP; }
else if (b && --n < 0) { b = false; return Maze.BOTTOM; }
else if (r && --n < 0) { r = false; return Maze.RIGHT; }
else { l = false; return Maze.LEFT; }
}
} // class Sqr
这是阵列迷宫。
protected byte[][] maze, path;
这就是重新初始化迷宫的原因:
protected void showMaze (boolean allDirty) {
if (allDirty || offscreenImage == null)
repaint();
else
repaint(leftOffset + minXdirty * sqWid, topOffset + minYdirty * sqHyt,
sqWid * (maxXdirty - minXdirty + 1) + lineWid,
sqHyt * (maxYdirty - minYdirty + 1) + lineHyt);
try { wait(); } catch (InterruptedException e) {}
long t = System.currentTimeMillis();
if ((timer -= t - (1000L / maxFrameRate)) > 0)
try { Thread.sleep(timer); } catch (InterruptedException e) {}
timer = System.currentTimeMillis();
}
protected void clearMaze(){
if(maze == null)
maze = new byte[mzWid][mzHyt];
byte sq = initSq();
for(int xx = mzWid; --xx >= 0;)
for(int yy = mzHyt; --yy >= 0;)
maze[xx][yy] = sq;
minXdirty = minYdirty = 0;
maxXdirty = mzWid - 1;
maxYdirty = mzHyt - 1;
startX = finishX = -1;
path = null;
}
我相信这就是我所寻找的:
public synchronized void setDimensions(int squaresWide, int squaresHigh){
if(mzWid != squaresWide || mzHyt != squaresHigh){
mzWid = Math.max(3, squaresWide); //min maze width is 3 squares
mzHyt = Math.max(3, squaresHigh); //min maze height is 3 squares
maze = null;
resetMaze();
}
}
答案 0 :(得分:1)
Vector较旧,但这不是你的问题 - 元素从0开始编号,所以如果你要求元素0,你需要至少有1个元素。
Vector未标记为已弃用,但它会比ArrayList慢,因为它已同步。
答案 1 :(得分:0)
&#34; 0&#34;在错误消息中是超出范围的索引。如果您没有零元素,则Vector
为空。
答案 2 :(得分:0)
要么您没有初始化阵列迷宫,要么因为某种原因将其初始化为0。