我制作了一个简单的益智游戏,您可以在网格上垂直或水平滑动球。级别格式只是一个数组,其中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;
}
}
}
}
}
然后我意识到我有一个问题:我如何处理可能同时处理多个方向的程序?如何处理多条正确的路线?
它还缺少一个部分来检查玩家已经去过哪些牌,以避免在圈内跑。
答案 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
(开始和结束),它就会为您提供路径。