简体   繁体   English

Java:带滑动的基于网格的路径查找

[英]Java: Grid-based path finding with sliding

I have made a simple puzzle game where you slide a ball either vertically or horizontally on a grid. 我做了一个简单的益智游戏,您可以在网格上垂直或水平滑动球。 The level format is just an array with 1 meaning a tile you can be onto and 0 being a wall. 关卡格式只是一个数组,其中1表示可以放置的瓷砖,0表示墙。 It's not possible to stop until the ball meets a wall. 直到球碰到墙才停止。

Example level: 示例级别:

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}
}

(I know it's a bit troublesome to have Y-axis first) (我知道先拥有Y轴有点麻烦)

The problem is how on earth can one make an algorithm that solves all possible routes from the starting point (3) to the goal (2). 问题在于,地球上如何能够制定一种算法,解决从起点(3)到目标(2)的所有可能路线。 This made me look up some common algorithms online but they only solved: 这使我在线查找了一些常用算法,但只能解决:

  • a route on a grid with free movement 自由移动的网格上的路线
  • the most efficient route 最有效的路线

I have written this: 我写了这个:

//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;
                }
            }
        }
    }
}

Then I realized I have a problem: How do I deal with the program handling multiple direction possibly at the same time? 然后我意识到我有一个问题:如何处理可能同时处理多个方向的程序? How about dealing with multiple correct routes? 如何处理多条正确的路线?

It's also missing a section to check which tiles the player has already been to, to avoid running in circles. 它还缺少一个部分来检查玩家已经去过哪些图块,以避免盘旋。

Your movement rules might be unconventional, but it's still a classic pathfinding problem. 您的运动规则可能不合常规,但这仍然是经典的寻路问题。

Dijkstra, A-star and all the rest work on any graph representation. Dijkstra,A-star和其他所有人都可以在任何图形表示形式上工作。 So you just need to abstract yout movement away into a graph representation. 因此,您只需要将运动抽象为图形表示即可。 At the most basic level, it only means each Node (State) links to a few other Nodes. 在最基本的级别上,它仅意味着每个节点(状态)链接到其他几个节点。

A pathfinder does not need to know yabout movement rules, it only needs a State representation like so: 探路者不需要知道运动规则,只需要像这样的State表示:

public interface State extends Comparable<State>{
    List<? extends State> neighbours(); // Alternatively, return a Map<State, Integer> to associate a distance/cost
}

I assume you know how to code a Pathfinder class that matches this interface (otherwise look around on S:O): 我假设您知道如何编写与该接口匹配的Pathfinder类(否则在S:O上四处看看):

public interface Pathfinder(){
    List<State> path(State start, State end);
}

In this case, here's what a resonable State implementation would look like for you: 在这种情况下,合理的State实施对您来说是什么样子:

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();
         }
    }
}

You're all set up, just feed two RollingBallState (start & end) to your Pathfinder , it will give you the path. 一切RollingBallState ,只需将两个RollingBallState (开始和结束)输入到Pathfinder ,它将为您提供路径。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM