Go Ebiten随机迷宫生成示例

引言
迷宫生成是计算机科学中一个经典的问题,常用于算法教学和游戏开发。本文将介绍如何使用 Go 语言和 Ebiten 游戏引擎实现一个基于深度优先搜索(DFS)的随机迷宫生成算法,并通过可视化的方式展示迷宫的生成过程。
技术栈
- Go 语言:一种高效、简洁的编程语言,适合实现算法和并发任务。
- Ebiten:一个轻量级的 2D 游戏引擎,适合快速开发简单的图形应用程序。
- 深度优先搜索(DFS):一种经典的图遍历算法,用于生成随机迷宫。
算法原理
深度优先搜索(DFS)
DFS 是一种用于遍历或搜索树或图的算法。在迷宫生成中,我们可以将迷宫看作一个图,每个块是一个节点,墙是节点之间的边。DFS 通过随机选择邻居节点并打破墙来生成迷宫。
栈回溯
为了确保迷宫生成的完整性,我们使用栈来记录访问路径。当当前块没有未访问的邻居时,通过栈回溯到上一个未完全探索的块,继续生成迷宫。
代码实现
package mainimport ("image/color""math/rand""os""time""github.com/hajimehoshi/ebiten/v2""github.com/hajimehoshi/ebiten/v2/vector"
)const (N int = 20 // 迷宫的行数和列数BlockSize int = 50 // 每个迷宫块的大小(像素)WindowWidth int = N*BlockSize + 2*int(WW) // 窗口宽度WindowHeight int = N*BlockSize + 2*int(WW) // 窗口高度WW float32 = 2 // 墙的宽度(像素)BS float32 = float32(BlockSize) // 块大小的浮点数表示
)// Pos 结构体表示一个二维坐标
type Pos struct {X, Y int
}// Dirs 数组表示四个可能的移动方向(上、左、右、下)
var Dirs [4]Pos = [4]Pos{Pos{0, -1}, Pos{-1, 0}, Pos{1, 0}, Pos{0, 1}}// Game 结构体表示游戏的状态
type Game struct {T int // 当前已访问的块数P Pos // 当前的位置Walls [N][N][4]bool // 记录每个块的四面墙是否存在IsVis [N][N]bool // 记录每个块是否被访问过Stack []Pos // 栈,用于记录访问路径
}// Update 是 Ebiten 游戏循环中的更新函数,每一帧调用一次
func (g *Game) Update() error {SystemFunction() // 处理系统功能(如退出)if g.T < N*N { // 如果还有未访问的块g.Next() // 生成下一个块}return nil
}// Draw 是 Ebiten 游戏循环中的绘制函数,每一帧调用一次
func (g *Game) Draw(screen *ebiten.Image) {g.DrawWalls(screen) // 绘制迷宫的墙
}// Layout 设置游戏窗口的布局
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {return outsideWidth, outsideHeight
}func main() {ebiten.SetWindowTitle("maze") // 设置窗口标题ebiten.SetWindowSize(WindowWidth, WindowHeight) // 设置窗口大小game := &Game{P: Pos{rand.Intn(N), rand.Intn(N)}, // 随机选择一个起始位置Stack: make([]Pos, 0), // 初始化栈}if err := ebiten.RunGame(game); err != nil { // 运行游戏panic(err)}
}// SystemFunction 处理系统功能,如退出游戏
func SystemFunction() {if ebiten.IsKeyPressed(ebiten.KeyEscape) { // 如果按下 ESC 键os.Exit(0) // 退出程序}
}// DrawWalls 绘制迷宫的墙
func (g *Game) DrawWalls(screen *ebiten.Image) {if g.T < N*N { // 如果还有未访问的块// 绘制当前块的位置(红色方块)vector.DrawFilledRect(screen, float32(g.P.X)*BS, float32(g.P.Y)*BS, BS, BS, color.RGBA{255, 0, 0, 255}, true)}// 遍历所有块,绘制墙for i := 0; i < N; i++ {for j := 0; j < N; j++ {if !g.Walls[i][j][0] { // 如果上墙存在vector.DrawFilledRect(screen, float32(i)*BS, float32(j)*BS, BS, WW, color.White, true)}if !g.Walls[i][j][1] { // 如果左墙存在vector.DrawFilledRect(screen, float32(i)*BS, float32(j)*BS, WW, BS, color.White, true)}if !g.Walls[i][j][2] { // 如果右墙存在vector.DrawFilledRect(screen, float32(i+1)*BS, float32(j)*BS, WW, BS, color.White, true)}if !g.Walls[i][j][3] { // 如果下墙存在vector.DrawFilledRect(screen, float32(i)*BS, float32(j+1)*BS, BS, WW, color.White, true)}}}
}// Next 生成迷宫的下一个块
func (g *Game) Next() {// check 函数检查给定的坐标是否在迷宫范围内且未被访问过check := func(x, y int) bool {return x >= 0 && x < N && y >= 0 && y < N && !g.IsVis[x][y]}// 标记当前块为已访问if !g.IsVis[g.P.X][g.P.Y] {g.IsVis[g.P.X][g.P.Y] = trueg.T++}// 查找当前块的所有未访问邻居var neighbors []intfor i := 0; i < 4; i++ {if check(g.P.X+Dirs[i].X, g.P.Y+Dirs[i].Y) {neighbors = append(neighbors, i)}}if len(neighbors) > 0 {// 如果有未访问的邻居,随机选择一个方向d := neighbors[rand.Intn(len(neighbors))]g.Stack = append(g.Stack, g.P) // 将当前位置压入栈g.Walls[g.P.X][g.P.Y][d] = true // 打破当前块的墙g.P.X += Dirs[d].X // 移动到邻居块g.P.Y += Dirs[d].Yg.Walls[g.P.X][g.P.Y][3-d] = true // 打破邻居块的对应墙} else if len(g.Stack) > 0 {// 如果没有未访问的邻居,回溯到上一个块g.P = g.Stack[len(g.Stack)-1] // 弹出栈顶元素g.Stack = g.Stack[:len(g.Stack)-1]}
}
相关文章:
Go Ebiten随机迷宫生成示例
引言 迷宫生成是计算机科学中一个经典的问题,常用于算法教学和游戏开发。本文将介绍如何使用 Go 语言和 Ebiten 游戏引擎实现一个基于深度优先搜索(DFS)的随机迷宫生成算法,并通过可视化的方式展示迷宫的生成过程。 技术栈 Go …...
前端学习DAY31(子元素溢出父元素)
.box1{width: 200px;height: 200px;background-color: chocolate;} 子元素是在父元素的内容区中排列的,如果子元素的大小超过了父元素,则子元素会从 父元素中溢出,使用overflow属性设置父元素如何处理溢出的子元素 可选值:visible…...
『SQLite』表的创建、修改和删除
本节摘要:主要讲述SQLite中创建、删除、修改表等操作。 创建表 CREATE TABLE 语句来创建表。 修改表 ALTER TABLE 语句来修改表名称、已有表字段,或者新增字段。 删除表 DROP TABLE 语句用来删除表. 注意: 上述内容详细讲解见文章&#…...
可持久化数据结构-线段树(主席树)
可持久化数据结构-线段树(主席树) (与可持久化字典树差不多) 概念:可持久化线段树是基本线段树的一个简单拓展, 是使用函数式编程思想的线段树; 作用: 可以存下来数据结构的所有历史版本 特点: 拓扑结构…...
如何利用PHP爬虫按关键字搜索淘宝商品
在当今的电商时代,获取淘宝商品信息对于市场研究、价格监控和竞争分析等方面具有重要意义。手动搜索和整理大量商品信息不仅耗时耗力,而且容易出错。幸运的是,PHP爬虫技术为我们提供了一种高效、自动化的方式来按关键字搜索淘宝商品。本文将详…...
GitHub - riscv-software-src/riscv-isa-sim: Spike, a RISC-V ISA Simulator
GitHub - riscv-software-src/riscv-isa-sim: Spike, a RISC-V ISA Simulator 操作手册 $ apt-get install device-tree-compiler libboost-regex-dev libboost-system-dev $ mkdir build $ cd build $ ../configure --prefix$RISCV $ make $ [sudo] make install 具体安装 …...
ubuntu开机启动服务
需求背景: 需要监控日志,每次都是手动启动 nohup ./prometheus >/dev/null & nohub ./node_exporter >/dev/null & 需求目标: 重启后系统自动启动服务...
电子电气架构 --- 设计车载充电机的关键考虑因素
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 简单,单纯,喜欢独处,独来独往,不易合同频过着接地气的生活,除了生存温饱问题之外,没有什么过多的欲望,表面看起来很高冷,内心热情,如果你身…...
2025_0105_生活记录
3号去内蒙看了流星雨。还记得上次看流星的时间是2018年,也是冬天,大家在雁栖湖校区的操场上仰望星空。那个时候幸运的看到了一颗流星,便迅速地在心里许愿。这次看到了三颗流星,我也许了愿,希望实现。 24年走过了十多个…...
电池管理系统(BMS)架构详细解析:原理与器件选型指南
BMS(电池管理系统)架构详细讲解 从你提供的BMS(Battery Management System)架构图来看,主要涉及到电池监控模块、通信模块、功率控制模块等部分。下面我将详细讲解该架构的各个功能模块及其工作原理。 1. 电池管理核…...
用JAVA编写一个简单的小游戏
用Java语言编写一个简单的小游戏。这里是一个非常基础的猜数字小游戏的代码示例。在这个游戏中,程序会随机选择一个1到100之间的整数,玩家需要猜测这个数字是什么。每次猜测后,程序会告诉玩家他们猜的数字是太高了、太低了还是正确。 impor…...
【SpringSecurity】二、自定义页面前后端分离
文章目录 1、用户认证流程AuthenticationSuccessHandler AuthenticationFailureHandlerSecurityFilterChain配置用户认证信息 2、会话并发处理2.1、实现处理器接口2.2、SecurityFilterChain配置 1、用户认证流程 AuthenticationSuccessHandler AuthenticationFailureHandler …...
小兔鲜儿:头部区域的logo,导航,搜索,购物车
头部:logo ,导航,搜索,购物车 头部总体布局: 设置好上下外边距以及总体高度, flex布局让总体一行排列 logo: logo考虑搜索引擎优化,所以要使用 h1中包裹 a 标签,a 里边写内容(到时候…...
什么是VLAN?
VLAN(Virtual Local Area Network,虚拟局域网)是一种将物理局域网划分成多个逻辑上独立的虚拟网络的技术。VLAN不依赖于设备的物理位置,而是通过逻辑划分,将局域网内的设备虚拟地组织到同一组。这种技术允许网络管理员…...
WPS计算机二级•数据查找分析
听说这里是目录哦 通配符🌌问号(?)星号(*)波形符(~) 排序🌠数字按大小排序以当前选定区域排序以扩展选定区域排序 文字按首字母排序 快速筛选分类数据☄️文字筛选数字筛选颜色筛选…...
计算机网络 (28)虚拟专用网VPN
前言 虚拟专用网络(VPN)是一种在公共网络上建立私有网络连接的技术,它允许远程用户通过加密通道访问内部网络资源,实现远程办公和安全通信。 一、基本概念 定义:VPN是一种通过公共网络(如互联网)…...
【Python学习(七)——序列、列表、元组、range、字符串、字典、集合、可变类型不可变类型】
Python学习(七)——序列、列表、元组、range、字符串、字典、集合、可变类型&不可变类型 本文介绍了序列、列表、元组、range、字符串、字典、集合、可变类型&不可变类型,仅作为本人学习时记录,感兴趣的初学者可以一起看…...
MATLAB常用建模方法——常用非参数检验
常用非参数检验 在用样本数据对正态总体参数作出统计判断(例如参数估计和假设检验)时,要求样本数据应服从正态分布,这种数据分布类型已知的总体参数的假设检验称为参数假设检验。 与参数假设检验相对应的还有非参数假设检验&#…...
【多线程初阶篇 ²】创建线程的方式
目录 二、多线程代码 1.继承Thread类 2.实现Runnable接口 3.匿名内部类 3.1 创建Thread⼦类对象 3.2 创建Runnable⼦类对象 4.lambda表达式(推荐) 小结: 🔥面试题:Java中创建线程都有哪些写法 二、多线程代码 …...
纵览!报表控件 Stimulsoft Reports、Dashboards 和 Forms 2025.1 新版本发布!
Stimulsoft 2025.1 新版发布,旨在增强您创建报告、仪表板和 PDF 表单的体验!此最新版本为您带来了许多改进和新功能,使数据处理更加高效和用户友好。亮点包括对 .NET 9 的支持、Microsoft Analysis Services 的新数据适配器、发布向导中适用于…...
Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...
HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...
华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...
MySQL JOIN 表过多的优化思路
当 MySQL 查询涉及大量表 JOIN 时,性能会显著下降。以下是优化思路和简易实现方法: 一、核心优化思路 减少 JOIN 数量 数据冗余:添加必要的冗余字段(如订单表直接存储用户名)合并表:将频繁关联的小表合并成…...
【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...
《Docker》架构
文章目录 架构模式单机架构应用数据分离架构应用服务器集群架构读写分离/主从分离架构冷热分离架构垂直分库架构微服务架构容器编排架构什么是容器,docker,镜像,k8s 架构模式 单机架构 单机架构其实就是应用服务器和单机服务器都部署在同一…...
