使用AStar算法的15个难题

时间:2018-11-07 18:48:13

标签: java algorithm a-star

我使用曼哈顿距离的A-star算法制作了一个简单的15益智游戏。 对于简单的问题,它可以工作,但解决方案不是最佳解决方案。

例如,如果运动是:

  

右->上

我的解决方法是:

  

右->上->左->下->右->上

如果我有一个很难解决的游戏,那将花费无限的时间并且无法解决任何问题,我想是因为这个问题。

为了实现我的游戏,我遵循了A *算法的维基百科伪代码。 这是我的AStar函数:

public ArrayList<String> solution(Vector<Integer> start){

    ArrayList<String> movePath = new ArrayList<String>(); //Path to solution
    PriorityQueue<Node> closedQueue = new PriorityQueue<Node>(500,new Comparator<Node>() {
        @Override public int compare(Node a,Node b) {
            return a.get_fScore() - b.get_fScore();
        }
    });

    Node node = new Node(start,movePath,heuristic);
    int cnt =0;
    openQueue.add(node);

    while(!openQueue.isEmpty() ) {

        //Alt if it takes too much time (ToRemove)
        if(cnt == (150)*1000) {
            ArrayList<String> noResult = new ArrayList<String>();
            noResult.add("Timeout");
            return noResult;
        }

        Node bestNode = openQueue.remove(); //Remove best node from openQueue
        closedQueue.add(bestNode); //Insert its to closedQueue

        cnt++;
        if( cnt % 10000 == 0) {
            System.out.printf("Analizzo %,d posizioni. Queue Size = %,d\n", cnt, openQueue.size());
        }
        //Get first step from bestNode and add to movePath
        if(!bestNode.isEmptyMoves()) {
            String step = bestNode.get_moves().get(0);
            movePath.add(step);
        }
        //Exit Condition
        if(bestNode.get_hScore() == 0) {
            return bestNode.get_moves();
        }
        //Looking for childs
        Vector<Node> childs = get_nextMoves(bestNode);
        for(int i=0; i<childs.size(); i++) {

            if(closedQueue.contains(childs.elementAt(i))) 
                continue;

            childs.elementAt(i).set_gScore(bestNode.get_gScore()+1); //Increment level in tree

            if(!openQueue.contains(childs.elementAt(i)))
                openQueue.add(childs.elementAt(i));

            else {
                //!Never reached this level!
                System.out.println("Here!");
                //TODO Copy child from openQueue to closedQueue
            }

        }   
    }
    return null;

这是我寻找邻居的功能:

public Vector<Node> get_nextMoves(Node act){

    Vector<Node> steps = new Vector<Node>();
    int position = act.get_valuePos(0);
    String lastMove = act.get_lastMove();
    //System.out.println(lastMove);


    //Right Child
    if(position + 1 < 16 && position + 1!=3 && position + 1!=7 && position+1 !=11 && lastMove !="Left") {

        int temp_pos[] = copyToArray(act.get_posVect());//Copy array of positions of ACT to a temp_pos array
        temp_pos[position] = temp_pos[position+1]; //Switch 0 position with Right position
        temp_pos[position+1] = 0;

        ArrayList<String> temp_moves = new ArrayList<String>();
        for(int i=0; i<act.get_moves().size(); i++) {
            temp_moves.add(act.get_moves().get(i)); //Save old steps
        }
        temp_moves.add("Right");//And add new one

        Node child = new Node(temp_pos,temp_moves,act.get_heuristic()); //New Node
        steps.addElement(child);//Added to vector
    }
    //Left Child
    if(position - 1 >= 0 && position - 1 != 4 && position - 1 != 8 && position - 1 != 12 && lastMove !="Right") {
        int temp_pos[] = copyToArray(act.get_posVect());
        temp_pos[position] = temp_pos[position-1];
        temp_pos[position-1] = 0;

        ArrayList<String> temp_moves = new ArrayList<String>();
        for(int i=0; i<act.get_moves().size(); i++) {
            temp_moves.add(act.get_moves().get(i));
        }
        temp_moves.add("Left");

        Node child = new Node(temp_pos,temp_moves,act.get_heuristic());
        steps.addElement(child);
    }
    //Up Child
    if(position - 4 >= 0 && lastMove !="Down") {
        int temp_pos[] = copyToArray(act.get_posVect());
        temp_pos[position] = temp_pos[position-4];
        temp_pos[position-4] = 0;

        ArrayList<String> temp_moves = new ArrayList<String>();
        for(int i=0; i<act.get_moves().size(); i++) {
            temp_moves.add(act.get_moves().get(i));
        }
        temp_moves.add("Up");

        Node child = new Node(temp_pos,temp_moves,act.get_heuristic());
        steps.addElement(child);
    }
    //Down Child
    if(position + 4 < 16 && lastMove !="Up") {
        int temp_pos[] = copyToArray(act.get_posVect());
        temp_pos[position] = temp_pos[position+4];
        temp_pos[position+4] = 0;

        ArrayList<String> temp_moves = new ArrayList<String>();
        for(int i=0; i<act.get_moves().size(); i++) {
            temp_moves.add(act.get_moves().get(i));
        }
        temp_moves.add("Down");

        Node child = new Node(temp_pos,temp_moves,act.get_heuristic());
        steps.addElement(child);
    }
    return steps;

那是我的ManhattanDistance函数:

public int calcolaDist(Vector<Integer> A) {
    int result = 0;
    Vector<Integer> goal_Mat = initialize_Mat();

    for(int i=0; i<16; i++) {
        int x_goal = (goal_Mat.indexOf(i))/4;
        int y_goal =  (goal_Mat.indexOf(i))%4;

        int x_def = (A.indexOf(i))/4;
        int y_def = (A.indexOf(i))%4;

        if(A.elementAt(i) > 0) {

            result += Math.abs(x_def - x_goal);
            result += Math.abs(y_def - y_goal);
        }
    }

    return result;

如果我的难题是:

  

start = {1,3,0,4,5,2,7,8,9,6,10,11,13,14,15,12}

我的解决方法是:

  

[左,下,下,右,下,右,上,左,下,右,上,左,下,右]

我知道使用Vectors不是一个好选择,并且我的代码“有点”肮脏,但是一旦摆脱这个问题,我将立即清理它!

谢谢大家!

1 个答案:

答案 0 :(得分:0)

首先,我发现您的代码与OPEN和CLOSED队列有些混淆。 OPEN队列应该是管理节点(PriorityQueue)优先级的队列。 CLOSED不需要这样做,因为它仅存储访问的节点及其成本(也许您的算法通过HashSetHashMap更改CLOSED会更有效,以避免也将节点排序为CLOSED)。我在您的代码中看不到如何初始化OPEN队列,但这也许是您实现A *的问题。

我在代码中看到的另一个问题是,基于A *的算法需要管理到达已处于“打开/关闭”状态但成本不同的节点的情况。如果您从其他父节点访问一个节点,或者您进入一个循环,则可能会发生这种情况。如果不考虑该算法,该算法将无法正常工作。

  1. 如果您访问的节点已经在OPEN队列中,并且新节点的f分数较低,则应从OPEN中删除旧节点,然后插入成本较低的节点。
  2. 如果该节点的成本较高(处于“打开”或“关闭”状态),则应简单地丢弃该节点以避免循环。

问题虽然存在,但是状态空间是有限的,算法应该在某个时候结束。我看到您的实现是用Java实现的。如果您看看具有Hipster4jan implementation of A*的图书馆an example solving the 8-puzzle,这可能对您有帮助。

希望我的回答有帮助。祝你好运!