【人工智能实验一】A*算法解决八数码难题

参考文章:

【精选】人工智能 A*算法 八数码 Java_人工智能八数码问题java_硝酸童不酸的博客-CSDN博客

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Scanner;

public class EightNum implements Comparable {
    int[] number = new int[9];
    int f;//估计函数
    int d;//实际代价,走到当前状态的步数
    int h;//估计代价,当前状态和目标状态有多少个数不同
    EightNum parent;//记录当前状态的父状态
    ArrayList result = new ArrayList<>();//保存最终路径

    //目标状态的可达性判断,通过判断两个状态的逆序数是否相同来判断
    //注意:需要排除0
    public boolean isSolvable(EightNum target) {
        int num = 0;
        for (int i=1; i<9; i++)
            for (int j=0; jnumber[i] && number[j]!=0 && number[i]!=0)
                    num++;
                if (target.number[j]>target.number[i] && target.number[j]!=0 && number[i]!=0)
                    num++;
            }
        //如果能被2整除,说明同奇或者同偶
        return num % 2==0;
    }

    //对状态进行初始化,计算估价函数
    public void init(EightNum target) {
        int sum=0;
        for (int i=0; i<9; i++)
            if (number[i]!=target.number[i])
                sum++; //记录当前状态和目标状态不同的个数
        this.h = sum;

        if(this.parent==null) //如果没有父状态
            this.d=0;
        else
            this.d=this.parent.d+1;//实际代价

        this.f=this.d+this.h;//返回当前状态的估计值
    }

    public boolean isTarget(EightNum target) {
        //判断当前状态是否是目标状态
        return Arrays.equals(number, target.number);
    }

    //重写compareTo
    @Override
    public int compareTo(Object o) {
        EightNum e = (EightNum) o;
        return this.f - e.f;
    }

    //获取0的位置
    public int getZeroPosition()
    {
        int position = -1;
        for (int i=0; i<9; i++)
            if (this.number[i]==0) position = i;

        return position;
    }

    //判断该状态是否在表中,如果在,就返回位置
    public int isContains(ArrayList arrayList) {
        for (int i=0; i 2; //只要位置不是第一行即可 0 1 2
    }
    //判断能否下移
    public boolean isMoveDown()
    {
        int position = getZeroPosition();
        return position < 6; //只要位置不是最后一行即可 7 8 9
    }
    //判断能否左移
    public boolean isMoveLeft()
    {
        int position = getZeroPosition();
        return (position) % 3 != 0; //只要位置不是第一列即可
                                    //0 4 7
    }
    //判断能否右移
    public boolean isMoveRight()
    {
        int position = getZeroPosition();
        return (position) % 3 != 2; //只要位置不是最后一列即可
                                    //2 5 8
    }
    //——————————————————判断移动————————————————————————————

    //实现移动
    public EightNum moveUp(int move)
    {
        EightNum newState = new EightNum();//创建一个对象
        newState.number = number.clone();//将当前状态赋值给新创建的对象
        int zero = getZeroPosition();//记录0的位置
        int position = 0;//记录移动后的位置
        switch (move)
        {
            case 0://上移
                position = zero - 3;
                break;
            case 1://下移
                position = zero + 3;
                break;
            case 2://左移
                position = zero - 1;
                break;
            case 3://右移
                position = zero + 1;
                break;
        }
        newState.number[zero] = number[position];
        newState.number[position] = 0;
        return newState;
    }

    //输出
    public void output()
    {
        for (int i=0; i<9; i++)
            if(i%3==2) System.out.println(this.number[i]);
            else System.out.print(this.number[i]+" ");
    }

    //输出最终路径
    public void printRoute() {
        EightNum temp;
        int count = -1;
        temp = this;
        System.out.println("————————最优方案步骤展示————————");
        //放到result表中,方便输出
        while(temp!=null)
        {
            result.add(temp);
            temp = temp.parent;  //从子状态逐步向上寻找父状态
            count++;
        }
        //因为list里,子状态放在最前面,为了从父状态开始输出,因此从后向前输出
        for (int i=result.size()-1; i>=0; i--)
        {
            System.out.println("第"+ (count-i) +"步:");
            result.get(i).output();
        }
        System.out.println("最小移动步数:" + count);
    }

    public void operation(ArrayList open, ArrayList close, EightNum minF, EightNum target) {
        if (this.isContains(close)==-1) //判断是否在close表
        {
            int position = this.isContains(open);//判断是否在open表,存在就返回其在open表中的位置
            if (position==-1) //不在open表中
            {
                this.parent = minF;//链接,设置minF为该子状态的父状态
                this.init(target);//计算估计函数
                open.add(this);//放入open表
            }
            else //在open表中
            {
                if (this.d < open.get(position).d) //根据移动步数,小的覆盖大的
                {
                    open.remove(position);
                    this.parent = minF;
                    this.init(target);
                    open.add(this);
                }
            }
        }
    }

    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        //————————————————————————————初始化————————————————————————————
        ArrayList open = new ArrayList<>(); //open表存放已经生成而未考察的节点
        ArrayList close = new ArrayList<>(); //close表存放已经访问过的节点
        EightNum start = new EightNum();//存放初始状态
        EightNum target = new EightNum();//存放目标状态
        int[] sNum = new int[9];//初始状态
        int[] tNum = new int[9];//目标状态
        System.out.println("请输入初始棋盘!(空处输入0)");
        for(int i=0;i<9;i++) sNum[i]=sc.nextInt();
        System.out.println("请输入目标棋盘!(空处输入0)");
        for(int i=0;i<9;i++) tNum[i]=sc.nextInt();
        start.number = sNum;
        target.number = tNum;
        System.out.println("初始状态:");
        start.output();
        System.out.println("目标状态:");
        target.output();
        //————————————————————————————初始化————————————————————————————

        if(start.isSolvable(target)) //判断从初始状态到目标状态是否可达
        {
            start.init(target);//初始化,计算估价函数
            open.add(start);//加入open表

            while(!open.isEmpty()) //循环导出open表中的状态
            {
                Collections.sort(open); //根据f值对open表进行从小到大排序

                EightNum minF = open.get(0); //取出最小的,也就是第0个
                open.remove(0); //从open表移出
                close.add(minF); //放入close表

                //f最小的状态如果==目标状态 则输出
                if(minF.isTarget(target)) //判断是否为目标状态
                {
                    minF.printRoute(); //输出完整路径
                    break;
                }

                int move;
                //由minF状态进行扩展并加入到open表
                //0的位置上移之后的状态不在close和open中设定minF为父状态,并初始化f的估值函数
                if(minF.isMoveUp())
                {
                    move = 0;
                    EightNum up = minF.moveUp(move);
                    up.operation(open,close,minF,target);
                }
                //0的位置下移之后状态不在close和open中设定minF为其父状态,并初始化f(n)估值函数
                if (minF.isMoveDown())
                {
                    move = 1;
                    EightNum down = minF.moveUp(move);
                    down.operation(open, close, minF, target);
                }
                //0的位置左移之后状态不在close和open中设定minF为其父状态,并初始化f(n)估值函数
                if (minF.isMoveLeft())
                {
                    move = 2;
                    EightNum left = minF.moveUp(move);
                    left.operation(open, close, minF, target);
                }
                //0的位置右移之后状态不在close和open中设定minF为其父状态,并初始化f(n)估值函数
                if (minF.isMoveRight())
                {
                    move = 3;
                    EightNum right = minF.moveUp(move);
                    right.operation(open, close, minF, target);
                }
            }
        }
        else
            System.out.println("目标状态不可达!");
    }
}


你可能感兴趣的:(人工智能实验,算法,java,开发语言,八数码,启发式搜索)