我用Go写了个华容道游戏,曹操终于不用再求关羽了!
程序员用Go语言复刻经典华容道游戏,包含自定义阵法系统、智能求解AI。通过二维数组表示棋盘,设计不同棋子移动逻辑,利用广度优先搜索算法实现自动求解。项目包含简洁界面、多种经典阵法及提醒诗句,完整源码可供下载体验。
缘起
最近闲着无聊,突然想起小时候玩的华容道游戏。那个时候玩得可起劲了,经常为了把曹操从困境中解救出来,绞尽脑汁好几个小时。现在我可是程序员了,不如用Go语言把这个经典游戏复刻出来?说干就干!毕竟之前我用易语言和快手语言都开发过这个游戏。
开发思路:从棋盘到代码
核心数据结构:棋盘是怎么表示的?
首先得想清楚,怎么在代码里表示这个棋盘。华容道是一个5x4的棋盘,上面有不同形状的棋子。我灵机一动,用一个二维数组就能搞定!
//TZHF 阵法的二维数组
type TZHF [5][4]int8
//ZhFaPz 阵法数据结构
type ZhFaPz struct {
Name string //阵法名称
ZhFa TZHF //阵法二维数组
}
这个设计我可是相当满意!数组里每个数字都有特殊含义:
1代表曹操(2x2大胖子)2-10代表关羽等历史人物(分横条和竖条两种)11代表小兵(1x1灵活的小瘦子)0代表空格(大家都想抢占的位置)-1代表占位符(比如曹操这么大,得占四个格子不是?)
这样设计的好处是一目了然,代码里判断起来特别方便。
阵法系统:让游戏更有挑战性
华容道好玩就好玩在有各种不同的阵法布局。我可不想写死一个布局,那样多没创意!于是我设计了一个配置文件系统:
func init() {
//从配置txt读取阵法
bb, _ := ioutil.ReadFile("config.txt")
strsz := strings.Split(string(bb), "\r\n")
for _, str := range strsz {
if z, err := strToZhenFa(str); err == nil {
zhenFaList = append(zhenFaList, z)
}
}
//加载背景图片和角色图片
//...
}
看,这样我只要在config.txt里加一行,就能添加一个新的阵法!比如:
横刀立马=5,1,-1,4,-1,-1,-1,-1,3,2,-1,6,-1,11,11,-1,11,0,0,11
层拦叠障=4,1,-1,11,-1,-1,-1,11,2,-1,11,11,6,7,-1,5,-1,0,0,-1
用户想玩什么难度,自己选!我还特意收集了好几种经典阵法,够玩家折腾一阵子了。
技术细节:如何让棋子听话地移动?
移动算法:看似简单实则复杂
移动棋子是游戏的核心。刚开始我以为很简单,后来发现不同形状的棋子移动规则完全不一样!曹操那么大一个,移动起来得考虑四个格子;而小兵就灵活多了。
我写了一个yd函数("移动"的拼音缩写)来处理所有移动逻辑:
func yd(yx, yy, nx, ny int32, TempZF TZHF) (TZHF, bool) {
// yx,yy: 原位置坐标
// nx,ny: 目标位置坐标
// 返回: 新的棋盘状态和是否移动成功
if yx == nx && yy == ny || TempZF[nx][ny] != 0 {
return TempZF, false
}
switch TempZF[yx][yy] {
case 1: // 曹操的移动逻辑
// 各种复杂的条件判断...
case 2,7,8,9,10: // 横条角色
// 横条移动规则...
case 3,4,5,6: // 竖条角色
// 竖条移动规则...
case 11: // 小兵
// 小兵移动规则...
}
return TempZF, false
}
这里我耍了个小技巧:棋子不仅可以移动一格,还可以一次性移动多格!只要路径上都是空的,想滑多远滑多远。这大大提高了游戏的流畅度,用起来特别爽!
电脑求解:让AI当你的救星
这绝对是我最得意的部分!当初我被华容道卡关时,要是有这功能就好了。我实现了一个自动求解的AI,用的是广度优先搜索(BFS)算法。
func (f *TForm1) OnButton1Click(sender vcl.IObject) {
hashjg := make(map[int]TZHF) // 存储已走过的状态,避免重复
sz := []TZHF{} // 待尝试的状态列表
sz = append(sz, zhenFa) // 从当前状态开始
// 广度优先搜索
for {
newsz := []TZHF{}
for _, sj := range sz {
ydhsz := getYdsz(sj) // 获取所有可能的下一步状态
for _, ydh := range ydhsz {
key := getKey(ydh)
// 检查是否已经达到目标状态(曹操到达出口)
if ydh[3][1] == 1 {
// 找到解了!
// ...
}
// 如果这个状态之前没出现过,就加入待尝试列表
if _, ok := hashjg[key]; !ok {
hashjg[key] = sj
newsz = append(newsz, ydh)
}
}
}
// ...
}
// 回溯并展示求解过程
// ...
}
为了让搜索更高效,我还发明了一个状态压缩的方法:
func getKey(sj TZHF) int {
jg := 1
for i := 0; i < 5; i++ {
for j := 0; j < 4; j++ {
sj := int(sj[i][j])
// 将相似的棋子类型进行归类,减少状态空间
if sj == 4 || sj == 5 || sj == 6 { sj = 3 } // 竖条统一
else if sj == 7 || sj == 8 || sj == 9 || sj == 10 { sj = 2 } // 横条统一
else if sj == 11 { sj = 4 } // 小兵转成4
else if sj == 0 { sj = 5 } // 空格转成5
if sj > -1 {
jg = jg*10 + sj // 合并数据得到一个int型的key
}
}
}
return jg
}
这招可管用了!把相似类型的棋子归类后,大大减少了需要存储的状态数量,搜索速度提升了不少。找到解后,我还加了个动画效果,一步步展示如何移动,特别直观!
项目结构
这个项目的文件组织还是比较清晰的,主要分为几个部分:
├── Form1.go # 界面定义文件
├── Form1Impl.go # 界面实现和核心游戏逻辑
├── Hrd.exe # 编译后的可执行文件
├── README.md # 项目说明文档(就是你现在看的这个)
├── config.txt # 阵法配置文件
├── go.mod # Go模块定义
├── go.sum # 依赖校验文件
├── h.go # 核心数据结构和工具函数
├── main.go # 程序入口
├── png/ # 图片资源文件夹
│ ├── 0.png # 空格图片
│ ├── 1.png # 曹操图片
│ ├── 2.png-11.png # 其他角色图片
│ ├── 原.jpg # 原始图片素材
│ └── 背景原.png # 背景图片
└── ui/ # 界面设计相关文件
└── backup/ # 备份文件
主要代码都在Form1Impl.go、h.go和main.go这几个文件里。如果你想修改游戏逻辑,这几个文件是重点。config.txt用来配置新的阵法,png文件夹里则存放了所有的游戏角色图片。
用户体验:让游戏更好玩
界面设计
我用govcl库做了个简洁的界面。左边是游戏棋盘,右边是阵法列表。用户可以:
- 点击选择棋子,再点击空格移动
- 双击右边的阵法列表切换不同的布局
- 实在解不出来时,点"电脑求解"按钮,让AI来救场
小彩蛋
游戏成功时,我特意加了一句古诗:
曹瞒兵败走华容,正与关公狭路逢,
只为当初恩义重,放开金锁走蛟龙。
有没有瞬间回到三国时代的感觉?这可是当初我翻了好久的资料找出来的,很应景吧!
上个图

总结
这个华容道游戏虽然不大,但让我学到了很多。从数据结构设计到算法实现,再到用户界面,每一步都充满了挑战和乐趣。最让我满足的是,现在我可以随时打开游戏,重温小时候的快乐时光了。
如果你也想挑战一下,不妨试试"横刀立马"这个经典阵法。要是实在解不出来,记得找AI帮忙哦!
PS:如果你有什么好的阵法创意,欢迎在config.txt里添加,分享你的智慧!
下载链接
想亲自体验这个华容道游戏吗?快来下载试试吧!
往期部分文章列表
- 用 Go 接口把 Excel 变成数据库:一个疯狂但可行的想法
- 穿墙术大揭秘:用 Go 手搓一个"内网穿透"神器!
- 布隆过滤器(go):一个可能犯错但从不撒谎的内存大师
- 自由通讯的魔法:Go从零实现UDP/P2P 聊天工具
- Go语言实现的简易远程传屏工具:让你的屏幕「飞」起来
- 当你的程序学会了"诈尸":Go 实现 Windows 进程守护术
- 验证码识别API:告别收费接口,迎接免费午餐
- 用 Go 给 Windows 装个"顺风耳":两分钟写个录音小工具
- 无奈!我用go写了个MySQL服务
- 使用 Go + govcl 实现 Windows 资源管理器快捷方式管理器
- 用 Go 手搓一个 NTP 服务:从"时间混乱"到"精准同步"的奇幻之旅
- 用 Go 手搓一个 Java 构建工具:当 IDE 不在身边时的自救指南
- 深入理解 Windows 全局键盘钩子(Hook):拦截 Win 键的 Go 实现
- 用 Go 语言实现《周易》大衍筮法起卦程序
- Go 语言400行代码实现 INI 配置文件解析器:支持注释、转义与类型推断
- 高性能 Go 语言带 TTL 的内存缓存实现:精确过期、自动刷新、并发安全
- Golang + OpenSSL 实现 TLS 安全通信:从私有 CA 到动态证书加载
更多推荐



所有评论(0)