canvas——随机生成迷宫

本文介绍了一种使用普里姆算法生成可通行迷宫的方法。通过确保迷宫中的每个点都能相互连接,实现了迷宫的完全连通性。文章详细解释了算法流程,并提供了具体的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先上图。

效果

代码

随机生成迷宫要求任意两点都能够找到相同的路径,也就是说,迷宫是一个连通图。随机生成迷宫可以使用普里姆算法、广度优先算法、深度优先算法等实现。这里将使用普里姆算法通过生成最小数的方法,实现迷宫图。

初始迷宫

迷宫有路和墙,白色表示路,黑色表示墙。每一个格子代表一个顶点,这里一共有100个顶点,需要找出99条边,使顶点连接起来,也就是要打通99块墙。

迷宫使用二位数组保存,为迷宫指定路的行数和列数,生成初始数组。

普利姆算法不了解的话,可以参考这篇博客的解析。

 
  
/*
* this.r 路的行数
* this.c 路的列数
* this.arr 保存迷宫的二维数组
*/
initArray() {
    for(let i = 0; i < 2 * this.r + 1; ++i) {
        this.arr[i] = [];
        for(let n = 0; n < 2 * this.c + 1; ++n) {
            if((n ^ (n - 1)) === 1 && (i ^ (i - 1)) === 1) {
                this.arr[i][n] = 0;                   // 0 表示路
                this.notAccessed.push(0);
            }else {
                this.arr[i][n] = 1;                   // 1 表示墙
            }
        }
    }
}

 

生成迷宫

 这里需要使用两个数组,分别保存已访问和未访问的顶点。

this.accessed = [];
this.notAccessed = [...];

(1)初始状态下,notAccessed包含所有顶点,状态为0表示未访问,accessed为空。

(2)随机从notAccessed中抽取一个顶点cur,放入accessed中,cur在notAccessed中的状态改为1,表示已访问。

(3)忽略墙,遍历cur上下左右的顶点。若其中一顶点没有超出边界,且未访问过的,则将顶点加入accessed中,修改notAccessed中的状态,cur指向该顶点.

(4)循环步骤3,直到accessed.length等于顶点数。generate() {

    let count = this.r * this.c;
    let cur = MathUtil.randomInt(0, count);
    let offs = [-this.c, this.c, -1, 1],         // 四周顶点在notAccessed的偏移量
offr
= [-1, 1, 0, 0], // 四周顶点在arr的纵向偏移量 offc = [0, 0, -1, 1]; // 四周顶点在arr的横向偏移量 this.accessed.push(cur); this.notAccessed[cur] = 1; while(this.accessed.length < count) { let tr = Math.floor(cur / this.c), tc = cur % this.c; let num = 0, off = -1;
// 遍历上下左右顶点
while(++num < 5) { let around = MathUtil.randomInt(0, 4), nr = tr + offr[around], nc = tc + offc[around]; if(nr >= 0 && nc >= 0 && nr < this.r && nc < this.c && this.notAccessed[cur + offs[around]] === 0) { off = around; break; } } // 四周顶点均被访问,则从已访问的顶点中随机抽取一个为cur if(off < 0) { cur = this.accessed[MathUtil.randomInt(0, this.accessed.length)]; }else { tr = 2 * tr + 1; tc = 2 * tc + 1; this.arr[tr + offr[off]][tc + offc[off]] = 0; cur = cur + offs[off]; this.notAccessed[cur] = 1; this.accessed.push(cur); } } }

渲染

最后,利用canvas,根据this.arr中的值,就可以生成迷宫啦。

好像少了入口和出口,直接将this.arr中这两个位置的值改成0就好了。

迷宫生成之后,可以对指定两个点生成路径哦。

转载于:https://www.cnblogs.com/xxhuan/p/6947651.html

生成迷宫的常见算法是深度优先搜索(DFS)和广度优先搜索(BFS)。以下是使用DFS算法生成迷宫的JavaFX实现: 1. 创建一个二维数组,表示迷宫的格子。每个格子有四个方向,可以表示为上、下、左、右。 ``` int[][] maze = new int[width][height]; // width和height是迷宫的宽度和高度 ``` 2. 定义一个DFS方法,用于递归生成迷宫。在方法中,随机选择一个未访问的相邻格子,并将其标记为已访问。 ``` private void DFS(int x, int y) { maze[x][y] = VISITED; List<int[]> neighbors = getUnvisitedNeighbors(x, y); // 获取未访问的相邻格子 while (!neighbors.isEmpty()) { int[] neighbor = neighbors.remove(random.nextInt(neighbors.size())); // 随机选择一个相邻格子 int nx = neighbor[0], ny = neighbor[1]; if (maze[nx][ny] == UNVISITED) { removeWall(x, y, nx, ny); // 移除两个格子之间的墙壁 DFS(nx, ny); // 递归访问相邻格子 } } } ``` 3. 定义一个方法,用于获取未访问的相邻格子。 ``` private List<int[]> getUnvisitedNeighbors(int x, int y) { List<int[]> neighbors = new ArrayList<>(); if (x > 0 && maze[x - 1][y] == UNVISITED) { neighbors.add(new int[]{x - 1, y}); // 上方格子 } if (x < width - 1 && maze[x + 1][y] == UNVISITED) { neighbors.add(new int[]{x + 1, y}); // 下方格子 } if (y > 0 && maze[x][y - 1] == UNVISITED) { neighbors.add(new int[]{x, y - 1}); // 左方格子 } if (y < height - 1 && maze[x][y + 1] == UNVISITED) { neighbors.add(new int[]{x, y + 1}); // 右方格子 } return neighbors; } ``` 4. 定义一个方法,用于移除两个格子之间的墙壁。假设每个格子的大小为cellSize,可以通过画线来表示墙壁。 ``` private void removeWall(int x1, int y1, int x2, int y2) { if (x1 == x2) { int y = y1 < y2 ? y1 : y2; gc.clearRect(x1 * cellSize, y * cellSize + wallSize, cellSize, wallSize); } else if (y1 == y2) { int x = x1 < x2 ? x1 : x2; gc.clearRect(x * cellSize + wallSize, y1 * cellSize, wallSize, cellSize); } } ``` 5. 在JavaFX的Application类中,创建一个Canvas和GraphicsContext对象,用于绘制迷宫。然后调用DFS方法生成迷宫。 ``` public void start(Stage primaryStage) { Canvas canvas = new Canvas(width * cellSize + wallSize, height * cellSize + wallSize); gc = canvas.getGraphicsContext2D(); gc.setFill(Color.WHITE); gc.fillRect(0, 0, canvas.getWidth(), canvas.getHeight()); gc.setStroke(Color.BLACK); gc.setLineWidth(wallSize); for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { gc.strokeRect(i * cellSize + wallSize / 2, j * cellSize + wallSize / 2, cellSize, cellSize); } } DFS(0, 0); // 从左上角开始生成迷宫 primaryStage.setScene(new Scene(new StackPane(canvas))); primaryStage.show(); } ``` 完整的代码如下:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值