随机迷宫小游戏

随机迷宫生成

随机Prim方法

package com.company;

import java.util.Random;

class Maze {
    // 初始化一个地图 默认所有路不通
    //最终产生的二维数组大小实际为(2width+1) * (2height+1)
    private static int width;
    private static int height;
    public static int[][] map;// 存放迷宫的数组
    private static int r;
    private static int c;

    Maze(int r0, int c0) {
        width = r0;
        height = c0;
        r = 2 * width + 1;
        c = 2 * height + 1;
        map = new int[r][c];
    }

    public static int[][] Init() {
        for (int i = 0; i < r; i++) // 将所有格子都设为墙
            for (int j = 0; j < c; j++)
                map[i][j] = 0;// 0 为墙 1为路
        // 中间格子放为1
        for (int i = 0; i < width; i++)
            for (int j = 0; j < height; j++)
                map[2 * i + 1][2 * j + 1] = 1;// 0 为墙 1为路
        // 普里姆算法
        rdPrime();
        return map;
    }

    public static void rdPrime() {
        // ok存放已访问队列,not存放没有访问队列
        int[] ok, not;
        int sum = width * height;
        int count = 0;// 记录访问过点的数量
        ok = new int[sum];
        not = new int[sum];
        // width上各方向的偏移 height各方向的偏移 0左 1右 3上 2下
        int[] offR = {-1, 1, 0, 0};
        int[] offC = {0, 0, 1, -1};

        // 四个方向的偏移 左右上下
        int[] offS = {-1, 1, width, -width}; // 向上向下移动都是变化一行
        // 初始化 ok中0代表未访问,not中0代表未访问
        for (int i = 0; i < sum; i++) {
            ok[i] =0;
            not[i] = 0;
        }
        // 起点
        Random rd = new Random();
        ok[0] = rd.nextInt(sum);// 起始点
        int pos = ok[0];
        // 第一个点存入
        not[pos] = 1;
        while (count < sum) {
            // 取出现在的点
            int x = pos % width;
            int y = pos / width;// 该点的坐标
            int offpos = -1;
            int w = 0;
            // 四个方向都尝试一遍 直到挖通为止
            while (++w < 5) {
                // 随机访问最近的点
                int point = rd.nextInt(4); // 0-3
                int repos;
                int move_x, move_y;
                // 计算出移动方位
                repos = pos + offS[point];// 移动后的下标
                move_x = x + offR[point];// 移动后的方位
                move_y = y + offC[point];
                if (move_y >= 0 && move_x >= 0 && move_x < width && move_y < height && repos >= 0 && repos < sum
                        && not[repos] != 1) {
                    not[repos] = 1;// 把该点标记为已访问
                    ok[++count] = repos;// ++count代表第几个已经访问的点,repos代表该点的下标
                    pos = repos;// 把该点作为起点
                    offpos = point;
                    // 相邻的格子中间的位置放1
                    map[2 * x + 1 + offR[point]][2 * y + 1 + offC[point]] = 1;
                    break;
                } else {
                    if (count == sum - 1)
                        return;
                }
            }
            if (offpos < 0) {// 周边没有找到能走的路了 从走过的路里重新找个起点
                pos = ok[rd.nextInt(count + 1)];
            }
        }
    }

}

A*算法

package com.company;

import java.util.ArrayList;
import java.util.List;

class AStar {
    public static int[][] NODES;//定义一个迷宫单元数组
    public  int STEP = 10;//设每一步的权值为10
    private ArrayList<Node> openList = new ArrayList<Node>();//维护一个开放列表
    private ArrayList<Node> closeList = new ArrayList<Node>();//维护一个关闭列表

    AStar(int[][] map) {
        NODES=map;//初始化迷宫单元为新生成的对应地图,把Maze类里面生成的地图传给NODES,再在此地图基础上用A*算法寻路径
        Node startNode = new Node(1, 1);//起点
        Node endNode = new Node(map.length-2, map.length-2);//终点
        Node parent = findPath(startNode, endNode); //父节点
        ArrayList<Node> arrayList = new ArrayList<Node>();
        while (parent != null) {

            arrayList.add(new Node(parent.x, parent.y));
            parent = parent.parent;
        }

        //打印有路径的地图,在控制台输出查看
        System.out.println("\n"+"打印有路径的地图:");
        for (int i = 0; i < NODES.length; i++) {
            for (int j = 0; j < NODES.length; j++) {
                if (exists(arrayList, i, j)) {
                    NODES[i][j]=2;//标记关闭列表里的方格为2,为了方便后面在界面画系统寻路路径
                }
                //System.out.print(NODES[i][j] + " ");
            }
            //System.out.println();
        }
    }
    public static int[][] ans(){
        return NODES;
    }
    //寻找开放列表里F值最小的节点的方法
    public Node findMinFNodeInOpneList() {
        Node tempNode = openList.get(0);
        for (Node node : openList) {
            if (node.F < tempNode.F) {
                tempNode = node;
            }
        }
        return tempNode;
    }

    //遍历当前节点上下左右四个邻居的方法,
    public ArrayList<Node> findNeighborNodes(Node currentNode) {
        ArrayList<Node> arrayList = new ArrayList<Node>();
        // 只考虑上下左右,不考虑斜对角
        int topX = currentNode.x;
        int topY = currentNode.y - 1;
        if (canReach(topX, topY) && !exists(closeList, topX, topY)) {
            arrayList.add(new Node(topX, topY));
        }
        int bottomX = currentNode.x;
        int bottomY = currentNode.y + 1;
        if (canReach(bottomX, bottomY) && !exists(closeList, bottomX, bottomY)) {
            arrayList.add(new Node(bottomX, bottomY));
        }
        int leftX = currentNode.x - 1;
        int leftY = currentNode.y;
        if (canReach(leftX, leftY) && !exists(closeList, leftX, leftY)) {
            arrayList.add(new Node(leftX, leftY));
        }
        int rightX = currentNode.x + 1;
        int rightY = currentNode.y;
        if (canReach(rightX, rightY) && !exists(closeList, rightX, rightY)) {
            arrayList.add(new Node(rightX, rightY));
        }
        return arrayList;
    }

    //判断此处坐标是否可达,若超界或者是墙则不可达
    public boolean canReach(int x, int y) {
        if (x >=0 && x < NODES.length && y >=0 && y < NODES.length && NODES[x][y]==1) {
            return true;
        }
        return false;
    }

    //A*寻路过程
    public Node findPath(Node startNode, Node endNode) {
        openList.add(startNode);// 把起点加入 open list
        while (openList.size() > 0) {
            Node currentNode = findMinFNodeInOpneList();// 遍历 open list ,查找 F值最小的节点,把它作为当前要处理的节点
            openList.remove(currentNode);// 从open list中移除
            closeList.add(currentNode);// 把这个节点移到 close list
            ArrayList<Node> neighborNodes = findNeighborNodes(currentNode);
            for (Node node : neighborNodes) {//遍历四个邻居
                if (exists(openList, node)) {
                    foundPoint(currentNode, node);
                } else {
                    notFoundPoint(currentNode, endNode, node);
                }
            }
            if (find(openList, endNode) != null) {
                return find(openList, endNode);//找到终点了并返回
            }
        }
        return find(openList, endNode);
    }

    //在列表里可以找到节点后的情况
    private void foundPoint(Node tempStart, Node node) {
        int G = calcG(tempStart, node);
        if (G < node.G) {
            node.parent = tempStart;
            node.G = G;
            node.calcF();
        }
    }

    //在节点里找不到节点的情况
    private void notFoundPoint(Node tempStart, Node end, Node node) {
        node.parent = tempStart;
        node.G = calcG(tempStart, node);
        node.H = calcH(end, node);
        node.calcF();
        openList.add(node);
    }


    //计算G值的方法
    private int calcG(Node start, Node node) {
        int G = STEP;
        int parentG = node.parent != null ? node.parent.G : 0;
        return G + parentG;
    }

    //计算H值的方法
    private int calcH(Node end, Node node) {
        int step = Math.abs(node.x - end.x) + Math.abs(node.y - end.y);
        return step * STEP;
    }

    //找到终点的方法
    public static Node find(List<Node> nodes, Node point) {
        for (Node n : nodes)
            if ((n.x == point.x) && (n.y == point.y)) {
                return n;
            }
        return null;
    }

    //下面两个是exist方法的重载,判断不同参数情况时节点是否在列表里
    public static boolean exists(List<Node> nodes, Node node) {
        for (Node n : nodes) {
            if ((n.x == node.x) && (n.y == node.y)) {
                return true;
            }
        }
        return false;
    }

    public static boolean exists(List<Node> nodes, int x, int y) {
        for (Node n : nodes) {
            if ((n.x == x) && (n.y == y)) {
                return true;
            }
        }
        return false;
    }

    //节点类,定义了每一个节点的属性
    public static class Node {
        public Node(int x, int y) {
            this.x = x;
            this.y = y;
        }
        public int x;
        public int y;
        public int F;
        public int G;
        public int H;

        public void calcF() {
            this.F = this.G + this.H;
        }
        public Node parent;
    }
}

MazePanel类

package com.company;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

class MazePanel extends JPanel implements KeyListener,ActionListener {
    public final static int WALL = 0;//障碍物
    public final static int ROAD = 1;//通路
    public static int width; //地图规模
    public static int height;
    public final static int current = 2; //标识当前位置图例
    public final static int MAXSTEPS = 200; //游戏的最大步数
    static int mx = 1; //当前位置(curX,curY)
    static int my = 1;
    static int score = 0; //游戏得分及步数
    static int steps = 0; // 步数
    static int level = 3;//难度
    static int[][] map;  //储存迷宫
    private JButton ans = new JButton("显示路径"); //按键和键盘方式,未实现,直接全用键盘操作了
    private JButton remake = new JButton("重置迷宫");
    private JPanel jp = new JPanel();
    private JButton hide = new JButton("隐藏路径");
    private JButton exit = new JButton("退出游戏");
    private JButton start = new JButton("开始游戏");

    public static int Difficult(int level) {   //游戏难度,初始为10,难度+1,地图+2
        int number = 10;
        for (int i = 0; i < level; i++) {
            number += 2;
        }
        return number;
    }

    public static void MapRandom() {   //随机迷宫
        width = Difficult(level);
        height = Difficult(level);
        com.company.Maze maze = new com.company.Maze(width, height);  //初始化迷宫
        map = com.company.Maze.Init();  //继承迷宫
        map[1][1] = 2; //设置迷宫的入口及出口
        mx = 1;
        my = 1;
        //map[map.length - 2][map.length - 2] = 2;
    }
    //游戏界面初始化和设计
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        this.addKeyListener(this);
        //count = Difficult(level);
        g.setColor(new Color(0,139,139));//添加RGB背景色
        g.fillRect(0, 0, 760, 807);
        //Date.location.paintIcon(this,g,0,50);
        //g.setColor(new Color(224, 238, 238));
        for (int i = 0; i < map.length; i++) {  //填充颜色的方法画出迷宫的wall和load
            for (int j = 0; j < map.length; j++) {
                if(i==map.length-2&&j==map.length-2){
                    g.setColor(Color.RED);
                    g.fillRect(10 * i + 10, 10 * j + 50, 10, 10);
                }else if (map[i][j] == 0) {
                    g.setColor(Color.BLACK);
                    g.fillRect(10 * i + 10, 10 * j + 50, 10, 10);
                } else if (map[i][j] == 1) {
                    g.setColor(Color.GRAY);
                    g.fillRect(10 * i + 10, 10 * j + 50, 10, 10);
                } else if (map[i][j] == 2) {
                    g.setColor(Color.RED);
                    g.fillRect(10 * i + 10, 10 * j + 50, 10, 10);
                }
            }
            g.setColor(new Color(188, 250, 250));
            g.fillRect(0, 0, 1000, 40);
            g.setColor(Color.BLACK);
            g.setFont(new Font("仿宋", Font.BOLD, 20));
            g.drawString("重置游戏(X)", 10, 25);
            g.drawString("寻路(Y)", 150, 25);
            g.drawString("当前步数:" + steps, 250, 25);
            g.drawString("难度:"+level,400,25);
            g.drawString("W:难度+  S:难度-",500,25);
            if (MazePanel.isSuccess()) {
                g.setFont(new Font("宋体", Font.BOLD, 50));
                g.drawString("恭喜通关", 500, 400);
            }
        }
    }
    //将A*算法得出的路径返回给map
    public void ans() {
        com.company.AStar aStart = new com.company.AStar(map);
        map = com.company.AStar.ans();
    }

    public MazePanel() {
        MapRandom();
        this.setFocusable(true);
        this.addKeyListener(this);
    }

    //判断是否走出迷宫
    public static boolean isSuccess() {
        //score += MazePanel.MAXSTEPS - steps;
        return map.length - 2 == mx && map.length - 2 == my;
    }

    @Override
    public void actionPerformed(ActionEvent e) {

    }
    static int i=0;
    @Override
    public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();
        int x = mx, y = my;
        //游戏移动方式和限制,下一步不能为墙且单次监听,不加i=0会产生bug
        if(!isSuccess()&&steps<MAXSTEPS) {
            if (key == KeyEvent.VK_LEFT && map[x - 1][y] != MazePanel.WALL&&i==0) {//左移
                map[x - 1][y] = MazePanel.current;   //更改当前位置到移动到的位置
                map[x][y] = 1;//恢复地图原有的图标
                mx--;i++;     //更改当前位置坐标
                steps++;
            } else if (key == KeyEvent.VK_RIGHT&&map[x + 1][y] != MazePanel.WALL&&i==0) {
                map[x + 1][y] = MazePanel.current;  //右移
                map[x][y] = 1;
                mx++;i++;
                steps++;
            } else if (key == KeyEvent.VK_UP&&map[x][y - 1] != MazePanel.WALL&&i==0) {
                map[x][y - 1] = MazePanel.current;  //上移
                map[x][y] = 1;
                my--;i++;
                steps++;
            } else if (key == KeyEvent.VK_DOWN&&map[x][y + 1] != MazePanel.WALL&&i==0) {
                map[x][y + 1] = 2;   //下移
                map[x][y] = 1;
                my++;i++;
                steps++;
            }else if(key == KeyEvent.VK_Y&&i==0){   //显示路径
                ans();
            }else if(key == KeyEvent.VK_X&&i==0){   //重置迷宫
                MapRandom();
            }
            else if(key==KeyEvent.VK_W&&i==0&&level<13){  //增加迷宫难度
                level++;i++;
                MapRandom();
            }else if(key==KeyEvent.VK_S&&i==0&&level>=3){  //减少迷宫难度
                level--;i++;
                MapRandom();
            }
        }
        repaint();   //刷新游戏界面
    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyReleased(KeyEvent e) {
        i=0;       //键盘监听限制,不加限制会一次移动好几格
    }
}



Main类
package com.company;

import javax.swing.*;

public class Main {

    public static void main(String[] args) {
        JFrame frame = new JFrame();  //生成窗口
        frame.setSize(770,825);   //设置窗口大小
        com.company.MazePanel maze = new com.company.MazePanel();
        frame.add(maze);    //添加游戏面板
        frame.setLocationRelativeTo(null);//显示屏幕中央
        frame.setResizable(false);//固定屏幕
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭指令
        frame.setVisible(true);  //窗口可视化
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,生成迷宫游戏可以使用深度优先搜索(DFS)算法来实现。以下是一个简单的C++实现: ```c++ #include <iostream> #include <stack> #include <vector> #include <random> using namespace std; // 定义迷宫大小 const int ROW = 10; const int COL = 10; // 定义迷宫类 class Maze { public: Maze() : maze_(ROW, vector<int>(COL, 1)) {} // 生成迷宫 void generate() { // 随机数生成器 random_device rd; mt19937 gen(rd()); uniform_int_distribution<> dis(0, 3); // DFS生成迷宫 stack<pair<int, int>> s; s.push(make_pair(0, 0)); while (!s.empty()) { auto p = s.top(); s.pop(); int x = p.first, y = p.second; maze_[x][y] = 0; // 标记为已访问 int dirs[4] = {0, 1, 2, 3}; // 随机打乱方向 for (int i = 0; i < 4; ++i) { int pos = dis(gen) % 4; swap(dirs[i], dirs[pos]); } // 按照打乱后的方向遍历 for (int i = 0; i < 4; ++i) { int dx = 0, dy = 0; if (dirs[i] == 0 && x > 0 && maze_[x-1][y]) { dx = -1; } else if (dirs[i] == 1 && x < ROW-1 && maze_[x+1][y]) { dx = 1; } else if (dirs[i] == 2 && y > 0 && maze_[x][y-1]) { dy = -1; } else if (dirs[i] == 3 && y < COL-1 && maze_[x][y+1]) { dy = 1; } if (dx || dy) { s.push(make_pair(x+dx, y+dy)); } } } // 标记起点和终点 maze_[0][0] = 2; maze_[ROW-1][COL-1] = 3; } // 打印迷宫 void print() const { for (const auto& row : maze_) { for (int cell : row) { if (cell == 0) { cout << " "; } else if (cell == 1) { cout << "██"; } else if (cell == 2) { cout << "口"; } else if (cell == 3) { cout << "出"; } } cout << endl; } } private: vector<vector<int>> maze_; }; int main() { Maze maze; maze.generate(); maze.print(); return 0; } ``` 在这个实现中,我们使用了深度优先搜索算法来生成迷宫,同时使用随机数生成器来打乱方向,使得迷宫更加随机。我们使用一个二维数组来表示迷宫,其中0表示可以通过的通道,1表示墙,2表示起点,3表示终点。在打印迷宫时,我们使用空格表示通道,`██`表示墙,`口`表示起点,`出`表示终点。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值