2021-03-07

一、九宫格对象

内容概述:
将九宫格每次移动后的结果看做一个对象,所以Square对象应该具有以下属性:
1:parent对象,用于存储当前图的上一步图的内容。
2:now_position [3][3],用于存储当前九宫格图中每个格子中的数。
g 表示当前结果对象已经移动的次数。(在状态空间中从初始节点到n节点的实际代价)。
h表示当前对象与目标结果,九宫格中内容不同的格子数。(当前对象的估计代价)
代码如下:

package ce;
public class Square {
public int [][]now_position=new int [3][3];
public  Square up;
public Square down;
public  Square left;
public Square right;
public Square parent;
public int g;//层数
public int h;
public Square(int a[][],Square parent,int h){
   for(int r=0;r<3;r++) {
       for(int r1=0;r1<3;r1++){
           now_position[r][r1]=a[r][r1];
       }
   }
   this.g =h;
   this.parent=parent;
}
public int returnFx(){
    return (h + g);
}
public void setGx(int g){
    this.h =g;
}
}

返回当前状态的F(x)

public int returnFx()

设置当前状态的G(x)

public void setGx(int g)

二、A* 算法的实现

内容概述:

1.A_star_中定义的属性

1:int[][]start_position;定义一个数组用于存储九宫格初始时各个数字的位置
2:int [][]end_position;定义一个数组用于存储九宫格的目标状态
3:List queue;定义一个List集合作为队列,对每一步中的九宫格状态进行存储。
4:List parents;定义一个List集合,存储九宫格已经移动过的步骤,
5:List path;定义一个List集合,存储九宫格从初始状态移动到目标状态时的路径。
6. 调用Judgefeasible()判断当前的九宫格状态是否能达到目标状态。如果不能,就打印输出。

2.A_star算法的内容

内容概述:
1:对当前的九宫格状态假设移动,将移动后合法的九宫格状态加入队列,将队列按代价从小到大排列。选择代价最小的九宫格状态,并让其出队,继续重复模拟九宫格中的格子移动,直到达到目标状态。
2:获得目标状态的结果对象以后,将目标状态往回找父节点,添加到path中。
代码如下:

   public void A_star() {
            Square p = start_Quare;
            queue.add(p);
            while (!is_same(p, end_Quare)) {
                int y= find_minfx(queue);
                p = queue.get(y);
                addSquare(p);
                queue.remove(y);
            }
             q = p;//最后的目标格子位置
            print();
    }

3.模拟九宫格格子移动

内容概述:

1:模拟格子移动的过程中一共有四种情况,分别是向左移动,向上移动,向下移动,向右移动。
2:考虑到四种情况后,分别对四种情况中坐标移动后合法的情况创建对象,修改状态后将其入队。
代码如下:

 public void addSquare(Square df){
        int tmp;
        Square p;
        int [][]a=new int[3][3];
        int [][]b=new int[3][3];
        int [][]c=new int[3][3];
        int [][]d=new int[3][3];
        for(int i=0;i<3;i++) {
            for(int j=0;j<3;j++){
                a[i][j]=df.now_position[i][j];
                b[i][j]=df.now_position[i][j];
                c[i][j]=df.now_position[i][j];
                d[i][j]=df.now_position[i][j];
            }
        }
        int x=0,y=0;
        for(int i=0;i<3;i++) {
            for(int j=0;j<3;j++){
                if(a[i][j]==0)
                {
                    x=i;
                    y=j;//寻找空格的位置
                }
            }
        }
        if ((x - 1) >= 0)//假设左移
        {
            tmp=a[x][y];
            a[x][y]=a[x-1][y];
            a[x-1][y]=tmp;
            p = new Square(a,null,0);
            if (Judge_has_passed(parents,p))
            {
                p.parent=df;
                p.g =df.g +1;
                int count= unsameNum(p,end_Quare);
                p.setGx(count);
                queue.add(p);
                parents.add(p);
            }
        }
        if (x + 1 <= 2)//假设右移
        {
            tmp=b[x][y];
            b[x][y]=b[x+1][y];
            b[x+1][y]=tmp;
            p = new Square(b,null,0);
            if (Judge_has_passed(parents,p))
            {
                p.parent=df;
                p.g =df.g +1;
                int count= unsameNum(p,end_Quare);
                p.setGx(count);
                queue.add(p);
                parents.add(p);
            }
        }
        if (y - 1 >= 0)//假设下移
        {
            tmp=c[x][y];
            c[x][y]=c[x][y-1];
            c[x][y-1]=tmp;
            p = new Square(c,null,0);
            if (Judge_has_passed(parents,p))
            { p.parent=df;
                p.g =df.g +1;
                int count= unsameNum(p,end_Quare);
                p.setGx(count);
                queue.add(p);
                parents.add(p);
            }
        }
        if (y + 1 <= 2)
        {
            tmp=d[x][y];
            d[x][y]=d[x][y+1];
            d[x][y+1]=tmp;
            p = new Square(d,null,0);
            if (Judge_has_passed(parents,p))
            {
                p.parent=df;
                p.g =df.g +1;
                int count= unsameNum(p,end_Quare);
                p.setGx(count);
                queue.add(p);
                parents.add(p);
            }
        }
    }
  

4.实现主要功能的函数

1.计算当前状态与目标状态,九宫格不同格子的数量。

public int unsameNum(Square p, Square q1)

2.判断当前状态是否可以达到目标状态。

 public boolean Judge_feasible(Square start,Square end)

3.挑选价值最小的对象并返回下标

public int find_minfx(List<Square> list)

4.判断两个对象的九宫格中的内容是否相同

public boolean is_same(Square s1,Square s2)

5.展示输出实现九宫格寻路的时的步骤和状态。

public void print()

代码如下:

package ce;
public class Square {
public int [][]now_position=new int [3][3];
public  Square up;
public Square down;
public  Square left;
public Square right;
public Square parent;
public int g;//层数
public int h;
public Square(int a[][],Square parent,int h){
   for(int r=0;r<3;r++) {
       for(int r1=0;r1<3;r1++){
           now_position[r][r1]=a[r][r1];
       }
   }
   this.g =h;
   this.parent=parent;
}
public int returnFx(){
    return (h + g);
}
public void setGx(int g){
    this.h =g;
}
}

package ce;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class A_star_ {
    private int[][]start_position=new int [3][3];
    private int [][]end_position=new int [3][3];
    private List<Square> queue=new ArrayList<>();
    private List<Square> parents=new ArrayList<>();
    private List<Square> path =new ArrayList<>();
    private Square start_Quare;
    private Square end_Quare;
    private long startTime;
    private long endTime;
    private Square q;
    Scanner sc=new Scanner(System.in);
    public A_star_(){
        System.out.println("请输入九宫格的起始状态(空格用0代替):");
        for(int i=0;i<3;i++){
            start_position[i][0]=sc.nextInt();
            start_position[i][1]=sc.nextInt();
            start_position[i][2]=sc.nextInt();
        }
        System.out.println("请输入九宫格的最终状态:");
        for(int i=0;i<3;i++){
            end_position[i][0]=sc.nextInt();
            end_position[i][1]=sc.nextInt();
            end_position[i][2]=sc.nextInt();
        }
          startTime=System.currentTimeMillis();
         start_Quare=new Square(start_position,null,0);
         end_Quare=new Square(end_position,null,0);
        if (Judge_feasible(start_Quare, end_Quare)) {//如果可行
            A_star();
    }else{
            System.out.println("这两个九宫格直接无法通过移动空格实现转换");
        }
    }
    public void A_star() {
            Square p = start_Quare;
            queue.add(p);
            while (!is_same(p, end_Quare)) {
                int y= find_minfx(queue);
                p = queue.get(y);
                addSquare(p);
                queue.remove(y);
            }
             q = p;//最后的目标格子位置
            print();
    }
    public void addSquare(Square df){
        int tmp;
        Square p;
        int [][]a=new int[3][3];
        int [][]b=new int[3][3];
        int [][]c=new int[3][3];
        int [][]d=new int[3][3];
        for(int i=0;i<3;i++) {
            for(int j=0;j<3;j++){
                a[i][j]=df.now_position[i][j];
                b[i][j]=df.now_position[i][j];
                c[i][j]=df.now_position[i][j];
                d[i][j]=df.now_position[i][j];
            }
        }
        int x=0,y=0;
        for(int i=0;i<3;i++) {
            for(int j=0;j<3;j++){
                if(a[i][j]==0)
                {
                    x=i;
                    y=j;//寻找空格的位置
                }
            }
        }
        if ((x - 1) >= 0)//假设左移
        {
            tmp=a[x][y];
            a[x][y]=a[x-1][y];
            a[x-1][y]=tmp;
            p = new Square(a,null,0);
            if (Judge_has_passed(parents,p))
            {
                p.parent=df;
                p.g =df.g +1;
                int count= unsameNum(p,end_Quare);
                p.setGx(count);
                queue.add(p);
                parents.add(p);
            }
        }
        if (x + 1 <= 2)//假设右移
        {
            tmp=b[x][y];
            b[x][y]=b[x+1][y];
            b[x+1][y]=tmp;
            p = new Square(b,null,0);
            if (Judge_has_passed(parents,p))
            {
                p.parent=df;
                p.g =df.g +1;
                int count= unsameNum(p,end_Quare);
                p.setGx(count);
                queue.add(p);
                parents.add(p);
            }
        }
        if (y - 1 >= 0)//假设下移
        {
            tmp=c[x][y];
            c[x][y]=c[x][y-1];
            c[x][y-1]=tmp;
            p = new Square(c,null,0);
            if (Judge_has_passed(parents,p))
            { p.parent=df;
                p.g =df.g +1;
                int count= unsameNum(p,end_Quare);
                p.setGx(count);
                queue.add(p);
                parents.add(p);
            }
        }
        if (y + 1 <= 2)
        {
            tmp=d[x][y];
            d[x][y]=d[x][y+1];
            d[x][y+1]=tmp;
            p = new Square(d,null,0);
            if (Judge_has_passed(parents,p))
            {
                p.parent=df;
                p.g =df.g +1;
                int count= unsameNum(p,end_Quare);
                p.setGx(count);
                queue.add(p);
                parents.add(p);
            }
        }
    }
    public int unsameNum(Square p, Square q1){
        int count=0;
        for (int i = 0; i < 3; i++)
        { for (int j = 0; j < 3; j++)
        { if(p.now_position[i][j]!=q1.now_position[i][j])
        { count++; }
        } }
        return count;
    }
    public boolean Judge_has_passed(List<Square> q,Square s) {
        int f=0;
        boolean flag=false;
        for (Square d : q) {
            for (int a = 0; a < 3; a++) {
                for (int a1 = 0; a1 < 3; a1++) {
                  if(d.now_position[a][a1]!=s.now_position[a][a1]){
                      f++;
                      flag=true;
                      break; } }
            if(flag==true){
                break; }
            }
            flag=false; }
        if(f==q.size()){
           return  true;
        } else{
            return false; }
    }
   public boolean Judge_feasible(Square start,Square end){
       int []b1=new int[9];
       int []b2=new int[9];
       int s11=0;
       int s12=0;
       int n1=0;
       int n2=0;
       for(int i=0;i<3;i++) {
           for(int j=0;j<3;j++){
               b1[n1++]=start.now_position[i][j];
               b2[n2++]=end.now_position[i][j];
           }
       }
       for(int i=0;i<9;i++){
           for(int j=0;j<i;j++){
               if(b1[j]>b1[i]&&b1[j]!=0&&b1[i]!=0)
               { s11++;}
           }
       }
       for(int i=0;i<9;i++){
           for(int j=0;j<i;j++){
               if(b2[j]>b2[i]&&b2[j]!=0&&b2[i]!=0)
                   s12++;
           }
       }
       if(s11%2==s12%2)
           return true;
       else
           return false;
   }
   public int find_minfx(List<Square> list){
     int i=0;
     int h=list.get(0).returnFx();
     for(int i1=0;i1<list.size();i1++){
         if(list.get(i1).returnFx()<h){
             h=list.get(i1).returnFx();
             i=i1;
         }
     }
     return i;
   }


public void print(){
        Square q1=q;
    while (q1 != null) {
        path.add(q1);
        q1 = q1.parent;
    }
    System.out.println("九宫格排列中移动的步骤为:");
    for(int k=path.size()-1;k>=0;k--)
    {
        System.out.println("第"+(path.size()-k-1)+"步为:");
        for(int i=0;i<3;i++) {
            for(int j=0;j<3;j++){
                System.out.print(path.get(k).now_position[i][j]+" ");
            }
            System.out.println();
        }
    }
    endTime=System.currentTimeMillis();
    System.out.println("总程序运行时间: "+(endTime-startTime)/1000.0+"s");

}
public boolean is_same(Square s1,Square s2){
        for(int a1=0;a1<3;a1++){
            for(int a2=0;a2<3;a2++){
                if(s1.now_position[a1][a2]!=s2.now_position[a1][a2]){
                    return false;
                }
            }
        }
        return true;
}
}

package ce;

public class test {
    public static void main(String[] args) {
        A_star_ d11=new A_star_();
    }
}


思路概括

将九宫格每次移动后的状态都看做是一个对象,对九宫格移动步数的处理就转化为了,在多个对象中寻找适合条件的对象输出每一个对象的九宫格状态,对于已走过的九宫格状态可以用父结点进行存储,最后再将所有的父节点取出作为路径即可,在假设九宫格移动的函数中,选取坐标合法的九宫格状态加入队列进行排序,将每个对象按价值由低到高进行排序,就可以找到最小代价的路径了。

运行结果

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值