我用两个类和一个枚举解决了这个问题。
首先,枚举,它定义要移动的方向,并根据其移动一次确定新索引。
enum Direction {
UP(-1, 0),
DOWN(1, 0),
LEFT(0, -1),
RIGHT(0, 1);
private final int rowSteps;
private final int colSteps;
private Direction(int rowSteps, int colSteps) {
this.rowSteps = rowSteps;
this.colSteps = colSteps;
}
public int getNewRowIdx(int currentRowIdx) {
return (currentRowIdx + getRowSteps());
}
public int getNewColIdx(int currentColIdx) {
return (currentColIdx + getColSteps());
}
public int getRowSteps() {
return rowSteps;
}
public int getColSteps() {
return colSteps;
}
};
主类称为GridPosition
(以下)。首先,通过其将双数组网格设置到其中int[][]
构造函数,并静态存储该实例:
private static final GridPosition GRID_HOLDER = new GridPosition(GRID);
(这一步可以设计得更好,但它有效。而且,它应该接受任何类型。)
设置网格后(这是一次性的事情,每次执行),然后使用 x/y 构造函数来声明初始位置:
GridPosition pos = new GridPosition(0, 0);
之后,根据需要移动:
pos = pos.getNeighbor(Direction.RIGHT);
pos = pos.getNeighbor(Direction.RIGHT);
pos = pos.getNeighbor(Direction.DOWN);
...
每个位置的值通过以下方式检索pos.getValue()
。 (顺便说一句:用于迷宫的巨大二维数组——在这篇文章的底部,在“完整代码”中——应该真正包含一位booleans
,而不是 4 字节ints
, but looking数组的代码有意义int
s,并且不包含布尔值...请注意,它至少应该更改为byte
s.)
因此,关于移动,如果您尝试在没有邻居的情况下找到邻居,例如在左边缘向左移动,则会出现IllegalStateException
被抛出。使用is*Edge()
函数来避免这种情况。
GridPosition 类还有一个方便的调试功能,称为getNineByNine()
,它返回数组值的 9x9 网格(作为字符串),其中中间项是当前位置。
import java.util.Arrays;
import java.util.Objects;
class GridPosition {
//state
private static int[][] GRID;
private final int rowIdx;
private final int colIdx;
//internal
private final int rowIdxMinus1;
private final int colIdxMinus1;
public GridPosition(int[][] GRID) {
if(this.GRID != null) {
throw new IllegalStateException("Grid already set. Use x/y constructor.");
}
GridPosition.GRID = GRID;
//TODO: Crash if null or empty, or sub-arrays null or empty, or unequal lengths, or contain anything but 0 or -1.
rowIdx = -1;
colIdx = -1;
rowIdxMinus1 = -1;
colIdxMinus1 = -1;
}
public GridPosition(int rowIdx, int colIdx) {
if(GridPosition.GRID == null) {
throw new IllegalStateException("Must set grid with: new GridPosition(int[][]).");
}
if(rowIdx < 0 || rowIdx >= GridPosition.getRowCount()) {
throw new IllegalArgumentException("rowIdx (" + rowIdx + ") is invalid.");
}
if(colIdx < 0 || colIdx >= GridPosition.getColumnCount()) {
throw new IllegalArgumentException("colIdx (" + colIdx + ") is invalid.");
}
this.rowIdx = rowIdx;
this.colIdx = colIdx;
rowIdxMinus1 = (rowIdx - 1);
colIdxMinus1 = (colIdx - 1);
}
public int getValue() {
return GridPosition.GRID[getRowIdx()][getColumnIdx()];
}
public int getRowIdx() {
return rowIdx;
}
public int getColumnIdx() {
return colIdx;
}
public GridPosition getNeighbor(Direction dir) {
Objects.requireNonNull(dir, "dir");
return (new GridPosition(
dir.getNewRowIdx(getRowIdx()),
dir.getNewColIdx(getColumnIdx())));
}
public GridPosition getNeighborNullIfEdge(Direction dir) {
if(isEdgeForDirection(dir)) {
return null;
}
return getNeighbor(dir);
}
public int getNeighborValueNeg1IfEdge(Direction dir) {
GridPosition pos = getNeighborNullIfEdge(dir);
return ((pos == null) ? -1 : pos.getValue());
}
public static final int getRowCount() {
return GRID.length;
}
public static final int getColumnCount() {
return GRID[0].length;
}
public boolean isEdgeForDirection(Direction dir) {
Objects.requireNonNull(dir);
switch(dir) {
case UP: return isTopEdge();
case DOWN: return isBottomEdge();
case LEFT: return isLeftEdge();
case RIGHT: return isRightEdge();
}
throw new IllegalStateException(toString() + ", dir=" + dir);
}
public boolean isLeftEdge() {
return (getColumnIdx() == 0);
}
public boolean isTopEdge() {
return (getRowIdx() == 0);
}
public boolean isBottomEdge() {
return (getRowIdx() == rowIdxMinus1);
}
public boolean isRightEdge() {
return (getColumnIdx() == colIdxMinus1);
}
public String toString() {
return "[" + getRowIdx() + "," + getColumnIdx() + "]=" + getValue();
}
public String getNineByNine() {
int[][] nineByNine = new int[3][3];
//Middle row
nineByNine[1][1] = getValue();
nineByNine[1][0] = getNeighborValueNeg1IfEdge(Direction.LEFT);
nineByNine[1][2] = getNeighborValueNeg1IfEdge(Direction.RIGHT);
//Top
GridPosition posUp = getNeighborNullIfEdge(Direction.UP);
if(posUp != null) {
nineByNine[0][0] = posUp.getNeighborValueNeg1IfEdge(Direction.LEFT);
nineByNine[0][1] = posUp.getValue();
nineByNine[0][2] = posUp.getNeighborValueNeg1IfEdge(Direction.RIGHT);
}
//Bottom
GridPosition posDown = getNeighborNullIfEdge(Direction.DOWN);
if(posDown != null) {
nineByNine[2][0] = posDown.getNeighborValueNeg1IfEdge(Direction.LEFT);
nineByNine[2][1] = posDown.getValue();
nineByNine[2][2] = posDown.getNeighborValueNeg1IfEdge(Direction.RIGHT);
}
String sLS = System.getProperty("line.separator", "\r\n");
return "Middle position in 9x9 grid is *this*: " + toString() + sLS +
Arrays.toString(nineByNine[0]) + sLS +
Arrays.toString(nineByNine[1]) + sLS +
Arrays.toString(nineByNine[2]);
}
}
这是一个演示用法:
public class GridPosDemo {
private static final int[][] GRID = new int[][] {
//mega grid goes here...
};
private static final GridPosition GRID_HOLDER = new GridPosition(GRID);
public static final void main(String[] ignored) {
GridPosition pos = new GridPosition(0, 0);
System.out.println("start: " + pos);
pos = pos.getNeighbor(Direction.RIGHT);
System.out.println("right: " + pos);
pos = pos.getNeighbor(Direction.RIGHT);
System.out.println("right: " + pos);
pos = pos.getNeighbor(Direction.DOWN);
System.out.println("down: " + pos);
pos = pos.getNeighbor(Direction.DOWN);
System.out.println("down: " + pos);
pos = pos.getNeighbor(Direction.RIGHT);
System.out.println("right: " + pos);
pos = pos.getNeighbor(Direction.DOWN);
System.out.println("down: " + pos);
pos = pos.getNeighbor(Direction.LEFT);
System.out.println("left: " + pos);
pos = pos.getNeighbor(Direction.UP);
System.out.println("up: " + pos);
pos = pos.getNeighbor(Direction.UP);
System.out.println("up: " + pos);
System.out.println(pos.getNineByNine());
}
}
Output
[C:\java_code\]java GridPosDemo
start: [0,0]=1
right: [0,1]=1
right: [0,2]=1
down: [1,2]=1
down: [2,2]=1
right: [2,3]=1
down: [3,3]=0
left: [3,2]=1
up: [2,2]=1
up: [1,2]=1
Middle position in 9x9 grid is *this*: [1,2]=1
[1, 1, 1]
[0, 1, 0]
[0, 1, 1]
为了使用它来穿过迷宫的正确路径,需要添加“碰撞检测”(这样它就不会穿过墙壁),此外还需要一些东西来跟踪你去过的地方(所以你不要最终回到起始位置)。比如与一些getNeighborIfNotWall(Direction)
and isWallToLeft()
功能。
抛开迷宫问题,在考虑完成这些课程之前我会做以下事情:
- 使数组类型变得通用,而不是整数
- 添加错误检查,如代码中所述
- 重新设计设置网格的方式。
- 添加对角线方向:
UP_LEFT
, UP_RIGHT
, DOWN_LEFT
, DOWN_RIGHT
- 添加向一个方向移动多个步骤的功能:
getNeighbor(3, Direction.DOWN)
这是完整的源代码文件,包含上述所有内容(包括巨型迷宫网格):
//Needed only by GridPosition
import java.util.Arrays;
import java.util.Objects;
enum Direction {
UP(-1, 0),
DOWN(1, 0),
LEFT(0, -1),
RIGHT(0, 1);
//config
private final int rowSteps;
private final int colSteps;
private Direction(int rowSteps, int colSteps) {
this.rowSteps = rowSteps;
this.colSteps = colSteps;
}
public int getNewRowIdx(int currentRowIdx) {
return (currentRowIdx + getRowSteps());
}
public int getNewColIdx(int currentColIdx) {
return (currentColIdx + getColSteps());
}
public int getRowSteps() {
return rowSteps;
}
public int getColSteps() {
return colSteps;
}
};
class GridPosition {
//config
private static int[][] GRID;
private final int rowIdx;
private final int colIdx;
//internal
private final int rowIdxMinus1;
private final int colIdxMinus1;
public GridPosition(int[][] GRID) {
if(this.GRID != null) {
throw new IllegalStateException("Grid already set. Use x/y constructor.");
}
GridPosition.GRID = GRID;
//TODO: Crash if null or empty, or sub-arrays null or empty, or unequal lengths, or contain anything but 0 or -1.
rowIdx = -1;
colIdx = -1;
rowIdxMinus1 = -1;
colIdxMinus1 = -1;
}
public GridPosition(int rowIdx, int colIdx) {
if(GridPosition.GRID == null) {
throw new IllegalStateException("Must set grid with: new GridPosition(int[][]).");
}
if(rowIdx < 0 || rowIdx >= GridPosition.getRowCount()) {
throw new IllegalArgumentException("rowIdx (" + rowIdx + ") is invalid.");
}
if(colIdx < 0 || colIdx >= GridPosition.getColumnCount()) {
throw new IllegalArgumentException("colIdx (" + colIdx + ") is invalid.");
}
this.rowIdx = rowIdx;
this.colIdx = colIdx;
rowIdxMinus1 = (rowIdx - 1);
colIdxMinus1 = (colIdx - 1);
}
public int getValue() {
return GridPosition.GRID[getRowIdx()][getColumnIdx()];
}
public int getRowIdx() {
return rowIdx;
}
public int getColumnIdx() {
return colIdx;
}
public GridPosition getNeighbor(Direction dir) {
Objects.requireNonNull(dir, "dir");
return (new GridPosition(
dir.getNewRowIdx(getRowIdx()),
dir.getNewColIdx(getColumnIdx())));
}
public GridPosition getNeighborNullIfEdge(Direction dir) {
if(isEdgeForDirection(dir)) {
return null;
}
return getNeighbor(dir);
}
public int getNeighborValueNeg1IfEdge(Direction dir) {
GridPosition pos = getNeighborNullIfEdge(dir);
return ((pos == null) ? -1 : pos.getValue());
}
public static final int getRowCount() {
return GRID.length;
}
public static final int getColumnCount() {
return GRID[0].length;
}
public boolean isEdgeForDirection(Direction dir) {
Objects.requireNonNull(dir);
switch(dir) {
case UP: return isTopEdge();
case DOWN: return isBottomEdge();
case LEFT: return isLeftEdge();
case RIGHT: return isRightEdge();
}
throw new IllegalStateException(toString() + ", dir=" + dir);
}
public boolean isLeftEdge() {
return (getColumnIdx() == 0);
}
public boolean isTopEdge() {
return (getRowIdx() == 0);
}
public boolean isBottomEdge() {
return (getRowIdx() == rowIdxMinus1);
}
public boolean isRightEdge() {
return (getColumnIdx() == colIdxMinus1);
}
public String toString() {
return "[" + getRowIdx() + "," + getColumnIdx() + "]=" + getValue();
}
public String getNineByNine() {
int[][] nineByNine = new int[3][3];
//Middle row
nineByNine[1][1] = getValue();
nineByNine[1][0] = getNeighborValueNeg1IfEdge(Direction.LEFT);
nineByNine[1][2] = getNeighborValueNeg1IfEdge(Direction.RIGHT);
//Top
GridPosition posUp = getNeighborNullIfEdge(Direction.UP);
if(posUp != null) {
nineByNine[0][0] = posUp.getNeighborValueNeg1IfEdge(Direction.LEFT);
nineByNine[0][1] = posUp.getValue();
nineByNine[0][2] = posUp.getNeighborValueNeg1IfEdge(Direction.RIGHT);
}
//Bottom
GridPosition posDown = getNeighborNullIfEdge(Direction.DOWN);
if(posDown != null) {
nineByNine[2][0] = posDown.getNeighborValueNeg1IfEdge(Direction.LEFT);
nineByNine[2][1] = posDown.getValue();
nineByNine[2][2] = posDown.getNeighborValueNeg1IfEdge(Direction.RIGHT);
}
String sLS = System.getProperty("line.separator", "\r\n");
return "Middle position in 9x9 grid is *this*: " + toString() + sLS +
Arrays.toString(nineByNine[0]) + sLS +
Arrays.toString(nineByNine[1]) + sLS +
Arrays.toString(nineByNine[2]);
}
}
public class GridPosDemo {
private static final int[][] GRID = new int[][] {
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1},
{1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1},
{1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,1},
{1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1},
{1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1},
{1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1},
{1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1},
{1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1},
{1,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1},
{1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1},
{1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1},
{1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1},
{1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1},
{1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1},
{1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,1},
{1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1},
{1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,1},
{1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1},
{1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1},
{1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1},
{1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,1},
{1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1},
{1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1},
{1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1},
{1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,1},
{1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1},
{1,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1},
{1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1},
{1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1},
{1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1},
{1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1},
{1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1},
{1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1}};
private static final GridPosition GRID_HOLDER = new GridPosition(GRID);
public static final void main(String[] ignored) {
GridPosition pos = new GridPosition(0, 0);
System.out.println("start: " + pos);
pos = pos.getNeighbor(Direction.RIGHT);
System.out.println("right: " + pos);
pos = pos.getNeighbor(Direction.RIGHT);
System.out.println("right: " + pos);
pos = pos.getNeighbor(Direction.DOWN);
System.out.println("down: " + pos);
pos = pos.getNeighbor(Direction.DOWN);
System.out.println("down: " + pos);
pos = pos.getNeighbor(Direction.RIGHT);
System.out.println("right: " + pos);
pos = pos.getNeighbor(Direction.DOWN);
System.out.println("down: " + pos);
pos = pos.getNeighbor(Direction.LEFT);
System.out.println("left: " + pos);
pos = pos.getNeighbor(Direction.UP);
System.out.println("up: " + pos);
pos = pos.getNeighbor(Direction.UP);
System.out.println("up: " + pos);
System.out.println(pos.getNineByNine());
}
}