简体   繁体   中英

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)

示例地图期望的路径

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

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.

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. 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).

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

Here's my solution (Java) in case someone is still interested. As @tobias_k suggested in his comment above, indeed BFS is the way to go:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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