8 puzzle 4 ways to solve with java

example: from
2 | 3 |    |
1 | 8 | 5 |
7 | 4 | 6 |
to
1 | 2 | 3 |
8 |    | 4 |
7 | 6 | 5 |

public class EightHuanfang {
	/**
	 * 输入中0表示该位置无小卡片
	 * @param Zing
	 */
	public static void main(String[] Zing) {
		int[][] input = { {2,3,0},{1,8,5},{7,4,6}};
		int[][] result = { {1,2,3},{8,0,4},{7,6,5}};
		BreadthFirst(input,result);
		DepthFirst(input,result);
		HillClimbing(input,result);
		BestFirstSearch(input,result);
		}
	/**
	 * 广度优先搜索
	 * 1队列实现,先放入根节点,
	 * 2看队首符不符合,符合就结束
	 * 3把根节点的叶子放进去,扔掉队首
	 * 4返回2
	 * 搜索成功返回true,否则返回false
	 * @return
	 */
	public static boolean BreadthFirst(int[][] input,int[][] result) {
		boolean ending = false;//ending=false:无解,ending=true:可解
		long startTime=System.currentTimeMillis();   //获取开始时间
		
		int[][] input0 = new int[3][3];
		input0 = shuzufuzhi(input);
		int[][] result0 = new int[3][3];
		result0 = shuzufuzhi(result);
		/**List里面可以装数组!!!
		 * int[][]数组也是对象!!!
		 */
		ArrayList<int[][]> list= new ArrayList<>();//队列
		/**下面这个visit很关键!!!不然就死循环了
		 */
		ArrayList<int[][]> visit= new ArrayList<>();//存储访问过的节点!!!
		list.add(input0);
		visit.add(input0);
		for(int i = 0;;i ++) {
			if(list.size() == 0) {//队列中没有元素,搜索失败
				ending = false;
				break;
			}
			if(0 == qifahanshu(list.get(0),result0)) {//成功搜索到元素
				ending = true;
				break;
			}else {
				ArrayList<int[][]> temp = new ArrayList<>();
				temp= move(shuzufuzhi(list.get(0)));
				list.remove(0);
				for(int j = 0;j < temp.size();j ++) {
					if(!visittest(visit,temp.get(j))) {
						list.add(temp.get(j));
						visit.add(temp.get(j));
					}
				}
			}
		}
		if(ending == false) {
			System.out.println("不可达");
		}else {
			System.out.println("可达");
		}
		long endTime=System.currentTimeMillis(); //获取结束时间
		System.out.println("Breadth-First: "+(endTime-startTime)+"ms ");
		return ending;
	}
	/**
	 * 深度优先搜索
	 * 1.首先将根节点放入队列中。
2.从队列中取出第一个节点,并检验它是否为目标。
如果找到目标,则结束搜寻并回传结果。
否则将它某一个尚未检验过的直接子节点加入队列中。
3.重复步骤2。
4.如果不存在未检测过的直接子节点。
将上一级节点加入队列中。
重复步骤2。
5.重复步骤4。
6.若队列为空,表示整张图都检查过了——亦即图中没有欲搜寻的目标。结束搜寻并回传“找不到目标”。
	 * @param input
	 * @param result
	 * @return
	 */
    public static boolean DepthFirst(int[][] input,int[][] result) {
    	boolean ending = false;
        long startTime=System.currentTimeMillis();   //获取开始时间
		
		int[][] input0 = new int[3][3];
		input0 = shuzufuzhi(input);
		int[][] result0 = new int[3][3];
		result0 = shuzufuzhi(result);
		ArrayList<int[][]> visit= new ArrayList<>();//存储访问过的节点
		node zuzong = new node(null,shuzufuzhi(input0));//别忘了在根节点上面添加一个无用节点!
		node root = new node(zuzong,shuzufuzhi(input0));
		ArrayList<node> nodes= new ArrayList<>();//深搜中的队列
		nodes.add(root);
		for(int i = 0;;i ++) {
			if(nodes.size() == 0) {
				ending = false;
				break;
			}
			
			if(nodes.get(0) == null) {
				ending = false;
				break;
			}
			
			node tempnode = nodes.get(0);//队列的头节点是tempnode
			nodes.remove(0);
			
			if(0 == qifahanshu(tempnode.getdata(),result0)) {
				ending = true;
				break;
			}
			
			if(tempnode.visit == false) {//该节点没有被访问过的情形
				
				tempnode.visit = true;
				
				if(tempnode.create == false) {//向节点中添加生成的叶子节点
					ArrayList<int[][]> temp = new ArrayList<>();
					temp= move(shuzufuzhi(tempnode.getdata()));//temp中装着tempnode生成的节点
					for(int k = 0;k < temp.size();k ++) {
						if(visittest(visit,temp.get(k)) == false) {
							visit.add(shuzufuzhi(temp.get(k)));
							node child = new node(tempnode,shuzufuzhi(temp.get(k)));
							tempnode.addchild(child);
						}
					}
					tempnode.create = true;
				}
				if(tempnode.getchildren().size() == 0) {
					
					nodes.add(tempnode.getparent());//没孩子就添加父母
				}else {
					nodes.add(tempnode.getchildren().get(0));//有孩子就添加最左边的孩子
				}
				
			}else {//该节点被访问过的情形
				for(int j = 0;j < tempnode.getchildren().size();j ++) {
					if(tempnode.getchildren().get(j).visit == false) {//还有孩子没被访问
						nodes.add(tempnode.getchildren().get(j));
						break;
					}
					if(j == tempnode.getchildren().size() - 1) {
						nodes.add(tempnode.getparent());
					}
				}
			}
				
		}
    	
		long endTime=System.currentTimeMillis(); //获取结束时间
		System.out.println("DepthFirst: "+(endTime-startTime)+"ms ");		
    	return ending;
    	}
    /**
     * 爬山法,把启发测度有大到小压人堆栈
     * @param input
     * @param result
     * @return
     */
    public static boolean HillClimbing(int[][] input,int[][] result) {
    	boolean ending = false;//ending=false:无解,ending=true:可解
		long startTime=System.currentTimeMillis();   //获取开始时间
		
		int[][] input0 = new int[3][3];
		input0 = shuzufuzhi(input);
		int[][] result0 = new int[3][3];
		result0 = shuzufuzhi(result);
		/**List里面可以装数组!!!
		 * int[][]数组也是对象!!!
		 */
		ArrayList<int[][]> list= new ArrayList<>();//栈,list的最后边是栈顶
		/**下面这个visit很关键!!!不然就死循环了
		 */
		ArrayList<int[][]> visit= new ArrayList<>();//存储访问过的节点!!!
		list.add(input0);
		visit.add(input0);
		for(int i = 0;;i ++) {
			if(list.size() == 0) {//队列中没有元素,搜索失败
				ending = false;
				break;
			}
			if(0 == qifahanshu(list.get(list.size() - 1),result0)) {//成功搜索到元素
				ending = true;
				break;
			}else {
				ArrayList<int[][]> temp = new ArrayList<>();
				temp= move(shuzufuzhi(list.get(list.size() - 1)));
				list.remove(list.size() - 1);
				ArrayList<int[][]> sort = new ArrayList<>();//用于按照启发测度排序
				for(int j = 0;j < temp.size();j ++) {
					if(!visittest(visit,temp.get(j))) {
						sort.add(temp.get(j));
						visit.add(temp.get(j));
					}
				}
				sort(sort,result0);
				for(int j = 0;j < sort.size();j ++) {
					list.add(sort.get(sort.size() - 1 - j));
				}
			}
		}
		long endTime=System.currentTimeMillis(); //获取结束时间
		System.out.println("HillClimbing: "+(endTime-startTime)+"ms ");
		return ending;
		
	}
    /**
     * 弄个堆,每次去取启发函数数值最小的
     * @param input
     * @param result
     * @return
     */
    public static boolean BestFirstSearch(int[][] input,int[][] result) {
		boolean ending = false;
		long startTime=System.currentTimeMillis(); 
    	int[][] input0 = shuzufuzhi(input);
    	int[][] result0 = shuzufuzhi(result);
		
		ArrayList<int[][]> list = new ArrayList<>();//堆
		ArrayList<Integer> intlist = new ArrayList<>();//和list对应的存储权值的arraylist
		ArrayList<int[][]> visit = new ArrayList<>();
		list.add(shuzufuzhi(input0));
		intlist.add(qifahanshu(list.get(0),result0));
		visit.add(shuzufuzhi(input0));
		for(int i = 0;;i ++) {
			
			if(list.size() == 0) {
				ending = false;
				break;
			}
			
			int minindex = 0;
			int min = 999999;
			for(int h = 0;h < intlist.size();h ++) {
				if((int)intlist.get(h) < min) {
					minindex = h;
					min = intlist.get(h);
				}
			}
			if((int)intlist.get(minindex) == 0) {
				ending = true;
				break;
			}
			ArrayList<int[][]> temp = new ArrayList<>();
			temp= move(shuzufuzhi(list.get(minindex)));
			list.remove(minindex);
			intlist.remove(minindex);
			for(int j = 0;j < temp.size();j ++) {
				if(!visittest(visit,temp.get(j))) {
					list.add(temp.get(j));
					intlist.add(qifahanshu(temp.get(j),result0));
					visit.add(temp.get(j));
				}
			}
			
			
			
		}
		 
		
    	long endTime=System.currentTimeMillis(); //获取结束时间
		System.out.println("BestFirstSearch: "+(endTime-startTime)+"ms ");
		return ending;
	}
    /**
     * 为防止数组赋值中的同地址引用而创建的新建对象数组复制方式
     * @param input
     * @return
     */
    public static int[][] shuzufuzhi(int[][] input){
    	int[][] ending = new int[3][3];
    	for(int i = 0;i < 3;i ++) {
    		for(int j = 0;j < 3;j ++) {
    			ending[i][j] = input[i][j];
    		}
    	}
    	return ending;
    }
    /**
     * 启发函数
     * 用于计算input和result的数组之间有多少个数字在对应位置上不一样
     * @param input
     * @param result
     * @return
     */
    public static int qifahanshu(int[][] input,int[][] result){
    	int ending = 0;
    	for(int i = 0;i < 3;i ++) {
    		for(int j = 0;j < 3;j ++) {
    			if(input[i][j] != result[i][j]) {
    				ending = ending + 1;
    			}
    		}
    	}
    	return ending;
    }
    /**
     * 把输入的数组进行一次操作,即把非0元素移到0的位置
     * 返回一个ArrayList中装着两个/多个新的数组
     * @param input
     * @return
     */
    public static ArrayList<int[][]> move(int[][] input){
    	int[][] input0 = new int[3][3];
    	ArrayList<int[][]> ending = new ArrayList<>();
    	int i0 = 0;//输入数组中0元素的横坐标
    	int j0 = 0;//输入数组中0元素的纵坐标
    	input0 = shuzufuzhi(input);
    	for(int i = 0;i < 3;i ++) {
    		for(int j = 0;j < 3;j ++) {
    			if(input0[i][j] == 0) {
    				i0 = i;
    				j0 = j;
    				break;
    			}
    		}
    	}
    	
    	if((j0 == 1)&&(i0 == 1)) {//0在中间的时候
    		int[][] temp = new int[3][3];
    		temp= shuzufuzhi(input0);
    		temp[1][1] = temp[0][1];
    		temp[0][1] = 0;
    		ending.add(temp);
    		temp= shuzufuzhi(input0);
    		temp[1][1] = temp[1][0];
    		temp[1][0] = 0;
    		ending.add(temp);
    		temp= shuzufuzhi(input0);
    		temp[1][1] = temp[1][2];
    		temp[1][2] = 0;
    		ending.add(temp);
    		temp= shuzufuzhi(input0);
    		temp[1][1] = temp[2][1];
    		temp[2][1] = 0;
    		ending.add(temp);
    	}else {
    		if(i0 == 1) {//当0位于中间行(除中心点)时
    			int[][] temp = new int[3][3];
        		temp= shuzufuzhi(input0);
        		temp[1][j0] = temp[0][j0];
        		temp[0][j0] = 0;
        		ending.add(temp);
        		temp= shuzufuzhi(input0);
        		temp[1][j0] = temp[2][j0];
        		temp[2][j0] = 0;
        		ending.add(temp);
        		if(j0 == 0) {//(1,0)
        			temp= shuzufuzhi(input0);
            		temp[1][0] = temp[1][1];
            		temp[1][1] = 0;
            		ending.add(temp);
        		}else {//(1,2)
        			temp= shuzufuzhi(input0);
            		temp[1][2] = temp[1][1];
            		temp[1][1] = 0;
            		ending.add(temp);
        		}
    		}else {
    			if(j0 == 1) {//当0位于中间列(除中心点)时
    				int[][] temp = new int[3][3];
            		temp= shuzufuzhi(input0);
            		temp[i0][1] = temp[i0][0];
            		temp[i0][0] = 0;
            		ending.add(temp);
            		temp= shuzufuzhi(input0);
            		temp[i0][1] = temp[i0][2];
            		temp[i0][2] = 0;
            		ending.add(temp);
            		if(i0 == 0) {//(0,1)
            			temp= shuzufuzhi(input0);
                		temp[0][1] = temp[1][1];
                		temp[1][1] = 0;
                		ending.add(temp);
            		}else {//(2,1)
            			temp= shuzufuzhi(input0);
                		temp[2][1] = temp[1][1];
                		temp[1][1] = 0;
                		ending.add(temp);
            		}
    			}else {
    				if((i0 == 0)&&(j0 == 0)) {//0在(0,0)
    					int[][] temp = new int[3][3];
                		temp= shuzufuzhi(input0);
                		temp[0][0] = temp[0][1];
                		temp[0][1] = 0;
                		ending.add(temp);
                		temp= shuzufuzhi(input0);
                		temp[0][0] = temp[1][0];
                		temp[1][0] = 0;
                		ending.add(temp);
    				}else {
    					if((i0 == 0)&&(j0 == 2)) {//0在(0,2)
    						int[][] temp = new int[3][3];
                    		temp= shuzufuzhi(input0);
                    		temp[0][2] = temp[0][1];
                    		temp[0][1] = 0;
                    		ending.add(temp);
                    		temp= shuzufuzhi(input0);
                    		temp[0][2] = temp[1][2];
                    		temp[1][2] = 0;
                    		ending.add(temp);
    					}else {
    						if((i0 == 2)&&(j0 == 0)) {//0在(2,0)
    							int[][] temp = new int[3][3];
                        		temp= shuzufuzhi(input0);
                        		temp[2][0] = temp[1][0];
                        		temp[1][0] = 0;
                        		ending.add(temp);
                        		temp= shuzufuzhi(input0);
                        		temp[2][0] = temp[2][1];
                        		temp[2][1] = 0;
                        		ending.add(temp);
    						}else {//0在(2,2)
    							int[][] temp = new int[3][3];
                        		temp= shuzufuzhi(input0);
                        		temp[2][2] = temp[1][2];
                        		temp[1][2] = 0;
                        		ending.add(temp);
                        		temp= shuzufuzhi(input0);
                        		temp[2][2] = temp[2][1];
                        		temp[2][1] = 0;
                        		ending.add(temp);
    						}
    					}
    				}
    			}
    		}
    	}
    	return ending;
    }
    /**
     * 选择排序
     * 按照启发测度从小大大排序
     * @param arr
     */
    public static void sort(ArrayList<int[][]> list,int[][] result) {
    	int[] arr = new int[list.size()];
    	for(int i = 0;i < list.size();i ++) {
    		arr[i] = qifahanshu(list.get(i),result);
    	}
        for (int x = 0; x < arr.length - 1; x++) {
            for (int y = x + 1; y < arr.length; y++) {
                if (arr[x] > arr[y]) {
                    int temp = arr[x];
                    int[][] temp0 = list.get(x);
                    arr[x] = arr[y];
                    list.add(x, list.get(y));
                    list.remove(x + 1);
                    arr[y] = temp;
                    list.remove(y);
                    list.add(y,temp0);
                }
            }
        }
    }
    /**
     * 基于内容判断,而非地址
     * 用来判断某元素是否在list中
     * true表示数组在list中
     * false表示富足不再list中
     * @param input
     * @return
     */
    public static boolean visittest(ArrayList<int[][]> input,int[][] shuzu) {
    	boolean ending = false;
    	int[][] temp = new int[3][3];
    	for(int i = 0;i < input.size();i ++) {
    		temp = input.get(i);
    		if(qifahanshu(temp,shuzu) == 0) {
    			ending = true;
    			break;
    		}
    	}
    	return ending;
    }
    /**
     * 测试中用于输出数组
     * @param input
     */
    public static void showtest(int[][] input) {
    	int[][] input0 = new int[3][3];
    	input0 = shuzufuzhi(input);
    	for(int i = 0;i < 3;i ++) {
    		for(int j = 0;j < 3;j ++) {
    			System.out.print(input0[i][j] + ",");
    		}
    		System.out.println("");
    	}
    	System.out.println("");
    }
}
/**
 * 树上的节点
 * @author ZingsGF
 *
 */
class node{
	private node parrent = null;
	private ArrayList<node> children = new ArrayList<>();
	private int[][] data = new int[3][3];
	public boolean visit = false;//该节点是否被访问过
	public boolean create = false;//该节点是否生成过子节点
	node(node parrent,int[][] data) {
		this.parrent = parrent;
		this.data = data;
	}
	public ArrayList<node> getchildren() {
		return this.children;
	}
	public void addchild(node child) {
		children.add(child);
	}
	public int[][] getdata() {
		return data;
	}
	public node getparent(){
		return this.parrent;
	}
}
Written on October 7, 2019