一条走廊拐上五次弯,仍然可以只表示一种连接。
看迷宫时,我们的目光通常沿着墙走。计算机却可以忽略大部分墙的样子。给每个格子起一个名字,记录哪些相邻格子之间有通道,画面就变成了图结构。这种换视角的方法不只适用于谜题,也能描述房间、文件夹、电路连接和任务之间的依赖关系。看上去复杂的画面有时反而容易处理:只要把关系写清楚,就有了可以准确检查的对象。
墙壁制造谜题,连接关系让它可以求解。
先有房间,再决定哪些门能打开
想象一张空白长方形网格。每个格子是一个小房间,每条公共边都可以成为门。最初把门全部关上,再打开其中一些,就形成了走廊。在图结构里,房间是顶点,打开的门是边。拐弯会改变画面,却不会创造一种新的连接关系。甚至可以把房间画在完全不同的位置,只要连接对象不变,图的关系就没有变化。
检查迷宫时,这个区分很实用。墙壁是否好看属于视觉判断;出口能否抵达属于连通性问题。把两件事混在一起,反而都难做。因此先建立并检查通道图。本篇直接用线条显示连接关系,并没有另外绘制墙壁。
树,让任意两个房间之间只有一条简单路径
一个连通、没有环的图叫作树。如果迷宫的通道构成树,任意两个格子之间都恰好有一条简单路径。这里的简单,是指途中不重复经过同一个格子。游客仍然会迷路、折返、钻进死胡同;唯一性描述的是底层解法,而不是实际走迷宫的感受。
含有 N 个格子的树会有 N 减一条通道。但只检查边数还不够:某些区域彼此断开,同时另一个区域存在环,也可能凑出同样的数量。本例还用遍历确认所有格子都能抵达。对于这里的无向网格图,连通性与边数结合,才能确定它是一棵树。 本次生成的 12 × 12 示例共有 144 个格子、143 条通道。

探索过程,也能用来修走廊
生成器寻找尚未访问的邻居,每进入一个新格子,就打开一条通道。如果当前位置已没有未访问的邻居,就沿原路回退,直到找到可以继续探索的地方。这就是深度优先回溯的思路。每个新格子通过一扇门加入已有的连通区域,所以通道不断增长,却不会形成环。
随机选择邻居会得到不同布局;固定随机种子,可以复现某一次选择序列。但这不意味着所有可能的迷宫出现概率相同。这种生成方式往往有自己的走廊风格,换一种算法,可能画出很不一样的迷宫,却同样满足树的全部性质。
求解器并不需要方向感
广度优先搜索按层探索:先访问起点,再访问相隔一条通道的格子,然后是相隔两条通道的格子,依次推进。每到一个新格子,都记住从哪个格子走来,找到出口后就能反向还原路线。通道代价相等时,这会找到边数最少的路径。在树里,本来也只有一条简单路径可选。
配图把计算出的 28 边路线覆盖在通道图上,从左上角的格子 0 到右下角的格子 143。连续两个格子必须存在真正打开的门,仅仅在画面上相邻还不够。一条看似合理的金线如果连接了本来不相通的格子,即使起终点正确,也仍然是程序错误。

多开一扇门,就改变了谜题的结构
在树中两个已经可以互通的格子之间,再打开一面墙。新增的门会形成一个环,沿这个环就有了两条简单走法,一些行程因此出现备选路线。改动很小,结构后果却明确:按通常的图论定义,它不再是完美迷宫。
很容易据此说新迷宫更简单,但这需要先定义简单。多一条连接可能缩短解题路线,同时让人面对的选择变得更不直观。死胡同数量、最短路径长度和分岔数量描述的是不同侧面,没有哪一个指标能单独衡量玩家是否觉得这个谜题有趣。
画得漂亮,不会让保证变得更强
本地测试假定每个格子都同样可以进入,每条通道代价相同。它没有模拟具体的人、轮椅、锁住的门,也没有考虑某段走廊可能更费时间。真实导航需要这些信息,往往还需要带权图。迷宫提供的是一个小而清楚、假设看得见的例子。
值得借用的是工作顺序:先定义关系,再检查性质,最后绘制解释。漂亮的图很容易把一个无法抵达的房间藏起来。简单的遍历不会欣赏设计,它只会告诉你还有一个房间从未被访问。这种不太客气的诚实,恰好是好测试应该有的性格。
