4

これらのヒューリスティックで A* 検索を使用して 8 パズルを解こうとしています: - h1: 間違って配置されたタイルの数 - h2: マンハッタンの合計距離 - h3: 上記の合計

移動タイルは 0 として知られています。

私の目標は、これらのセットを解決することです:

4 1 2
5 8 3
7 0 6

8 6 7
2 5 4
3 0 1

私が抱えている問題は、現在の A* の実装では、最初の問題は解決できますが、2 番目の問題は解決できないということです。

だから、私のA *コードの何が問題なのかを理解するのを手伝ってください:

int[,] current = コンソールから文字列 (412583706) として入力され、パズルを表す 2D int に変換されます。正しい場合も同じで、0 は右下隅にあります。

var openList = new List<int[,]> { current };
var closedList = new List<int[,]>();

while (openList.Count > 0)
{
    steps++;
    current = GetBestNodeFromList(correct, dimensions, openList, useHeuristic);
    // "GetBestNodeFromList()" finds the cheapest node in the openList.
    // cheapest node: lowest value of h3.

    openList.Remove(current);
    h1 = getHeuristic1b(current, correct, dimensions);
    h2 = getHeuristic2b(current, correct, dimensions);
    h3 = h1 + h2;
    if (h1 == 0 && h2 == 0) { break; }

    openList = Puzzle_PossibleNext(current, closedList);
    // the method "PossibleNext()" finds possible next moves from the current
    // position. if the next move exists in the closedList, it is discarded.

    // Drawing the puzzle and showing heuristics.
    DrawCurrentState(h1, h2, h3, current, steps);

    // adding last visited position to the closedlist.
    closedList.Add(current);
}

最初の問題は 7 つのステップで解決されます。私がテストした別のプログラムによると、次の問題は 32 ステップで解決できます。

私のプログラムが他のプログラムと異なる点は、最初の 4 つのステップが同じで、他のプログラムが別のルートを選択することです。私のプログラムが最も安いノードを選択したように見えるので、何が悪いのか理解できません。

経路探索アルゴリズムは初めてなので解いてみたいと思います。私はこの問題を 3 日間抱えていて、多くの解決策を試したような気がしますが、どれもうまくいきません T_T

よろしくお願いします。

----編集----- 追加コード:

// Put heuristic value from all in list, then return list item with lowest h-value.
static int[,] GetBestNodeFromList(int[,] correct, int d, List<int[,]> list, string useHeuristic)
{
    int[,] n = new int[d,d];
    if (list.Count > 0)
    {
        List<Int32> heuristicsValueList = new List<Int32>();
        for (int i = 0; i < list.Count; i++)
        {
            if (useHeuristic == "h1")      { heuristicsValueList.Add(getHeuristic1b(list[i], correct, d)); }
            else if (useHeuristic == "h2") { heuristicsValueList.Add(getHeuristic2b(list[i], correct, d)); }
            else  { heuristicsValueList.Add(getHeuristic3(list[i], correct, d)); }
        }
        n = list[heuristicsValueList.IndexOf(heuristicsValueList.Min())];
    }
    return n;
}

---------編集 2-------- 私のコードを少し変更しましたが、パズルのセットアップ/ノードとそのヒューリスティックはすべて PuzzleNode オブジェクトにあります。

// 現在のノードから次に可能な移動のリストを返します。// closedNodeList 内で見つかった移動は含まれません。

static List<PuzzleNode> Puzzle_GenerateNextNodes(PuzzleNode node, List<PuzzleNode> closedNodeList)
        {
            List<PuzzleNode> nextList = new List<PuzzleNode>();
            Point isNow = new Point(0, 0);

            // 1) Find where [0] is.
            int dimensions = (int)Math.Sqrt((double)node.n.Length);
            for (int x = 0; x < dimensions; x++) {
                for (int y = 0; y < dimensions; y++) { if (node.n[x, y] == 0) { isNow.X = y; isNow.Y = x; break; } }
            }

            // 2) Check possible moves.
            bool moveUp = false, moveDown = false, moveLeft = false, moveRight = false;

            if (isNow.X == 0)
            {
                moveRight = true;
                if (isNow.Y == 0) { moveDown = true; }
                else if (isNow.Y == 1) { moveUp = true; moveDown = true; }
                else if (isNow.Y == 2) { moveUp = true; }
            }
            else if (isNow.X == 1)
            {
                moveRight = true;
                moveLeft = true;
                if (isNow.Y == 0) { moveDown = true; }
                else if (isNow.Y == 1) { moveUp = true; moveDown = true; }
                else if (isNow.Y == 2) { moveUp = true; }
            }
            else if (isNow.X == 2)
            {
                moveLeft = true;
                if (isNow.Y == 0) { moveDown = true; }
                else if (isNow.Y == 1) { moveUp = true; moveDown = true; }
                else if (isNow.Y == 2) { moveUp = true; }
            }
            // 3) Create list of possible moves.

// Add moved puzzle node to list over next moves 
            if (moveRight)
            {
                int[,] right = new int[dimensions, dimensions];
                Array.Copy(node.n, right, node.n.Length);
                PuzzleNode tmp = new PuzzleNode( PuzzleMoveRight(right, isNow.X, isNow.Y) );
                if (!ListHasThisValue(tmp.n, closedNodeList, dimensions)) { nextList.Add(tmp); }
            }
// moveleft, up, down, same structure as moveRight
            if (moveLeft)
            {
                ..
            }
            if (moveUp)
            {
                ..
            }
            if (moveDown)
            {
                ..
            }

            return nextList;
        }

-----------編集3----------------

ところで、A* のさまざまなステップの実装が正しく理解されているかどうかを尋ねたいと思います。現時点では、私のプログラムの A* 検索はこれを行います:

  1. 初期リスト OPEN および CLOSED を作成し、開始ノードを OPEN に追加します
  2. ループを開始し、OPEN から最も安価なノードを削除し、CLOSED に追加します *最も安価なノードは、そのマンハッタン距離値によって決定されます。
  3. ノードを使用して隣人/子供/次の動きを見つけ、これらを SUCCESSOR リストに追加します。
  4. SUCCESSOR リストを探索し、それらのいずれかに目標状態が含まれているかどうかを確認し、そうでない場合は OPEN リストに追加します
  5. 2 ~ 4 を繰り返し、リスト内のノードを調べます。

Q1 でこれらの手順を試すと、7 つの手順で解決策が得られます。これは正しいです。これも手探りで発見。しかし、第 2 四半期では、OPEN リストが空になり、他に探索するものがなくなるまで続きます。それで、私は何が欠けていますか?

4

2 に答える 2

0

この問題で私を助けてくれてありがとう。

今日、問題を見つけることができました。なんて言っていいのかわからない、本当にバカバカしい。問題はコードや A* 実装ではありません (私の現在のコードは以前に投稿したものと異なる場合があります)。

この問題は、使用されるヒューリスティックに過度に依存していました。Q1 では、ヒューリスティックな h1、h2、および h3 (h1 と h2 のコストは同じ) はすべて解を見つけることができたようです。ただし、Q2 では、h2 と h3 の両方がソリューションへのパスを見つけることができませんでしたが、h1 は見つけました。私のプログラムでは、デバッグとテストのデフォルトのヒューリスティックとして h3 を使用し続けましたが、これも私の失敗でした。

したがって、学ぶべき教訓は、自分が何を扱っているかを知ることです。最も単純なヒューリスティックでさえ、その違いに気付くことができませんでした。

Q1とQ2を解けるようになりました。ありがとうございました。プログラマーとして、私は確かにこれから学びました。

でも、時間を割いて助けてくれたことにもっと目に見える功績を残せたらいいのにと思います。

于 2014-07-23T10:39:27.480 に答える