简体   繁体   English

冰滑动拼图路径发现

[英]Ice Sliding Puzzle Path Finding

I apologize for the somewhat vague title, I'm unsure what you would call this puzzle. 我为这个有点模糊的标题道歉,我不确定你会把这个拼图称为什么。

I'm making a path finding method to find the route with the least moves, not the distance traveled. 我正在寻找一种路径查找方法,以找到移动最少的路线,而不是行进的距离。

The rules of the game are simple, you must traverse from the orange square to the green square, but you can only move in a straight line, and cannot stop moving in that direction until you hit a boundary (either the wall of the arena or an obstacle), as if they were sliding across ice. 游戏规则很简单,你必须从橙色方块移动到绿色方块,但你只能沿着一条直线移动,并且不能停止朝那个方向移动,直到你到达一个边界(竞技场的墙壁或一个障碍,好像它们在冰上滑行。

Example map, and unless I'm mistaken, the desired path (8 moves) 示例地图,除非我弄错了,所需的路径(8个移动)

示例地图期望的路径

Arena.java: https://gist.github.com/CalebWhiting/3a6680d40610829b1b6d Arena.java: https://gist.github.com/CalebWhiting/3a6680d40610829b1b6d

ArenaTest.java: https://gist.github.com/CalebWhiting/9a4767508831ea5dc0da ArenaTest.java: https://gist.github.com/CalebWhiting/9a4767508831ea5dc0da

I'm assuming this would be best handled with a Dijkstras or A* path finding algorithm, however I'm not only not very experienced with these algorithms, but also don't know how I would go about defining the path rules. 我假设这最好用Dijkstras或A *路径查找算法处理,但是我不仅对这些算法不是很有经验,而且我也不知道如何定义路径规则。

Thank you for any help in advance. 感谢您提前提供的任何帮助。

I think the best solution would probably be the BFS, where you represent the state of the board with a "State" object with the following parameters: number of moves made so far, and coordinates. 我认为最好的解决方案可能是BFS,你可以用一个带有以下参数的“状态”对象来表示电路板的状态:到目前为止所做的移动次数和坐标。 It should also have a method to find the next states attainable (which should be fairly easy to code, just go N, S, E, W and return an array of the first blocking spots). 它还应该有一个方法来找到可达到的下一个状态(这应该相当容易编码,只需要去N,S,E,W并返回第一个阻塞点的数组)。

Create initial state (0 moves with initial coordinates)
Put in a priority queue (sorting by number moves)
while(priority queue has more states):
    Remove node
    if it is a goal state:
        return the state
    Find all neighbors of current state
    Add them to priority queue (remembering to increment number of moves by 1)

This uses an implicit graph representation. 这使用隐式图表示。 Optimality is guaranteed because of the priority queue; 由于优先级队列,保证了最优性; when the goal state is found, it will have been reached with the fewest moves. 当找到目标状态时,将以最少的动作达到目标状态。 If the whole priority queue is exhausted and no state is returned, then no solution exists. 如果整个优先级队列已用尽且未返回任何状态,则不存在解决方案。 This solution takes O(V^2logV) time because of the priority queue, but I think this is the simplest to code. 由于优先级队列,此解决方案需要O(V ^ 2logV)时间,但我认为这是最简单的代码。 A straight up O(V) BFS solution is possible but you'll have to keep track of what states you have or have not visited yet and the fewest number of moves to reach them, which would take O(V) memory. 一个直接的O(V)BFS解决方案是可能的,但是您必须跟踪您已经或尚未访问过的状态以及到达它们的移动次数最少,这将需要O(V)内存。

Here's my solution (Java) in case someone is still interested. 这是我的解决方案(Java),以防有人仍然感兴趣。 As @tobias_k suggested in his comment above, indeed BFS is the way to go: 正如@tobias_k在上面的评论中所建议的那样, BFS确实是要走的路:

import java.util.LinkedList;

public class PokemonIceCave {
    public static void main(String[] args) {
        int[][] iceCave1 = {
                {0, 0, 0, 1, 0},
                {0, 0, 0, 0, 1},
                {0, 1, 1, 0, 0},
                {0, 1, 0, 0, 1},
                {0, 0, 0, 1, 0}
        };
        System.out.println(solve(iceCave1, 0, 0, 2, 4));
        System.out.println();

        int[][] iceCave2 = {
                {0, 0, 0, 1, 0},
                {0, 0, 0, 0, 1},
                {0, 1, 1, 0, 0},
                {0, 1, 0, 0, 1},
                {0, 0, 0, 1, 0},
                {0, 0, 0, 0, 0}
        };
        System.out.println(solve(iceCave2, 0, 0, 2, 5));
    }

    public static int solve(int[][] iceCave, int startX, int startY, int endX, int endY) {
        Point startPoint = new Point(startX, startY);

        LinkedList<Point> queue = new LinkedList<>();
        Point[][] iceCaveColors = new Point[iceCave.length][iceCave[0].length];

        queue.addLast(new Point(0, 0));
        iceCaveColors[startY][startX] = startPoint;

        while (queue.size() != 0) {
            Point currPos = queue.pollFirst();
            System.out.println(currPos);
            // traverse adjacent nodes while sliding on the ice
            for (Direction dir : Direction.values()) {
                Point nextPos = move(iceCave, iceCaveColors, currPos, dir);
                System.out.println("\t" + nextPos);
                if (nextPos != null) {
                    queue.addLast(nextPos);
                    iceCaveColors[nextPos.getY()][nextPos.getX()] = new Point(currPos.getX(), currPos.getY());
                    if (nextPos.getY() == endY && nextPos.getX() == endX) {
                        // we found the end point
                        Point tmp = currPos;  // if we start from nextPos we will count one too many edges
                        int count = 0;
                        while (tmp != startPoint) {
                            count++;
                            tmp = iceCaveColors[tmp.getY()][tmp.getX()];
                        }
                        return count;
                    }
                }
            }
            System.out.println();
        }
        return -1;
    }

    public static Point move(int[][] iceCave, Point[][] iceCaveColors, Point currPos, Direction dir) {
        int x = currPos.getX();
        int y = currPos.getY();

        int diffX = (dir == Direction.LEFT ? -1 : (dir == Direction.RIGHT ? 1 : 0));
        int diffY = (dir == Direction.UP ? -1 : (dir == Direction.DOWN ? 1 : 0));

        int i = 1;
        while (x + i * diffX >= 0
                && x + i * diffX < iceCave[0].length
                && y + i * diffY >= 0
                && y + i * diffY < iceCave.length
                && iceCave[y + i * diffY][x + i * diffX] != 1) {
            i++;
        }

        i--;  // reverse the last step

        if (iceCaveColors[y + i * diffY][x + i * diffX] != null) {
            // we've already seen this point
            return null;
        }

        return new Point(x + i * diffX, y + i * diffY);
    }

    public static class Point {
        int x;
        int y;

        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }

        public int getX() {
            return x;
        }

        public int getY() {
            return y;
        }

        @Override
        public String toString() {
            return "Point{" +
                    "x=" + x +
                    ", y=" + y +
                    '}';
        }
    }

    public enum Direction {
        LEFT,
        RIGHT,
        UP,
        DOWN
    }
}

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

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