Java:基于网格的滑动路径查找
我做了一个简单的益智游戏,你可以在网格上垂直或水平滑动一个球。标高格式只是一个数组,1表示可以放置在瓷砖上,0表示墙。在球碰到墙之前是不可能停下来的 示例级别:Java:基于网格的滑动路径查找,java,path-finding,Java,Path Finding,我做了一个简单的益智游戏,你可以在网格上垂直或水平滑动一个球。标高格式只是一个数组,1表示可以放置在瓷砖上,0表示墙。在球碰到墙之前是不可能停下来的 示例级别: map[][] = { {0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,1,1,1,0,0,2,0,1,1,1,1,0}, {0,0,1,1,1,1,1,1,1,1,0,1,0}, {0,1,1,1,1,0,1,1,1,1,1,1,0}, {0,1,0,1,1,1,1,1,1,1,
map[][] = {
{0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,1,1,1,0,0,2,0,1,1,1,1,0},
{0,0,1,1,1,1,1,1,1,1,0,1,0},
{0,1,1,1,1,0,1,1,1,1,1,1,0},
{0,1,0,1,1,1,1,1,1,1,1,1,0},
{0,1,0,1,1,1,1,1,0,1,1,1,0},
{0,1,1,0,1,1,1,1,1,1,1,1,0},
{0,1,1,1,0,1,1,0,1,1,1,1,0},
{0,1,1,1,1,0,1,1,1,1,1,1,0},
{0,1,1,1,1,1,0,1,1,0,1,1,0},
{0,1,1,1,1,1,3,1,1,1,1,1,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0}
}
(我知道先有Y轴有点麻烦)
问题是一个人究竟怎样才能做出一个算法来解决从起点(3)到目标(2)的所有可能路线。这让我在网上查找了一些常见的算法,但它们只解决了以下问题:
- 在网格上自由移动的路线
- 最有效的路线
//keep track of tiles the player has already been to
List<Integer> beenToX = new ArrayList<Integer>();
List<Integer> beenToY = new ArrayList<Integer>();
beenToX.add(0, 6); //starting x-coordinate
beenToY.add(0, 10); //starting y-coordinate
Boolean solving = true;
while (solving) {
for (int i = 0; i < 4; i++) { //num of directions N=0, E=1, S=2, W=3
for (int j = 1; j < 11; j++) {
if (i == 0) {
if (map[beenToY.get(0)+j][beenToX.get(0)] == 0) {
beenToX.add(0, currentX);
beenToY.add(0, beenToY.get(0)+j);
break;
}
if (map[beenToY.get(0)+j][beenToX.get(0)] == 2) {
beenToX.add(0, currentX);
beenToY.add(0, beenToY.get(0)+j);
solving = false;
break;
}
}
if (i == 1) {
if (map[beenToY.get(0)][beenToX.get(0)+j] == 0) {
beenToX.add(0, currentX);
beenToY.add(0, beenToY.get(0)+j);
break;
}
if (map[beenToY.get(0)][beenToX.get(0)+j] == 2) {
beenToX.add(0, currentX);
beenToY.add(0, beenToY.get(0)+j);
solving = false;
break;
}
}
if (i == 2) {
if (map[beenToY.get(0)-j][beenToX.get(0)] == 0) {
beenToX.add(0, currentX);
beenToY.add(0, beenToY.get(0)+j);
break;
}
if (map[beenToY.get(0)-j][beenToX.get(0)] == 2) {
beenToX.add(0, currentX);
beenToY.add(0, beenToY.get(0)+j);
solving = false;
break;
}
}
if (i == 3) {
if (map[beenToY.get(0)][beenToX.get(0)-j] == 0) {
beenToX.add(0, currentX);
beenToY.add(0, beenToY.get(0)+j);
break;
}
if (map[beenToY.get(0)][beenToX.get(0)-j] == 2) {
beenToX.add(0, currentX);
beenToY.add(0, beenToY.get(0)+j);
solving = false;
break;
}
}
}
}
}
//跟踪玩家已经访问过的磁贴
List beenToX=new ArrayList();
List beenToY=newarraylist();
添加(0,6)//起始x坐标
添加(0,10)//起始y坐标
布尔解=真;
同时(解决){
对于(inti=0;i<4;i++){//方向数N=0,E=1,S=2,W=3
对于(int j=1;j<11;j++){
如果(i==0){
if(map[beenToY.get(0)+j][beenToX.get(0)]==0){
beenToX.add(0,currentX);
beenToY.add(0,beenToY.get(0)+j);
打破
}
if(map[beenToY.get(0)+j][beenToX.get(0)]==2){
beenToX.add(0,currentX);
beenToY.add(0,beenToY.get(0)+j);
解决=错误;
打破
}
}
如果(i==1){
if(map[beenToY.get(0)][beenToX.get(0)+j]==0){
beenToX.add(0,currentX);
beenToY.add(0,beenToY.get(0)+j);
打破
}
if(map[beenToY.get(0)][beenToX.get(0)+j]==2){
beenToX.add(0,currentX);
beenToY.add(0,beenToY.get(0)+j);
解决=错误;
打破
}
}
如果(i==2){
if(map[beenToY.get(0)-j][beenToX.get(0)]==0){
beenToX.add(0,currentX);
beenToY.add(0,beenToY.get(0)+j);
打破
}
if(map[beenToY.get(0)-j][beenToX.get(0)]==2){
beenToX.add(0,currentX);
beenToY.add(0,beenToY.get(0)+j);
解决=错误;
打破
}
}
如果(i==3){
if(map[beenToY.get(0)][beenToX.get(0)-j]==0){
beenToX.add(0,currentX);
beenToY.add(0,beenToY.get(0)+j);
打破
}
if(map[beenToY.get(0)][beenToX.get(0)-j]==2){
beenToX.add(0,currentX);
beenToY.add(0,beenToY.get(0)+j);
解决=错误;
打破
}
}
}
}
}
然后我意识到我有一个问题:如何处理可能同时处理多个方向的程序?如何处理多条正确的路线
它还缺少一个部分来检查玩家已经去过哪些瓷砖,以避免在圆圈中奔跑。你的移动规则可能是非常规的,但这仍然是一个典型的寻路问题 Dijkstra、A-star和所有其他人都致力于任何图形表示。所以你只需要把你的运动抽象成一个图形。在最基本的层面上,它只意味着每个节点(状态)链接到几个其他节点 探路者不需要知道移动规则,它只需要一个
状态
表示,如下所示:
public interface State extends Comparable<State>{
List<? extends State> neighbours(); // Alternatively, return a Map<State, Integer> to associate a distance/cost
}
您已经设置好了,只需将两个
RollingBallState
(开始和结束)输入到您的寻路器中,它将为您提供路径。您的移动规则可能是非常规的,但这仍然是一个典型的寻路问题
Dijkstra、A-star和所有其他人都致力于任何图形表示。所以你只需要把你的运动抽象成一个图形。在最基本的层面上,它只意味着每个节点(状态)链接到几个其他节点
探路者不需要知道移动规则,它只需要一个状态
表示,如下所示:
public interface State extends Comparable<State>{
List<? extends State> neighbours(); // Alternatively, return a Map<State, Integer> to associate a distance/cost
}
您已经设置好了,只需将两个RollingBallState
(开始和结束)输入到您的Pathfinder
,它将为您提供路径。您尝试过经典的广度优先搜索吗?另外请注意,您可能希望保留布尔值的映射而不是列表,因为这样检查beenTo[x][y]
将是即时的,而不像beenToX.contains(x)和&beenToY.contains(y)
。嗯,只是检查一下。。。你的例子应该有解决方案吗?因为在我看来,它实际上并没有(尽管我可能错了)。我希望您的担忧不会来自于在没有有效路由输出的情况下期望有效的路由输出!;-)(编辑:刚刚看到这个已经有几个月了,你找到解决方案了吗?)这个解决方案是在一月份找到的,多亏了Sergey,不幸的是他刚刚留下了一条评论,所以我无法将其标记为最佳答案。你试过经典的广度优先搜索吗?另外请注意,您可能希望保留布尔值的映射而不是列表,因为这样检查beenTo[x][y]
将是即时的,而不像beenToX.contains(x)和&beenToY.contains(y)
。嗯,只是检查一下。。。你的例子应该有解决方案吗?因为在我看来,它实际上并没有(尽管我可能错了)。我希望您的担忧不会来自于在没有有效路由输出的情况下期望有效的路由输出!;-)(编辑:刚刚看到这个已经有几个月了,你找到解决方案了吗?)这个解决方案是在一月份找到的,多亏了谢尔盖,不幸的是,他只是留下了一条评论,所以我不能把它标记为最佳答案。
public class RollingBallState extends Point implements State{
private static map[][] map = [...];// This must be available somehow at the start, you decide how (hint: static var like I did is ugly AF)
public RollingBallState(int xStart, int yStart){
super(xStart, yStart);
}
@Override
public List<RollingBallState> neighbours(){
List<RollingBallState> neighbours = new ArrayList<>(4);
int xLeft = getX(); // Where the ball can travel left
for(int x=getX()-1; x>=0; x--){
if(map[x][getY()] == 0){
break;
} else{
xLeft = x;
}
}
if(xLeft < xBall){
neighbours.add(new RollingBallState(xLeft, getY()));
}
[...Get xRight, yUp, yDown, and add them in the same fashion ...]
return neighbours;
}
@Override
public int compareTo(RollingBallState other){
if(getX() == other.getX()){
return getY() - other.getY();
} else {
return getX() - other.getX();
}
}
}