- 玩法一 数字一笔:规则库、求解器、26 关、竖屏触摸 Web 原型、测试 - 玩法二 连连气球:连消畅玩版核心、Web 原型、Cocos 球槽组件与导出脚本 - 玩法三 六边一笔:规则库、求解器、10 关 + 转墙实验包、Web 原型、测试 - 产品文档、UI 设计规范、各玩法 GDD / HANDOFF - 文档移除全部外部参考作引用;删除玩法二 v0 旧稿
13 KiB
玩法三 · 六边一笔
本文只描述玩法三。玩法一、玩法二有自己的目录和 GDD,见仓库 docs/PRODUCT.md。
在六边形拼板上画一条哈密顿路径。格子之间的边上可以有墙,墙挡住那一条邻接。预先写好的数字,必须刚好在那一步走到。
本玩法是独立玩法:六边形 + 边墙,不用矩形大格。墙的价值是把“第一步往哪走”收成推理——看起来相邻的格子,有墙就走不过去。关卡、资源、文案全部原创。
1. 一句话
在六边形盘上走遍每一格;黄黑条纹的墙贴在两条格子的共用边上,那条路走不通;线索数字必须踩在对应步号上。
2. 产品定位
| 项 | 决定 |
|---|---|
| 类型 | 单机、离线、无体力、无计时的逻辑 puzzle |
| 平台 | 手机竖屏。本玩法 V1 先在 modes/03-hex-walls/web/ 可玩 |
| 单局 | 20–120 秒想,5–12 秒画完 |
| 会话 | 通勤 3 关,睡前 10 关 |
| 对象 | 已经能接受一笔画的人;墙是给“矩形走腻了”的第二层 |
| 付费 | 竖直切面免费无广告 |
和玩法一同属“顺序一笔画”,但几何不同:
| 玩法一 | 玩法三 | |
|---|---|---|
| 格子 | 矩形,可 2×2 只计一步 | 正六边形,一格一步 |
| 邻接 | 四向共边 | 六向共边 |
| 障碍 | 空洞 | 空洞 + 边墙 |
| 代码 | modes/01-number-stroke |
modes/03-hex-walls,禁止互相 import |
不要把墙补进玩法一的后期关。墙是本玩法的主旋钮。
3. 核心循环
- 看盘:线索在哪,墙封了哪几条边,哪一格看起来近其实过不去。
- 推:从线索往外挤,尤其是被墙封死的第一步。
- 画:滑到相邻且无墙的未走格,自动填步号。
- 错了沿原路退,或重开。
- 全填满且线索全部对上 → 过关。
没有分数。爽感来自“墙把表面的近路掐掉,只剩一条”。
4. 规则(权威)
4.1 盘面
- 格子是点顶(pointy-top)正六边形,用轴坐标
(q, r)。 - 每个格是图上一个节点,路径里计 1 步。没有大格。
- 单位格要么属于恰好一个六边形,要么是空洞。
- 盘面可不规则。
轴坐标邻接(未考虑墙):
(q+1, r), (q-1, r), (q, r+1), (q, r-1), (q+1, r-1), (q-1, r+1)
4.2 墙
墙是无向边,贴在两个相邻格的共用边上,画成黄黑斜纹警示条。
- 有墙的两格视为不相邻。其它邻接不受影响。
- 墙不占格,不能走在墙上。
- 同一对格最多一堵墙。
- 墙必须画在真实共用边上。不能“对角墙”。
这是本玩法相对玩法一多出来的唯一新原语。
4.3 路径
目标:在「去墙之后的格图」上找一条哈密顿路径。
- 每个格恰好一次。
- 只能走到相邻、无墙、尚未走过的格。
- 第 k 个格显示数字 k(从 1 起)。
- 不能分叉、不能跳、不能穿墙。
4.4 线索格
部分格预先写了正整数 c,带描边。
- 走到该格时步号必须等于
c。 - 可以没有
1(起点未知)。教学前 8 关必须有1。 - 线索互不相同,
1 ≤ c ≤ N。 - 可以没有
N。
4.5 对错
允许暂时画错:
- 踩到线索但步号 ≠
c:该格冲突态(红底),显示当前步号。 - 冲突不打断手势。
- 过关:所有格走过,且所有线索步号正确。
- 无失败弹窗。穿墙或对角滑:忽略。
4.6 内容铁律
发布前求解器必须断言:
- 去墙后的图连通。
- 恰好 1 条哈密顿路径满足全部线索。
- 线索尽量少。教学关可以多给。
若去掉全部墙后解变得不唯一,说明墙在干活,这关才算合格的“墙关”。第 3 关起,每关至少 1 堵墙,且去掉墙会破坏唯一性。
5. 交互
单指。和玩法一同一套手感,只是命中的是六边形、且要检查墙。
| 手势 | 行为 |
|---|---|
| 点合法起点 | 该格成为第 1 步 |
| 滑向相邻、无墙、未走格 | 追加 |
| 滑向有墙的邻居 | 忽略(可在墙上闪一下) |
| 滑回上一格 | 撤销 |
| 滑到不相邻 / 已走且非上一格 | 忽略 |
| 松手 | 保留路径,可从末端继续 |
合法起点:有线索 1 则只能从它起手;否则任意格。
按钮:重开、提示、菜单(本玩法选关 / 回壳)。顶栏:{pack}-{index}、剩余格、菜单。
输入状态机与玩法一相同:Empty → Drawing → Idle → Cleared。实现时不要 import 玩法一,允许各写一份。
6. 反馈与手感
| 事件 | 反馈 |
|---|---|
| 追加一步 | 六边形 80ms 弹,共用边拉一条短线 |
| 撞墙 | 墙闪白 100ms,短振动,不追加 |
| 线索步号正确 | 描边闪白 |
| 冲突 | 红底 |
| 过关 | 路径色提高,短线顺次扫过 |
未走:中灰。已走:蓝紫。墙:黄黑斜纹,对比足够,不靠颜色当唯一信息(色弱可把墙改成粗黑 + 缺口)。背景白。
7. 关卡语言
一次只加一个旋钮。
| 旋钮 | 作用 | 何时引入 |
|---|---|---|
| 格数 N | 6–8 教学,9–14 常规,15–20 后期 | 全程 |
| 墙的条数 | 1 堵教规则,2–4 堵做推理 | 第 3 关 |
| 墙贴在线索旁 | 第一步往往只剩一个方向 | 第 4 关 |
| 空洞 | 和墙叠加,近路更假 | 第 6 关 |
| 中段线索 | 不只靠起点 | 第 5 关 |
| 无线索 1 | 起点未知 | 第 13 关之后 |
不做:矩形大格、斜穿、传送、限时。大格是玩法一的旋钮,不要混进来。
7.1 教学 8 关(必须手做)
1-1 到 1-4 的坐标在 levels/pack-1-tutorial.json。
| 关 | 教什么 |
|---|---|
| 1-1 | 六边形、滑动、自动出数字。无墙。3 格 |
| 1-2 | 必须走完。5 格,标 1 和 5 |
| 1-3 | 第一堵墙:看起来相邻,滑不过去,必须绕 |
| 1-4 | 墙贴在 1 旁边,第一步不是“随便挑邻居” |
| 1-5 | 中段线索 |
| 1-6 | 两堵墙 + 一个空洞 |
| 1-7 | 先想再画,错了要退 |
| 1-8 | 综合:约 12 格、3 堵墙、3 个线索 |
1-3 是关键:过不了“墙是边不是格”,后面全废。
7.2 结构
一包 8 关。V1:教学 8 + 3 包 × 8 = 32 关。线性解锁。
7.3 规则样例
规则样例直接用 levels/pack-1-tutorial.json:1-3 演示“墙是边不是格”(两格共边却被墙封住,看起来相邻,滑不过去,必须绕),1-4 演示“墙贴在线索旁,第一步只剩一个方向”。全部关卡由求解器断言唯一解且墙参与唯一性(§4.6)。
8. 生成器与求解器
教学关手做。第 9 关起可生成,人要过一眼。
求解器:
- 输入:六边形列表 + 墙边列表 + 线索。
- 邻接 = 轴坐标六邻接减去墙。
- 回溯哈密顿路径,线索处剪枝。
N ≤ 20。发布条件paths.length === 1。- 额外检查:删掉所有墙之后
paths.length !== 1(墙必须改变解集合)。
生成:
- 铺一块连通的六边形聚落,可挖洞。
- 随机一条哈密顿路径当作者解。
- 在不是作者解所用的边上插 1~3 堵墙。
- 加 2~3 个线索直到唯一。
- 跑“去墙不唯一”检查。失败则换墙。
关卡文件:
{
"id": "1-3",
"pack": 1,
"index": 3,
"orientation": "pointy",
"cells": [
{ "id": "a", "q": 0, "r": 0, "clue": 1 },
{ "id": "b", "q": 1, "r": 0 },
{ "id": "c", "q": 0, "r": 1 }
],
"walls": [
["a", "b"]
]
}
walls 是格 id 对。求解器不写进 JSON。
9. 界面与流程
(壳:选玩法)→ 本玩法选关 → 对局 → 过关 → 下一关
↘ 菜单:关卡列表 / 回壳
对局层:顶栏关号与剩余格,中间六边形盘(按短边缩放),底栏重开 / 提示。过关短动画后自动下一关。
1-1 一行:“从一个数字滑到旁边的格子”。1-3 一行:“条纹是墙,绕开它”。之后无文案。
10. 提示、存档
提示:
- 无路径:指出合法起点。
- 路径是唯一解前缀:指出下一步。
- 已偏离:高亮分叉点,不继续给错下一步。
- 竖直切面无限次。
存档键前缀 mode:03-hex-walls。clearedId[]、currentId。不存半途路径。
11. 设计边界
V1 只做主规则(§4)。明确不做:
- 矩形大格(玩法一的旋钮)
- 矩形 + 墙、斜穿、传送、限时
- 计分
几何锁定为六边形,墙是边不是格。关卡、资源、文案全部原创,不使用第三方题库或素材。
12. 技术
全部落在 modes/03-hex-walls/。
禁止:
- import 玩法一的 Cell / 四向邻接 / 矩形碰撞
- 把墙做成“第三种格子”
| 项 | 决定 |
|---|---|
| 竖直切面 | web/ 单页 |
| 坐标 | 轴坐标 pointy-top |
| 求解器 | tools/solver.ts,只服务本玩法 |
| 关卡 | levels/*.json |
模块:model(Hex、Wall、Path)、rules、input、solver、view。
13. 竖直切面
- 1-1、1-2 无墙可过。
- 1-3 直滑进墙无效,绕开后能过。
- 1-4 有线索 1 时点别的格起手无效;墙让第一步只剩一个方向。
- 冲突、撤销、重开与玩法一同样稳。
- 求解器对 VS 关断言唯一解,且去墙后不唯一(1-3 起)。
- 提示在偏离时拉回分叉。
14. 里程碑
| 阶段 | 交付 |
|---|---|
| M0 | 本 GDD 锁定 |
| M1 | 规则 + 求解器 + 1-1~1-4 可玩 |
| M2 | 1-1~1-8 + 存档 |
| M3 | 再 24 关 + 选关 |
| M4 | 迁 Cocos 本玩法场景 |
15. 关键决定
- 独立玩法,不是玩法一的 DLC。 六边形模型和边墙都住在本目录。
- 墙是边,不是格。 穿墙 = 那条邻接不存在。
- 解唯一,且墙必须参与唯一性。
- 允许画错,随时撤回。
- 无大格。 大格留给玩法一。
- 先 Web,再 Cocos。
16. 验收
- 没玩过的人在 1-3 结束前理解墙。
- 1-4 开始出现停顿,不是闭眼滑。
- 任意关关闭提示仍可人解。
- 撞墙 10 次不误走、不穿模。
17. 已关闭的问题
- 要不要合并进玩法一?不要。
- 要不要矩形 + 墙?不要。本玩法锁六边。
- 要不要计分?不要。
18. 留给实现的缺口
- 对外名称是否就用「六边一笔 / Hex Stroke」。
- 墙的最终画法(斜纹宽度、是否要缺口给色弱)。
- M3 关是手做还是生成后人工改,看 M2。
19. 附录 A · 转墙(实验机制,2026-09-15 加入)
A.1 设计铁律:手指就是笔尖
路径的末端永远在指尖下面;手指走过哪些格,路径就是哪些格。任何让末端离开指尖的机制(滑行、传送、跳格、自动延伸)一律不做。新机制只能改三样东西:哪一步合法、数字怎么数、过关条件是什么。
A.2 规则
- 六边形网格上每个顶点交汇三条边,互成 120°。转墙固定在一个顶点上,任意时刻占其中一条边,画法与静态墙相同,只在轴心那一端加一个圆点。
- 每走一格(含起手那一格),所有转墙同拍顺时针转 120°。已走 t 格时,墙在第
(phase + t) mod 3条边上。 - 判定能否从末端走到邻格,用的是出发前的位置;走完再转。撤销一步则倒转回去。状态完全由步号推出,不需要额外存档。
- 转到盘外或空洞的边上时,墙暂时不挡任何东西。
- 转墙不得与静态墙重叠;周围至少要有两条盘上的边。
A.3 玩家体验
玩家不仅要估计路线,还要估计到达某条边时墙在哪。线索数字给出步号,步号 mod 3 就是墙的位置,所以线索和转墙天然互相配合:为了让某一步“刚好开着”,路线要多绕或少绕一格。
A.4 内容铁律(在 §4.6 之上追加)
每个转墙必须同时满足:
- 去掉它,解不再唯一。
- 把它换成钉在任意一条候选边上的静态墙,解都不再唯一(保证“会转”参与推理,而不是随便一堵墙就能替代)。
同一顶点只能放一个转墙;两个转墙可以共用一条候选边。实验包里最多放到 4 个转墙(19 格),正式包按试玩结果定上限。
A.5 关卡文件
"spinners": [{ "cell": "c", "corner": 0, "phase": 1 }]
corner 是该格第几个角(从 30° 起顺时针 0..5),phase 是空盘时墙在第几条候选边。候选边顺时针编号:0 = 背离该格的那条边,1 = 该格与顺时针下一邻格,2 = 该格与上一邻格。
A.6 实验包
levels/pack-2-spinner.json,9 关:2-1 教规则(起手后墙正好挡住直觉的第一步),2-2 用中段线索算拍子,2-3 静态墙 + 转墙综合;2-4 起转墙数逐步加到 4,格数 7→19,让“满盘都在动”的感觉逐关加强。