Algorithm 关于将A*与15方块拼图结合使用的问题

Algorithm 关于将A*与15方块拼图结合使用的问题,algorithm,graph,a-star,Algorithm,Graph,A Star,我正试着为一家公司建立一个 目标是重新排列瓷砖,使其显示在其自然位置。一次只能滑动一个磁贴。谜题的每个可能状态都是搜索图中的一个节点 对于h(x)函数,我使用了所有分片的总和,分片与目标状态的错位。在上图中,5位于位置0,0,它属于位置1,0,因此它为h(x)函数贡献了1。下一个瓷砖是11,位于0,1,属于2,2,因此它对h(x)贡献了3。等等编辑:我现在明白了这就是他们所谓的“曼哈顿距离”或“曼哈顿距离” 我一直在使用g(x)的步长计数。在我的实现中,对于状态图中的任何节点,g与前一个节点

我正试着为一家公司建立一个

目标是重新排列瓷砖,使其显示在其自然位置。一次只能滑动一个磁贴。谜题的每个可能状态都是搜索图中的一个节点

对于h(x)函数,我使用了所有分片的总和,分片与目标状态的错位。在上图中,5位于位置0,0,它属于位置1,0,因此它为h(x)函数贡献了1。下一个瓷砖是11,位于0,1,属于2,2,因此它对h(x)贡献了3。等等编辑:我现在明白了这就是他们所谓的“曼哈顿距离”或“曼哈顿距离”

我一直在使用g(x)的步长计数。在我的实现中,对于状态图中的任何节点,g与前一个节点的g仅相差+1

为了找到连续的节点,我只需检查在哪里可以移动拼图中的“洞”。显示的拼图状态(又名节点)有3个邻居:洞可以向北、向西或向东移动

我的A*搜索有时在20秒内收敛到一个解决方案,有时在180秒内收敛,有时根本不收敛(等待10分钟或更长时间)。我认为h是合理的。我想知道我是否正确地建模了g。换句话说,我的A*函数是否可能通过非最短路径的路径到达图中的节点

也许我等的时间不够长?也许10分钟不够长

对于完全随机排列(假设没有奇偶校验问题),a*解决方案将检查的平均排列数是多少?(请显示数学)

我将在代码中查找逻辑错误,但同时, 有什么建议吗

(附言:这是用Javascript完成的)

还有,不,这不是作业。这只是个人的探索。我只是想学习Javascript


编辑:我发现运行时高度依赖于启发式。我看到有人提到的文章将10倍因子应用于启发式,这让我想知道——为什么是10倍?为什么是线性的?因为这是在javascript中完成的,所以我可以修改代码来动态更新html表,其中包含当前正在考虑的节点。这让我得以在算法进行的过程中窥视它。通过常规的出租车距离启发,我看到它无法收敛

最上面一排有5个和12个,他们一直在闲逛。我会看到1,2,3,4爬到最上面一行,但是他们会退出,其他数字会上升。我希望看到的是1,2,3,4爬到顶端,然后留在那里

我想,这不是我个人解决问题的方式。手动执行此操作时,我会同时求解第一行、第二行、第三行和第四行

因此,我调整了h(x)函数,使更高的行和“左”列的权重更大。结果是A*收敛得更快。它现在在3分钟内运行,而不是“无限期”。通过我提到的“偷看”,我可以看到较小的数字爬到较高的行并停留在那里。这看起来不仅是正确的,而且运行速度更快

我正在尝试一系列的变化。很明显,A*运行时对启发式非常敏感。目前,我发现最好的启发式方法是使用位错*((4-I)+(4-j))的总和,其中I和j是行和列,位错是出租车距离

我得到的结果中有一个有趣的部分:使用特定的启发式方法,我很快找到了一条路径,但它显然不是最短路径。我认为这是因为我对启发式进行加权。在一个例子中,我得到了10秒内178步的路径。我自己的手动工作产生了87步的解决方案。(远远超过10秒)。需要进行更多的调查

所以结果是我看到它收敛得更快,而且路径肯定不是最短的。我得多想想


代码:

var stop = false; 
function Astar(start, goal, callback) {
    // start and goal are nodes in the graph, represented by 
    // an array of 16 ints.  The goal is:  [1,2,3,...14,15,0] 
    // Zero represents the hole. 

    // callback is a method to call when finished. This runs a long time, 
    // therefore we need to use setTimeout() to break it up, to avoid
    // the browser warning like "Stop running this script?"

    // g is the actual distance traveled from initial node to current node.
    // h is the heuristic estimate of distance from current to goal.
    stop = false;
    start.g = start.dontgo = 0;

    // calcHeuristic inserts an .h member into the array
    calcHeuristicDistance(start);

    // start the stack with one element
    var closed = [];       // set of nodes already evaluated.
    var open = [ start ];  // set of nodes to evaluate (start with initial node)

    var iteration = function() {
        if (open.length==0) {
            // no more nodes.  Fail. 
            callback(null);
            return;
        }
        var current = open.shift();  // get highest priority node

        // update the browser with a table representation of the 
        // node being evaluated
        $("#solution").html(stateToString(current));

        // check solution returns true if current == goal
        if (checkSolution(current,goal)) {
            // reconstructPath just records the position of the hole 
            // through each node
            var path= reconstructPath(start,current);
            callback(path);
            return;
        }

        closed.push(current);

        // get the set of neighbors.  This is 3 or fewer nodes.
        // (nextStates is optimized to NOT turn directly back on itself)
        var neighbors = nextStates(current, goal);

        for (var i=0; i<neighbors.length;  i++) {
            var n = neighbors[i];

            // skip this one if we've already visited it
            if (closed.containsNode(n)) continue;

            // .g, .h, and .previous get assigned implicitly when 
            // calculating neighbors.  n.g is nothing more than
            // current.g+1 ;

            // add to the open list
            if (!open.containsNode(n)) {
                // slot into the list, in priority order (minimum f first)
                open.priorityPush(n);
                n.previous = current;
            }
        }

        if (stop) {
            callback(null);
            return;
        }

        setTimeout(iteration, 1);
    };

    // kick off the first iteration
    iteration();

    return null;
}
var-stop=false;
函数Astar(开始、目标、回调){
//开始和目标是图中的节点,由
//16整数的数组。目标是:[1,2,3,…14,15,0]
//零代表洞。
//callback是一个在完成时调用的方法。它会运行很长时间,
//因此,我们需要使用setTimeout()来分解它,以避免
//浏览器警告,如“停止运行此脚本?”
//g是从初始节点到当前节点的实际移动距离。
//h是从当前到目标距离的启发式估计。
停止=错误;
start.g=start.dontgo=0;
//calcHeuristic在数组中插入一个.h成员
calcHeuristicDistance(开始);
//用一个元素开始堆栈
var closed=[];//已计算的节点集。
var open=[start];//要计算的节点集(从初始节点开始)
var迭代=函数(){
if(open.length==0){
//没有更多节点。失败。
回调(空);
返回;
}
var current=open.shift();//获取最高优先级节点
//使用浏览器的表格表示形式更新浏览器
//正在评估的节点
$(“#解决方案”).html(stateToString(当前));
//如果当前==目标,则检查解决方案返回true
if(检查解决方案(当前、目标)){
//重建路径只记录孔的位置
//通过每个节点
var路径=重建路径(开始,当前);
回调(路径);
返回;
}
关闭。推送(电流);
//获取邻居集。这是3个或更少的节点。
//(nextStates经过优化,不会直接打开自身)
var邻居=下一个状态(当前、目标);
(弗吉尼亚州)
check this
import javax.swing.*; 
import java.awt.*;
import java.awt.event.*;
import java.lang.Object;

class Puzzle extends JPanel implements ActionListener
{
    JButton[] b = new JButton[16];
    Puzzle()
    {
        b[0] = new JButton("4");
        b[1] = new JButton("11");
        b[2] = new JButton("5");
        b[3] = new JButton("9");
        b[4] = new JButton("1");
        b[5] = new JButton("10");
        b[6] = new JButton("12");
        b[7] = new JButton("13");
        b[8] = new JButton("15");
        b[9] = new JButton("14");
        b[10] = new JButton("3");
        b[11] = new JButton("2"); 
        b[12] = new JButton("7");
        b[13] = new JButton("8");
        b[14] = new JButton("6");
        b[15] = new JButton("");
        GridLayout grid = new GridLayout(4,4);
        setLayout(grid);
        for(int i=0;i<16;i++)
            add(b[i]);
        for(int i=0;i<16;i++)
            b[i].addActionListener(this);
    }
    public void actionPerformed(ActionEvent e)
    {
        /*if(e.getSource()==b[11])
        {
            if(b[15].getText()=="")
            {
                b[15].setText("");
            }
        }
        else if(e.getSource()==b[3])
        {
            if(b[2].getText()=="")
            {
                b[2].setText("");
            }
        }*/
        for(int i=0;i<16;i++)
        {
            System.out.println(e.getSource());
            if(e.getSource()==b[i])
            {
                if(i==5 || i==6 || i==9 || i==10)
                {   
                    if(b[i-1].getText()=="")
                    {
                        b[i-1].setText(b[i].getText());
                        b[i].setText("");
                    }
                    else if(b[i+1].getText()=="")
                    {
                        b[i+1].setText(b[i].getText());
                        b[i].setText("");
                    }
                    else if(b[i-4].getText()=="")
                    {
                        b[i-4].setText(b[i].getText());
                        b[i].setText("");
                    }
                    else if(b[i+4].getText()=="")
                    {
                        b[i+4].setText(b[i].getText());
                        b[i].setText("");
                    }
                }
                else if(i==4 || i==8)
                {   
                    if(b[i+1].getText()=="")
                    {
                        b[i+1].setText(b[i].getText());
                        b[i].setText("");
                    }
                    else if(b[i-4].getText()=="")
                    {
                        b[i-4].setText(b[i].getText());
                        b[i].setText("");
                    }
                    else if(b[i+4].getText()=="")
                    {
                        b[i+4].setText(b[i].getText());
                        b[i].setText("");
                    }
                }
                else if(i==7 || i==11)
                {   
                    if(b[i-1].getText()=="")
                    {
                        b[i-1].setText(b[i].getText());
                        b[i].setText("");
                    }
                    else if(b[i-4].getText()=="")
                    {
                        b[i-4].setText(b[i].getText());
                        b[i].setText("");
                    }
                    else if(b[i+4].getText()=="")
                    {
                        b[i+4].setText(b[i].getText());
                        b[i].setText("");
                    }
                }
                if(i==0)
                {   
                    if(b[i+1].getText()=="")
                    {
                        b[i+1].setText(b[i].getText());
                        b[i].setText("");
                    }
                    else if(b[i+4].getText()=="")
                    {
                        b[i+4].setText(b[i].getText());
                        b[i].setText("");
                    }
                }
                if(i==3)
                {   
                    if(b[i-1].getText()=="")
                    {
                        b[i-1].setText(b[i].getText());
                        b[i].setText("");
                    }
                    else if(b[i+4].getText()=="")
                    {
                        b[i+4].setText(b[i].getText());
                        b[i].setText("");
                    }
                }
                if(i==15)
                {   
                    if(b[i-1].getText()=="")
                    {
                        b[i-1].setText(b[i].getText());
                        b[i].setText("");
                    }
                    else if(b[i-4].getText()=="")
                    {
                        b[i-4].setText(b[i].getText());
                        b[i].setText("");
                    }
                    else if(b[i+4].getText()=="")
                    {
                        b[i+4].setText(b[i].getText());
                        b[i].setText("");
                    }
                }
                if(i==12)
                {   
                    if(b[i+1].getText()=="")
                    {
                        b[i+1].setText(b[i].getText());
                        b[i].setText("");
                    }
                    else if(b[i-4].getText()=="")
                    {
                        b[i-4].setText(b[i].getText());
                        b[i].setText("");
                    }
                }
                if(i==1 || i==2)
                {   
                    if(b[i+1].getText()=="")
                    {
                        b[i+1].setText(b[i].getText());
                        b[i].setText("");
                    }
                    else if(b[i-1].getText()=="")
                    {
                        b[i-1].setText(b[i].getText());
                        b[i].setText("");
                    }                   
                    else if(b[i+4].getText()=="")
                    {
                        b[i+4].setText(b[i].getText());
                        b[i].setText("");
                    }
                }
                if(i==13 || i==14)
                {   
                    if(b[i+1].getText()=="")
                    {
                        b[i+1].setText(b[i].getText());
                        b[i].setText("");
                    }
                    else if(b[i-1].getText()=="")
                    {
                        b[i-1].setText(b[i].getText());
                        b[i].setText("");
                    }                   
                    else if(b[i-4].getText()=="")
                    {
                        b[i-4].setText(b[i].getText());
                        b[i].setText("");
                    }
                }
            }
        }
        //System.out.println(e.getActionCommand());
        }

    public static void main(String[] args)
    {
        JFrame frame = new JFrame("15-Puzzle");             

        //frame.setContentPane(panel);

JComponent newContentPane = new Puzzle();
        //newContentPane.setOpaque(true); //content panes must be opaque
        frame.setContentPane(newContentPane);





        //panel.add(button);  
        frame.setSize(400,400);


        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}