Java:使用滑动

时间:2016-01-11 17:21:02

标签: 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,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;
                }
            }
        }
    }
}

然后我意识到我有一个问题:我如何处理可能同时处理多个方向的程序?如何处理多条正确的路线?

它还缺少一个部分来检查玩家已经去过哪些牌,以避免在圈内跑。

1 个答案:

答案 0 :(得分:0)

你的行动规则可能是非常规的,但它仍然是一个典型的寻路问题。

Dijkstra,A-star以及所有其他人在任何图表表示上的工作。所以你只需要将你的运动抽象成图形表示。在最基本的层面上,它只表示每个节点(State)链接到其他一些节点。

路径查找器不需要知道移动规则,只需要State表示如下:

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

我假设您知道如何编写与此接口匹配的Pathfinder类(否则在S:O上查看):

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

在这种情况下,这是一个合理的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();
         }
    }
}

您完成所有设置,只需向RollingBallState提供两个Pathfinder(开始和结束),它就会为您提供路径。