深度优先搜索--八数码问题(一)(升级版 11数码)

利用深度优先搜索解决八数码问题的进阶版本--十一数码。

十一数码是在12个格子中,存在一个空位及1-11个数字的游戏。

进阶版本不同于八数码上下左右移动的特性,可以向上、下、左、右、左上、左下、右上、右下,一共八个方向移动(不过当然也不能超出边界)。

代码先放出来,之后详细讲解。

import java.util.*;
import java.io.*;

public class miniProject {


    public static void main(String[] args) {

        Scanner scan = new Scanner(System.in);
        String initState = scan.nextLine();
        String goalState = scan.nextLine();

        String currentState;



        //  Deep-First Search
//
        DFS dfSearch = new DFS();
        dfSearch.Init(initState, goalState);
        dfSearch.Search();

        dfSearch.findPath();


    }
}

 

import java.util.*;
import java.io.*;


public class DFS {

    //  思路:
    //  图中存储当前节点及其父节点 用于抵达目标之后计算回溯路径
    //  close数组存储已访问过的节点 需要声明的大一些
    //  图中存储的key值为每个状态+上一步是如何到达此状态的操作符'a'--'l'
    //  代表将『0』移动至位置'*'

    //  数据结构:
    //  Open        栈
    //  Close       数组
    //  Backtrack   图

    private Stack openList = new Stack();
    private Stack closeList = new Stack();
    private HashMap backMap = new HashMap<>();
    private Stack outputList = new Stack<>();
    private Stack outputMoveList = new Stack<>();

    private boolean findGoal = false;
    private boolean canMove = false;

    private String initState;
    private String goalState;
    private String currentState;
    private String childState;

    private String popState;
    private String popModified;

    private int numOfNodes = 0;

    public DFS() {

    }

    public void Init(String initState, String goalState) {
        openList.push(initState);

        this.initState = initState;
        this.goalState = goalState;

        openList.push(initState);

        backMap.put(initState, "0");

    }


    public void Search() {

        //  比较起始节点,如果为目标节点 -->结束 找到目标
        if(initState.equals(goalState)) {
            //  若相同 -->结束 找到目标 跳出循环
            findGoal = true;
            System.out.println("Find the goal state!");
        }


        while (!openList.isEmpty() && !findGoal) {

            //  如果栈为空
            //  失败 -->"搜索因栈为空,失败了" 退出

            //  将栈顶元素(记作结点N)从栈中取出
            currentState = openList.pop();



            //  若相同 跳出循环
            if (currentState.equals(goalState)) {
                //  若相同 -->结束 找到目标 跳出循环
                findGoal = true;
                //System.out.println("Find the goal state!");
                break;
            }

            //  扩展结点N的所有结点,产生其全部的后继结点,并压入栈
            //  应先产生UP-LEFT节点 压入栈!!!!
            //  产生后继结点(检测后继结点是否合法)
            for (int dir = 8; dir>=1; dir--){

                //  尝试生成子节点
                ChildState(dir);

                //  无法移动 直接跳过
                if (!canMove) {
                    continue;
                }

                //  检查后继结点是否存在于Open和Close中, 不存在的话就可以入Open栈
                if (closeList.contains(childState) || openList.contains(childState)){
                    //  存在的话,嘛也不做
                    continue;
                }
                else {
                    openList.push(childState);
                }

                //System.out.println(childState);
                //  存入回溯图
                backMap.put(childState, currentState);


                //  (目前不执行此步骤)如果后继结点中有任一结点为目标结点,则求得解,否则转向步骤Ⅱ。

            }

            numOfNodes++;


            //  子节点生成结束 存入close表
            closeList.push(currentState);


        }

        if (findGoal)
            System.out.println("Find the goal state!");
        else
            System.out.println("Could not find the goal state!");

        if (openList.isEmpty())
            System.out.println("ERROR! Open list is empty!");



    }




    //  寻找状态的后继结点
    public void ChildState(int dir){



        //  用x,y来存储0节点(空方快)的位置
        int x = 0;
        int y = 0;


        //  字符串数组存储当前字符串状态
        char[] currentArray = currentState.toCharArray();

        //  寻找0点
        for (int n = 0; n < 3; n++){
            for (int m = 0; m < 4; m++){
                if(currentState.substring(n * 4 + m, n * 4 + m + 1).equals("0")) {
                    x = n;
                    y = m;

                }
            }
        }

        //  从1-8 从UP->UP-RIGHT->RIGHT->.....->UP-LEFT
        //  00 01 02 03     0 1 2 3
        //  10 11 12 13     4 5 6 7
        //  20 21 22 23     8 9 10 11
        switch (dir){
            case 1:
                if (x == 0)
                    canMove = false;
                else {
                    currentArray[x * 4 + y] = currentArray[x * 4 - 4 + y];
                    currentArray[x * 4 + y - 4] = '0';
                    canMove = true;
                }
                break;
            case 2:
                if (x == 0 || y == 3)
                    canMove = false;
                else {
                    currentArray[x * 4 + y] = currentArray[x * 4 - 3 + y];
                    currentArray[x * 4 + y - 3] = '0';
                    canMove = true;
                }
                break;
            case 3:
                if (y == 3)
                    canMove = false;
                else {
                    currentArray[x * 4 + y] = currentArray[x * 4 + 1 + y];
                    currentArray[x * 4 + y + 1] = '0';
                    canMove = true;
                }
                break;
            case 4:
                if (x == 2 || y == 3)
                    canMove = false;
                else {
                    currentArray[x * 4 + y] = currentArray[x * 4 + 5 + y];
                    currentArray[x * 4 + y + 5] = '0';
                    canMove = true;
                }
                break;
            case 5:
                if (x == 2)
                    canMove = false;
                else {
                    currentArray[x * 4 + y] = currentArray[x * 4 + 4 + y];
                    currentArray[x * 4 + y + 4] = '0';
                    canMove = true;
                }
                break;
            case 6:
                if (x == 2 || y == 0)
                    canMove = false;
                else {
                    currentArray[x * 4 + y] = currentArray[x * 4 + 3 + y];
                    currentArray[x * 4 + y + 3] = '0';
                    canMove = true;
                }
                break;
            case 7:
                if (y == 0)
                    canMove = false;
                else {
                    currentArray[x * 4 + y] = currentArray[x * 4 - 1 + y];
                    currentArray[x * 4 + y - 1] = '0';
                    canMove = true;
                }
                break;
            case 8:
                if (x == 0 || y == 0)
                    canMove = false;
                else {
                    currentArray[x * 4 + y] = currentArray[x * 4 - 5 + y];
                    currentArray[x * 4 + y - 5] = '0';
                    canMove = true;

                }
                break;
        }


        childState = new String(currentArray);


    }

    //  转换输出格式
    public void changePrintType() {
        popModified = "[";

        char[] popArray = popState.toCharArray();
        for (int i = 0; i < popState.length() - 1; i++) {
            popModified = popModified + popArray[i] + ", ";
        }
        popModified = popModified + popArray[popState.length() - 1];

        popModified = popModified + "]";

    }

    public void findPath() {
        //  从最后回溯
        currentState = goalState;

        while(!backMap.get(currentState).equals("0")) {
            //System.out.println(currentState);
            outputList.push(currentState);
            currentState = backMap.get(currentState);

        }

        try {
            File file = new File("/Users/sunny/Documents/miniProject1/DFS.txt");
            PrintStream ps = new PrintStream(new FileOutputStream(file));

        while (!outputList.isEmpty()) {
            popState = outputList.pop();

            //  寻找0点
            for (int n = 0; n < 3; n++){
                for (int m = 0; m < 4; m++){
                    if(popState.substring(n * 4 + m, n * 4 + m + 1).equals("0")) {

                        changePrintType();
                        switch (n * 4 + m + 1) {
                            case 1:
                                ps.println("a " + popModified);
                                break;
                            case 2:
                                ps.println("b " + popModified);
                                break;
                            case 3:
                                ps.println("c " + popModified);
                                break;
                            case 4:
                                ps.println("d " + popModified);
                                break;
                            case 5:
                                ps.println("e " + popModified);
                                break;
                            case 6:
                                ps.println("f " + popModified);
                                break;
                            case 7:
                                ps.println("g " + popModified);
                                break;
                            case 8:
                                ps.println("h " + popModified);
                                break;
                            case 9:
                                ps.println("i " + popModified);
                                break;
                            case 10:
                                ps.println("j " + popModified);
                                break;
                            case 11:
                                ps.println("k " + popModified);
                                break;
                            case 12:
                                ps.println("l " + popModified);
                                break;
                        }
                    }
                }
            }


        }

        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}

 

你可能感兴趣的:(Java,AI)