我为这个有点模糊的标题道歉,我不确定你会把这个拼图称为什么。
我正在寻找一种路径寻找方法来找到行动最少的路线,而不是行进的距离。
游戏规则很简单,你必须从橙色方块移动到绿色方块,但你只能沿着一条直线移动,并且不能停止朝那个方向移动,直到你到达一个边界(或者是竞技场或障碍物,就好像它们在冰上滑行一样。
示例地图,除非我弄错了,所需路径(8次移动)
Arena.java:https://gist.github.com/CalebWhiting/3a6680d40610829b1b6d
ArenaTest.java:https://gist.github.com/CalebWhiting/9a4767508831ea5dc0da
我认为这最好用Dijkstras或A *路径查找算法处理,但是我不仅对这些算法不是很有经验,而且我也不知道如何定义路径规则
感谢您提前提供任何帮助。
答案 0 :(得分:0)
我认为最好的解决方案可能是BFS,在这里您可以使用以下参数表示具有“状态”对象的电路板状态:到目前为止所做的移动次数和坐标。它还应该有一个方法来找到可达到的下一个状态(这应该相当容易编码,只需要去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)
这使用隐式图表表示。由于优先级队列,保证了最优性;当找到目标状态时,将以最少的动作达到目标状态。如果整个优先级队列已用尽且未返回任何状态,则不存在解决方案。由于优先级队列,此解决方案需要O(V ^ 2logV)时间,但我认为这是最简单的代码。可以直接使用O(V)BFS解决方案,但是您必须跟踪您已经或尚未访问过的状态以及到达它们的移动次数最少,这将需要O(V)内存。
答案 1 :(得分:0)
如果有人仍然感兴趣,这是我的解决方案(Java)。正如@tobias_k在上面的comment中所建议的那样,确实 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
}
}