软件编程
位置:首页>> 软件编程>> java编程>> 如何利用JAVA实现走迷宫程序

如何利用JAVA实现走迷宫程序

作者:愚笨难解  发布时间:2022-06-23 10:52:06 

标签:java,走迷宫,游戏

本Demo使用三个类

一个Test类

一个自定义的Stack类

一个自定义的Queue类

可以实现的功能:

1.对于一个写在文本文件中的迷宫,能够将其转换为二维数组用广度优先搜索实现查找最短路径

2.可以不定义迷宫的入口和出口,能自动查找到出入口

前提是要有一个对应路径的.txt文件

这里举个例子吧,我的是"F:/1号迷宫(0,18).txt"路径下

如何利用JAVA实现走迷宫程序

运行结果

如何利用JAVA实现走迷宫程序

示例代码

注释写的很详细,这里就不多赘述了


package com;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;

/**迷宫测试
* 1号迷宫(0,18).txt
*2号迷宫(0,1).txt
*/
public class Test {
   public static void main(String[] args) throws Exception {
       Test test = new Test();
       //通过文件输入流得到二维数组
       char[][] arr = test.getFile("F:/1号迷宫(0,18).txt");
       System.out.println("二维数组的长度为:"+arr[0].length);
       int deep = test.getDeepByChar(arr);
       System.out.println("二维数组的深度为:"+deep);

//找到入口位置
       int [] begin = test.begin(arr);
       System.out.println("入口位置:("+begin[0]+","+begin[1]+")");
       //找到出口位置
       int [] end = test.end(arr,deep);
       System.out.println("出口位置:("+end[0]+","+end[1]+")");
       System.out.println("=================================打印二维数组============================================");
       //打印二维数组
       test.printArr(arr,deep);
       System.out.println("=================================最短路径图展示===========================================");
       //求最短路径图
       int[][] bfs = test.bfs(arr,begin,end,deep);
       for (int i = 0; i < deep; i++) {
           for (int j = 0; j < bfs[0].length; j++) {
               System.out.print(bfs[i][j]+"\t");
           }
           System.out.println();
       }
       System.out.println("================================最短路径===============================================");
       //根据最短路径图得到最短路径
       int[][] result = test.getLoaderFromMap(bfs, begin, end, deep);
       //得到result的深度
       int deep1 = test.getDeepByInt(result);
       for (int i = 0; i < deep1; i++) {
           System.out.println("("+result[i][0]+","+result[i][1]+")\t");
       }
   }

//求最短路径图
   public int[][] bfs(char [][] arr, int [] begin, int [] end,int deep) {
       //移动的四个方向
       int[] dx = {1, 0, -1, 0};
       int[] dy = {0, 1, 0, -1};
       //d二维数组用来表示路径图
       int[][] d = new int [deep][arr[0].length];
       //储存未进行处理的节点,这里LinkedList实现了Deque,Deque又继承了Queue
       Queue1<int[]> que = new Queue1<>();
//        Queue<int []> que = new LinkedList<>();
       //将所有的位置都初始化为最大
       for(int i = 0; i < d.length; i++) {
           for(int j = 0; j < d[0].length; j++) {
               d[i][j] = -1;
           }
       }
       //将起始点放入队列
       que.offer(begin);
       //将起始点最短路径设为0
       d[begin[0]][begin[1]] = 0;
       //一直循环直到队列为空
       while(!que.isEmpty()) {
           //取出队列中最前端的点
           int [] current = que.poll();
           //如果是终点则结束
           if(current[0] == end[0] && current[1] == end[1]){
               break;
           }
           //四个方向循环
           for(int i = 0; i < 4; i++) {
               //试探
               int nx = current[0] + dx[i];
               int ny = current[1] + dy[i];
               //判断是否可以走
               if(nx >= 0 && nx < deep && ny >= 0 && ny < d[0].length  && arr[nx][ny] == '0' && d[nx][ny] == -1) {
                   //如果可以走,则将该点的距离加1
                   d[nx][ny] = d[current[0]][current[1]] + 1;
                   //并将该点放入队列等待下次处理
                   int[] c = {nx, ny};
                   que.offer(c);
               }
           }
       }
       return d;
   }

//根据最短路径图得到最短路径
   private int [][] getLoaderFromMap(int [][] map,int [] begin,int [] end,int deep) {
       int k = 0;//标志位
       //创建二维数组最终正序存储结果
       int[][] resultList = new int[map.length * map.length][2];
       //result数组存储每个正确位置的下标
       int[] result;
       //创建一个栈,从出口开始把位置压入栈,之后再遍历栈就是正的迷宫顺序
       Stack1<int[]> stack = new Stack1<>();
       //先把出口压入栈
       stack.push(end);
       //移动的四个方向
       int[] dx = {1, 0, -1, 0};
       int[] dy = {0, 1, 0, -1};
       //已知出口和入口,从出口逆推入口
       //只要出口没有和入口下标重合,就一直循环
       while(true){
           //获得栈中最顶层元素,不取出
           int[] current = stack.peek();
           for (int i = 0; i < 4; i++) {
               //试探
               int nx = current[0] + dx[i];
               int ny = current[1] + dy[i];
               //如果当前节点不是入口节点,就继续向前追溯
               if(map[current[0]][current[1]] != map[begin[0]][begin[1]]){
                   //判断是否可以走
                   if (nx >= 0 && nx < deep && ny >= 0 && ny < map[0].length && map[nx][ny] != -1) {
                       //从后往前追溯,前一个数值一定比后一个小1
                       if(map[nx][ny] == map[current[0]][current[1]]-1){
                           //如果可以走,将此节点入栈
                           result = new int[]{nx, ny};
                           stack.push(result);
                       }
                   }
               }else{
                   k++;
                   break;
               }
           }
           //k是为了打破最外层循环,在比较map[current[0]][current[1]] != map[begin[0]][begin[1]]时
           //如果当前节点等于入口时,就应该打破循环,但是while和for是两重循环,所以加一个标志位再打破一次
           if(k != 0){
               break;
           }
       }

//取出栈中元素赋给resultList
       int len = stack.length();
       for(int i = 0;i < len;i++){
           result = stack.pop();
           resultList[i][0] = result[0];
           resultList[i][1] = result[1];
       }
       return resultList;
   }

//把文件中的二进制转换为二维数组
   private char[][] getFile (String pathName) throws Exception {
       File file = new File(pathName);
       //文件不存在时抛出异常
       if (!file.exists())
           throw new RuntimeException("Not File!");
       //字符缓冲输入流//缓冲流是处理流,要先new一个字符输入流
       BufferedReader br = new BufferedReader(new FileReader(file));
       //字符串str用来存储一行数据
       String str;
       //初始化一个二维数组
       char[][] arr = new char[110][];
       //x用来记录读取的行数
       int x = 0;
       while ((str = br.readLine()) != null) {
           x++;
           //把字符串变成字符数组存储
           char[] cArr = str.toCharArray();
           //把一行字符数组加入到二维数组中
           arr[x - 1] = cArr;
       }
       br.close();
       return arr;
   }

//找到入口位置
   private int[] begin ( char[][] arr){
       //存储起点的下标begin[0]=x,begin[1]=y
       int[] begin = new int[2];
       //用StringBuffer把数组转为字符串,方便找到其中的元素
       StringBuffer s = new StringBuffer();
       for (int i = 0; i < arr[0].length; i++) {
           s.append(arr[0][i]);
       }
       //如果入口在第一行
       //判断下标是否存在
       if (s.indexOf("0") != -1) {
           begin[0] = 0;
           begin[1] = s.indexOf("0");
           return begin;
       } else {
           //如果入口在第一列
           for (int i = 0; i < arr.length; i++) {
               if (arr[i][0] == '0') {
                   begin[0] = i;
                   begin[1] = 0;
                   return begin;
               }
           }
       }
       return begin;
   }

//找到出口位置
   private int[] end ( char[][] arr, int deep){
       //存储出口的下标end[0]=x,end[1]=y
       int[] end = new int[2];
       //出口在最后一列上     //18是第二个表的深度
       for (int i = 0; i < deep; i++) {
           //最后一列上找到出口
           if (arr[i][arr[0].length - 1] == '0') {
               end[0] = i;
               end[1] = arr[0].length - 1;
               return end;
           }
       }
       //出口在最后一行上
       for (int i = 0; i < arr.length; i++) {
           //最后一行上找到出口    //deep为最后一行的下标
           if (arr[deep - 1][i] == '0') {
               end[0] = deep - 1;
               end[1] = i;
               return end;
           }
       }
       return end;
   }

/**
    * 由于二维数组刚创建时的默认行数为110,但是实际存储不到110,在对二维数组进行遍历得到实际有效深度时
    * 就会抛出数组下标越界异常,发生越界异常可认为到达二维数组的深度边缘,此时的深度就是有效深度
    * 将异常捕获,返回此时深度就可以得到二维数组的有效深度
    */
   //得到二维数组有效深度
   private int getDeepByChar ( char[][] arr){
       int y = 0;//深度
       for (int i = 0; i < arr.length; i++) {
           //由于i可能越界,当i越界时就认为到达最底部,返回当前y值
           try {
               //如果第一列那行数据不为1或0,就认为此行无效
               if (arr[i][0] != '1' && arr[i][0] != '0') {
                   break;
               }
           } catch (Exception e) {
               return y;
           }
           y++;
       }
       return y;
   }

//得到二维整形数组有效深度
   private int getDeepByInt ( int[][] arr){
       int y = 0;//深度
       for (int i = 0; i < arr.length; i++) {
           //如果遇到(0,0)的,认为已经失效
           if (arr[i][0] == 0 && arr[i][1] == 0) {
               break;
           }
           y++;
       }
       return y;
   }

//打印二维数组
   private void printArr ( char[][] arr, int deep){
       for (int i = 0; i < arr[0].length; i++) {
           for (int j = 0; j < deep; j++) {
               try {
                   System.out.print(arr[i][j] + "\t");
               } catch (Exception e) {
               }
           }
           System.out.println();
       }
   }
}

/**
* 队列
* @param <E>
*/
class Queue1<E> {
   private E[] arr;//使用数组表示一个队列
   private int size;//size表示队列中有效元素个数
   private int putIndex=-1;//putIndex表示从队列中放数的索引始终从队首取,并且取得索引始终为arr[0]

//有参构造
   protected Queue1(int initSize){
       if(initSize < 0){
           throw new IllegalArgumentException("参数错误");
       }
       arr = (E[])new Object[initSize];
       size = 0;
   }
   //无参构造,默认10个长度大小
   protected Queue1(){
       this(110);
   }

//入队
   protected void offer(E e){
       if(size == arr.length) {
           throw new ArrayIndexOutOfBoundsException("无法进行push操作,队列已满");
       }
       arr[++putIndex] = e;
       size++;
   }

//判断队列是否为空
   protected boolean isEmpty(){
       return size == 0?true:false;
   }

//出队
   protected E poll() {
       if (size == 0) {
           throw new ArrayIndexOutOfBoundsException("This queue is empty!当前队列为空");
       }
       E tmp = arr[0];
       //后面的元素向前移动
       for (int i = 0; i < size - 1; i++) {
           arr[i] = arr[i + 1];
       }
       arr[size - 1] = null;
       putIndex--;
       size--;
       return tmp;
   }
}

/**
* 栈
* @param <E>
*/
class Stack1<E> {
   private int maxSize;//最大长度
   private int top = -1;//栈顶指针,初始指向-1
   private E[] data;//数组代替栈存放元素

//初始化栈大小
   protected Stack1(int maxSize){
       if(maxSize > 0){
           this.maxSize = maxSize;
           //data数组对象也要初始化大小
           data = (E[])new Object[maxSize];
       }else{
           throw new IllegalArgumentException("初始化栈大小失败,参数不合法");
       }
   }

//默认初始化大小为10
   protected Stack1(){
       //调用有参构造,传入10
       this(10);
   }

//入栈
   protected boolean push(E e){
       //先判断栈是否已满
       if(top == maxSize-1){
           //扩容
           this.resize();
       }
       //先top++,再top = e
       data [++top] = e;
       return true;
   }

//判断栈是否为空
   protected boolean isEmpty(){
       return top == -1;
   }

//得到栈的长度
   protected int length(){
       return top+1;
   }
   //出栈
   protected E pop(){
       //先判断栈是否为空
       if(top == -1){
           throw new IllegalArgumentException("栈当前为空");
       }
       else{
           E e = data[top];
           //先top = null,再top--
           data[top--] = null;
           return  e;
       }
   }

//查看栈顶元素
   protected E peek(){
       //先判断栈是否为空
       if(top == -1){
           throw new IllegalArgumentException("栈当前为空");
       }else{
           return data[top];
       }
   }

//栈扩容,默认扩容为原来的一倍
   protected void resize(){
       int newSize = maxSize*2;
       E[] newData = (E[])new Object[newSize];
       for (int i = 0;i < data.length;i ++){
           newData[i] = data[i];
       }
       //刷新最大长度
       maxSize = newSize;
       //再把newData赋值给data数组
       data = newData;
   }
}

总结

来源:https://blog.csdn.net/suo_jia_hao/article/details/118253958

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com