questions regarding the use of A* with the 15-square puzzle

泄露秘密 提交于 2019-12-03 05:25:28

An A-star search will find the optimal solution by proving that all paths that have not yet been solved are incapable of being solved with fewer moves than the current solution. You aren't looking for the best solution, but the fastest solution. Therefore, you can optimize your algorithm by returning the first solution, by weighting the number of moves lower than your heuristic function, and the heuristic can return an over-estimate.

The heuristic function itself is typically best modeled by the Manhattan distance and linear conflict. Manhattan distance is well explained in other answers and in the Wikipedia article, and you seem to have a handle on it. Linear conflict adds two to the manhattan distance for each pair of blocks that would have to be swapped to reach a solution. For example, if a row contains "3 2 1 4", then the one and the three have to be swapped, and one would have to be moved to another row to do so.

Using a pattern database is an option and could help your search avoid certain dead-ends, and the memory usage of doing so for a 15-puzzle should be manageable.

Use IDA* instead of A*. You need much less memory. As a heuristics, the "Walking distance" developed by Ken'ichiro Takahashi is much more effective, though using only 25 kB of memory.
Here and here is English translation.

Yes, that's how I've heard of this problem being done. g(x) is the number of tile slides that have taken place, and h(x) is the total distance that all tiles are from their required squares. I hadn't seen anything used but this approach (the Manhattan heuristic) before today, but just found this so-called diagonal shortcut -- you might want to check it out.

What are you using for test data? If it's random, you will not be able to solve the puzzle about half the time. It is not possible to switch two tiles while keeping the rest in the same position, and so if you reach what is almost the end position but has two tiles interchanged, you can't possibly get it into the desired position, and no search algorithm can possibly terminate successfully.

In the 19th Century, American puzzlemaster Sam Loyd sold these toys with the 15 and 14 reversed, and offered a big prize for anybody who could demonstrate a solution switching the tiles (presumably other than the one I've got, a small screwdriver). In today's legal climate, I don't know if he'd have dared.

One possibility would be to try to get it into either the correct configuration or the 15-14 configuration.

What I learned

  • apparently this is well-known, but it wasn't to me: the A* convergence is very sensitive to the heuristic function.
  • if I write a heuristic that weights the top 2 rows more heavily than other rows, it converges much more quickly, but the path is generally much longer.
  • I found the diagonal H(x) function shown here to converge much more quickly than the Manhattan distance, for the 15-square puzzle.
  • even with the heuristic function that encourages speedier convergence, there is wide variance in the run time. Sometimes it finds the path in 10 seconds. Sometimes 10 minutes. Sometimes longer.
  • The number of moves required in the paths found, using the diagonal heuristic, ranges from 30-ish to 110.
ragnarius

I have programmed such an algorithm once (windowsApp) and I have the following experience

1) it is most fun to see the robot in action if it uses an (near) optimal solution. (For the human observer it is impossible to understand how the robot "thinks" and the transaction from chaos to order is sudden)

2) if you like to find the optimal solution your h() function must underestimate true distance. If you overestimate it you will not find the optimum.

3) The potential state-space is huge, 15!/2 (10^12). If you use a bad heuristic function your data sets will grow far beyond the size of your main-memory and every data access will require multiple disc-accesses. If this happens the execution time will be "infinite".

Maybe it will converge quicker if you shoot for intermediate goals first. For instance, only score the top and right rows. It shouldn't take very long to get those rows in place, then you can solve the remaining 3x3.

swapnil Fulmali
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);
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!