2

私は現在、Java で小さなタワーディフェンス プロジェクトに取り組んでおり、経路探索に行き詰まりました。私は A* dijkstra などについて多くのことを読みましたが、経路探索には Floyd-Warshall を使用するのがおそらく最善であると判断しました (少なくとも、すべてのペアの最短経路問題を解決しているように思えます)。

とにかく、私は自分でそれを実装しようとしましたが、本来のように機能しません。ウィキペディアのコードを最初に使用しましたhttp://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm

だからここに私のコードがあります:

public class MyMap {
public class MyMapNode {
    // list of neighbour nodes
    public List<MyMapNode> neighbours;
    // Currently no need for this :)
    public int cellX, cellY;
    // NodeIndex for pathreconstruction
    public int index;
    // this value is checked by units on map to decide wether path needs
    // reconstruction
    public boolean isFree = true;

    public MyMapNode(int cellX, int cellY, int index) {
        this.cellX = cellX;
        this.cellY = cellY;
        this.index = index;
        neighbours = new ArrayList<MyMapNode>();
    }

    public void addNeighbour(MyMapNode neighbour) {
        neighbours.add(neighbour);
    }

    public void removeNeighbour(MyMapNode neighbour) {
        neighbours.remove(neighbour);
    }

    public boolean isNeighbour(MyMapNode node) {
        return neighbours.contains(node);
    }
}
//MapSize
public static final int CELLS_X = 10;
public static final int CELLS_Y = 10;

public MyMapNode[][] map;

public MyMap() {
    //Fill Map with Nodes
    map = new MyMapNode[CELLS_X][CELLS_Y];
    for (int i = 0; i < CELLS_X; i++) {
        for (int j = 0; j < CELLS_Y; j++) {
            map[i][j] = new MyMapNode(i, j, j + i * CELLS_Y);
        }
    }
    //-------------------------------------------------
    initNeighbours();
    recalculatePath();
}

public void initNeighbours() {
    //init neighbourhood without diagonals
    for (int i = 0; i < CELLS_X; i++) {
        for (int j = 0; j < CELLS_Y; j++) {
            int x, y;// untere Grenze
            if (j == 0)
                y = 0;
            else
                y = -1;
            if (i == 0)
                x = 0;
            else
                x = -1;
            int v, w;// obere Grenze
            if (j == CELLS_Y - 1)
                w = 0;
            else
                w = 1;
            if (i == CELLS_X - 1)
                v = 0;
            else
                v = 1;
            for (int h = x; h <= v; h++) {
                if (h != 0)
                    map[i][j].addNeighbour(map[i + h][j]);
            }
            for (int g = y; g <= w; g++) {
                if (g != 0)
                    map[i][j].addNeighbour(map[i][j + g]);
            }

        }
    }
}
//AdjacencyMatrix
public int[][] path = new int[CELLS_X * CELLS_Y][CELLS_X * CELLS_Y];
//for pathreconstruction
public MyMapNode[][] next = new MyMapNode[CELLS_X * CELLS_Y][CELLS_X
        * CELLS_Y];

public void initAdjacency() {
    for (int i = 0; i < map.length; i++) {
        for (int j = 0; j < map[0].length; j++) {
            path[i][j] = 1000;
            List<MyMapNode> tmp = map[i][j].neighbours;
            for (MyMapNode m : tmp) {
                path[m.index][map[i][j].index] = 1;
                path[map[i][j].index][m.index] = 1;
            }
        }
    }
}

public void floydWarshall() {
    int n = CELLS_X * CELLS_Y;
    for (int k = 0; k < n; k++) {
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (path[i][k] + path[k][j] < path[i][j]) {
                    path[i][j] = path[i][k] + path[k][j];
                    next[i][j] = getNodeWithIndex(k);
                }
            }
        }
    }
}

public void recalculatePath() {
    initAdjacency();
    floydWarshall();
}

public MyMapNode getNextWayPoint(MyMapNode i, MyMapNode j) {
    if (path[i.index][j.index] >=1000)
        return null;
    MyMapNode intermediate = next[i.index][j.index];
    if (intermediate == null)
        return j; /* there is an edge from i to j, with no vertices between */
    else
        return getNextWayPoint(i, intermediate);
}

public MyMapNode getNodeWithIndex(int k) {
    //for testing purpose,this can be done faster
    for (int i = 0; i < map.length; i++) {
        for (int j = 0; j < map[0].length; j++) {
            if (map[i][j].index == k)
                return map[i][j];
        }
    }
    return null;
}

public void removeMapNode(MyMapNode m) {
    //for testing purpose,this can be done faster
    m.isFree = false;
    for (int i = 0; i < map.length; i++) {
        for (int j = 0; j < map[0].length; j++) {
            if (map[i][j].neighbours.contains(m)) {
                map[i][j].neighbours.remove(m);
            }
        }
    }
}

}

Floyd-Warshall アルゴリズムはグラフで機能するように設計されているため、すべてのノードがその隣接ノード (接続先のノード) を認識しているグラフを作成します。

私は実際にそれがどこでうまくいかないのか今はわかりませんが、どういうわけかそうです。しかし、少なくとも隣接行列の初期化は機能しているようです。

floydwarshall 関数では、next[][] で次のノードのインデックスを取得したかったのですが、null または 10/11 しか取得できませんでした。

だから私の質問は、私が間違っていること、または私のアプローチがまったく間違っていることです? 誰かが私を助けてくれることを願っています。さらに情報が必要な場合はお尋ねください

pS 下手な英語でごめんなさい ;)

4

1 に答える 1

1

Java を利用できませんが、initAdjacency() 関数に欠陥があるようです。path[][] は次元 [CELL_X * CELLS_Y][CELLS_X * CELLS_Y] ですが、[CELL_X][CELL_Y] であるマップの次元を反復処理しているため、エッジのないすべての要素をデフォルトに設定するわけではありません値は 1000 で、最終的には 0 になります。

追加してみる

for (int i = 0; i < CELLS_X * CELLS_Y; i++)
    for (int j = 0; j < CELLS_X * CELLS_Y; j++)
        path[i][j] = 1000;

ループの前に initAdjacency() 関数の先頭に移動して、適切に初期化します。

あなたもやりたいかもしれません

for (int i = 0; i < CELLS_X * CELLS_Y) path[i][i] = 0;

その後、念のため、これがアルゴリズムに影響するかどうかはわかりません。

于 2012-04-11T10:21:55.840 に答える