Bootstrap

Java 迷宫项目

迷宫项目

1.项目介绍

一个网格迷宫由n行m列的单元格组成,每个大院要么是空地(用0表示),要么是障碍物(用1表示)。你的任务是找一条从起点到终点的移动序列,其中只能上下左右移动到相邻单元格。任何时候都不能在有障碍物的单元格中,也不能走到迷宫之外。起点为左上角,终点为右下角。

2.项目功能

解决迷宫路径查找问题,寻找一条从左上角迷宫入口到右下角迷宫出口的一条有效路径,0代表可走,1代表不能行走,找到请输出最终的迷宫和路径信息,找不到请输出不存在有效路径。

3.项目结果演示

在这里插入图片描述

4.项目实现分析

1)迷宫由n行m列的单元格组成。所以要定义一个二维数组。
2)迷宫要设置空地和障碍物,用0表示空地,1表示障碍物,假设迷宫是一个3 × 3的单元格,每个单元格里要放0和1,那么简单的设计成一个整型二维数组可以吗?我们除了在每个单元格中要设置0和1外,还要额外考虑当前单元格的东、南、西、北四个方向是否可以走,以及当前单元格所在的行和列。所以如果只是简单的设计成二维数组是不可以的,因此,我们可以定义一个MazeNode类,东南西北四个方向先设为false(即不可走),在后面中做调整。

public class MazeNode {
    private int value;
    private int xPos;//行下标
    private int yPos;//列下标
    private boolean way_east
    private boolean way_south;
    private boolean way_west;
    private boolean way_north;

    public MazeNode(int value, int xPos, int yPos) {
        this.value = value;
        this.xPos = xPos;
        this.yPos = yPos;
    }
}

3)接下来我们设计一个MazeNode类,在MazeNode类中设计一个MazeNode类型的二维数组。然后给二维数组的每个元素赋初值。

public class Maze {
    private MazeNode[][] mazeNodes;
    private int row;
    private int col;

    public Maze() {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入迷宫行数:");
        this.row = scanner.nextInt();
        System.out.println("请输入迷宫列数:");
        this.col = scanner.nextInt();
        mazeNodes = new MazeNode[row][col];
    }

    private void initValue() { //从键盘输入row行,col列数据,初始化二维数组
        Scanner scanner = new Scanner(System.in);
        System.out.println("请设置迷宫 0 or 1");
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                this.mazeNodes[i][j] = new MazeNode(scanner.nextInt(), i, j);
            }
        }
    }
}

4)假定初始化了一个3×3的二维数组,里面的值如下在这里插入图片描述
现在每个元素的东南西北四个方向都是false,我们要调整每个0元素东南西北四个方向的布尔值,如果该0元素的东南西北任何一个方向是0的话,表示是空地,可以通过,把这个方向的布尔值设为true,表示可以通过。

private void adjustState() {   //调整当前节点的东 南 西 北 四个方向的状态 如果为 0 改为true
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                if (mazeNodes[i][j].getValue() == 1) {
                    continue;
                }

                //mazeNodes[i][j] == 0;// 0 2 row = 2 col = 3
                if ((j + 1 < col) && mazeNodes[i][j + 1].getValue() == 0) {//东
                    mazeNodes[i][j].setWay_east(true);
                }

                if ((i + 1 < row) && mazeNodes[i + 1][j].getValue() == 0) {//南
                    mazeNodes[i][j].setWay_south(true);
                }

                if ((j - 1 >= 0) && mazeNodes[i][j - 1].getValue() == 0) {//西
                    mazeNodes[i][j].setWay_west(true);
                }

                if ((i - 1 >= 0) && mazeNodes[i - 1][j].getValue() == 0) {//北
                    mazeNodes[i][j].setWay_north(true);
                }
            }
        }
}

调整好每个0元素四个方向的布尔值后,要开始走迷宫啦,从左上角开始入迷宫,当然如果左上角第一个元素为1的话就肯定进不去迷宫了,也就走迷宫失败了。当遇到0就开始通过,走的过程中我们要注意,走过来了就不要走老路了,就不要回去了,一直向前,不后退,这就要把当前走到的位置的相反方向设为false,防止回去,比如你往东走到了新的位置,就要把当前位置的西边设为false,这样就不会回去了。如果在走的过程中,发现无路可走了,就要退一步开始寻求新路,这时候就要注意了,当我们退一步后,上一次的路就不能走了,就要把上次走的方向设为false,防止走老路。可是我们已经把回去的路封住了,那么应该怎么退回去呢?
在这里我们可以运用栈的特点来操作。
栈有一个特点就是先进后出,后进先出,我们可以把栈想象成一个瓶子,先进的肯定要后出,后进的肯定要先出了。如图:
在这里插入图片描述
在图示中,进栈的顺序是4 0 2 1,出栈的顺序就是1 0 2 4。同时还要了解出栈操作pop(),入栈操作push(),获得栈顶元素peek()
因此我们可以利用栈的特性来走迷宫,每到达一个位置,把该位置元素入栈;退一步,进行栈顶元素出栈操作,直到栈中元素为空退出循环,不再进行,也就是不存在有效迷宫路径,否则到达右下角元素位置,走迷宫成功。(在maze类中添加实例变量private Stack stack;;构造函数中添加stack = new Stack<>();因为操作的数组是MazeNode类型,在这里用到泛型。)
代码如下:

public void goMaze() {
        initValue();//初始化迷宫 -->从键盘输入
        adjustState();//调整当前节点四个方向的行走状态
        //判断左上角和右下角是否为 0 不为 0 则不能
        if (mazeNodes[0][0].getValue() == 1 || mazeNodes[row - 1][col - 1].getValue() == 1) {
            System.out.println("不存在有效路径");
            return;
        }
        stack.push(mazeNodes[0][0]);//左上角节点入栈
        while (stack.isEmpty() == false) {
            MazeNode top = stack.peek();//获取栈顶元素
            int x_Pos = top.getxPos();//获取当前节点的x坐标
            int y_Pos = top.getyPos();//获取当前节点的y坐标

            //如果当前节点正好是迷宫右下角节点,那么走出迷宫成功
            if (x_Pos == row - 1 && y_Pos == col - 1) {
                System.out.println("走出迷宫成功");
                break;
            }



            if (top.isWay_east()) {//东
                stack.push(mazeNodes[x_Pos][y_Pos + 1]);//把当前节点的东边节点压入栈
                mazeNodes[x_Pos][y_Pos + 1].setWay_west(false);//防止节点往回走
                mazeNodes[x_Pos][y_Pos].setWay_south(false);//防止节点走老路
            } else if (top.isWay_south()) {//南
                stack.push(mazeNodes[x_Pos + 1][y_Pos]);
                mazeNodes[x_Pos + 1][y_Pos].setWay_north(false);
                mazeNodes[x_Pos][y_Pos].setWay_south(false);
            } else if (top.isWay_west()) {//西
                stack.push(mazeNodes[x_Pos][y_Pos - 1]);
                mazeNodes[x_Pos][y_Pos - 1].setWay_east(false);
                mazeNodes[x_Pos][y_Pos].setWay_west(false);
            } else if (top.isWay_north()) {//北
                stack.push(mazeNodes[x_Pos - 1][y_Pos]);
                mazeNodes[x_Pos - 1][y_Pos].setWay_south(false);
                mazeNodes[x_Pos][y_Pos].setWay_south(false);
            } else {//无路可走
                stack.pop();
            }
        }
        show();
}

4)打印函数,如果栈中为空,表示没有迷宫路径;栈不为空,就要把走的迷宫路径标识出来,可以把走过的位置值置为2。获得栈顶元素,把该元素所在值置为2,然后出栈,再获得栈顶元素,把元素的所在值置为2,然后出栈…直到栈为空。遍历二维数组,打印数组。

private void show() {
        if (stack.isEmpty()) {
            System.out.print("没有迷宫路径");
            return;
        }

        while (!stack.isEmpty()) {
            MazeNode top = stack.peek();
            top.setValue(2);
            stack.pop();
        }
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                System.out.print(mazeNodes[i][j].getValue() + " ");
            }
            System.out.println();
        }
}

5.迷宫完整代码

MazeNode类:

package com.wysheng.迷宫;

/**
 * @Author Wang Yongsheng
 * @Date 2021/11/10 8:59
 * @Version 1.0
 */
public class MazeNode {
    private int value;
    private int xPos;//行下标
    private int yPos;//列下标
    private boolean way_east;
    private boolean way_south;
    private boolean way_west;
    private boolean way_north;

    public MazeNode(int value, int xPos, int yPos) {
        this.value = value;
        this.xPos = xPos;
        this.yPos = yPos;
    }

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }


    public void setWay_east(boolean way_east) {
        this.way_east = way_east;
    }

    public void setWay_south(boolean way_south)
    {
        this.way_south = way_south;
    }

    public void setWay_west(boolean way_west) {
        this.way_west = way_west;
    }

    public void setWay_north(boolean way_north) {
        this.way_north = way_north;
    }

    public boolean isWay_east() {
        return way_east;
    }

    public boolean isWay_south() {
        return way_south;
    }

    public boolean isWay_west() {
        return way_west;
    }

    public boolean isWay_north() {
        return way_north;
    }

    public int getxPos() {
        return xPos;
    }

    public int getyPos() {
        return yPos;
    }

}

Maze类:

package com.wysheng.迷宫;

import java.util.Scanner;
import java.util.Stack;

/**
 * @Author Wang Yongsheng
 * @Date 2021/11/10 9:14
 * @Version 1.0
 */
public class Maze {
    private MazeNode[][] mazeNodes;
    private int row;
    private int col;
    private Stack<MazeNode> stack;

    public Maze() {
        stack = new Stack<>();

        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入迷宫行数:");
        this.row = scanner.nextInt();
        System.out.println("请输入迷宫列数:");
        this.col = scanner.nextInt();
        mazeNodes = new MazeNode[row][col];
    }

    private void initValue() { //从键盘输入row行,col列数据,初始化二维数组
        Scanner scanner = new Scanner(System.in);
        System.out.println("请设置迷宫 0 or 1");
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                this.mazeNodes[i][j] = new MazeNode(scanner.nextInt(), i, j);
            }
        }
    }

    //打印迷宫
    private void show() {
        if (stack.isEmpty()) {
            System.out.print("没有迷宫路径");
            return;
        }

        while (!stack.isEmpty()) {
            MazeNode top = stack.peek();
            top.setValue(2);
            stack.pop();
        }
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                System.out.print(mazeNodes[i][j].getValue() + " ");
            }
            System.out.println();
        }
    }

    private void adjustState() {   //调整当前节点的东 南 西 北 四个方向的状态 如果为 0 改为true
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                if (mazeNodes[i][j].getValue() == 1) {
                    continue;
                }

                //mazeNodes[i][j] == 0;// 0 2 row = 2 col = 3
                if ((j + 1 < col) && mazeNodes[i][j + 1].getValue() == 0) {//东
                    mazeNodes[i][j].setWay_east(true);
                }

                if ((i + 1 < row) && mazeNodes[i + 1][j].getValue() == 0) {//南
                    mazeNodes[i][j].setWay_south(true);
                }

                if ((j - 1 >= 0) && mazeNodes[i][j - 1].getValue() == 0) {//西
                    mazeNodes[i][j].setWay_west(true);
                }

                if ((i - 1 >= 0) && mazeNodes[i - 1][j].getValue() == 0) {//北
                    mazeNodes[i][j].setWay_north(true);
                }
            }
        }
    }

    public void goMaze() {
        initValue();//初始化迷宫 -->从键盘输入
        adjustState();//调整当前节点四个方向的行走状态
        //判断左上角和右下角是否为 0 不为 0 则不能
        if (mazeNodes[0][0].getValue() == 1 || mazeNodes[row - 1][col - 1].getValue() == 1) {
            System.out.println("当前迷宫不可走");
            return;
        }
        stack.push(mazeNodes[0][0]);//左上角节点入栈
        while (stack.isEmpty() == false) {
            MazeNode top = stack.peek();//获取栈顶元素
            int x_Pos = top.getxPos();//获取当前节点的x坐标
            int y_Pos = top.getyPos();//获取当前节点的y坐标

            //如果当前节点正好是迷宫右下角节点,那么走出迷宫成功
            if (x_Pos == row - 1 && y_Pos == col - 1) {
                System.out.println("不存在有效路径");
                break;
            }



            if (top.isWay_east()) {//东
                stack.push(mazeNodes[x_Pos][y_Pos + 1]);//把当前节点的东边节点压入栈
                mazeNodes[x_Pos][y_Pos + 1].setWay_west(false);//防止节点往回走
                mazeNodes[x_Pos][y_Pos].setWay_south(false);//防止节点走老路
            } else if (top.isWay_south()) {//南
                stack.push(mazeNodes[x_Pos + 1][y_Pos]);
                mazeNodes[x_Pos + 1][y_Pos].setWay_north(false);
                mazeNodes[x_Pos][y_Pos].setWay_south(false);
            } else if (top.isWay_west()) {//西
                stack.push(mazeNodes[x_Pos][y_Pos - 1]);
                mazeNodes[x_Pos][y_Pos - 1].setWay_east(false);
                mazeNodes[x_Pos][y_Pos].setWay_west(false);
            } else if (top.isWay_north()) {//北
                stack.push(mazeNodes[x_Pos - 1][y_Pos]);
                mazeNodes[x_Pos - 1][y_Pos].setWay_south(false);
                mazeNodes[x_Pos][y_Pos].setWay_south(false);
            } else {//无路可走
                stack.pop();
            }
        }
        show();
    }
}

MazeTest类:

package com.wysheng.迷宫;

/**
 * @Author Wang Yongsheng
 * @Date 2021/11/10 9:24
 * @Version 1.0
 */
public class MazeTest {
    public static void main(String[] args) {
        Maze maze = new Maze();
        maze.goMaze();
    }
}

;