基本上,我正在尝试在C中实现一个可以使用右手或左手规则解决迷宫的算法。我在文件中得到了这样的三角形迷宫:
我已经实现了解析文件并将迷宫加载到动态2D数组中的函数。从数组中的值,我可以判断每个字段是否具有右边框,左边框和垂直边框(顶部或底部,具体取决于字段的位置)。我还告诉起点的坐标(即这个特定例子中的6,1)和要遵循的初始边界(即底部),当然,还要使用右手或左手规则来查找退出。
我应该列出通往出口的字段的坐标。我基本上已经实现了解析和检查迷宫有效性的所有必要功能,但我并不完全理解如何在算法中放置右手和左手规则。我希望这是足够的信息,以了解我正在尝试做什么。我不一定需要特定的代码,我只需要了解如何实际执行此操作。
感谢。
答案 0 :(得分:9)
让我们根据三角形迷宫细胞制定右手规则。假设我们已通过穿过其底边进入单元格,如下图中的灰色箭头所示。
右手规则告诉我们将右手放在墙上。当我们进入一个单元格时,墙壁在哪里?
在上面的第一个案例中,右边没有墙。在我们右边的某个地方必须有一堵墙,所以我们要继续向右转,直到我们击中它。在三角形迷宫中右转意味着顺时针旋转60度,然后跨过三角形边缘进入相邻的单元格。
在第二种情况下,当我们进入牢房时,右边有一堵墙。我们希望将这个墙保持在我们的右边,所以我们向左转,然后沿着那个方向步进到相邻的单元格。
在第三种情况下,两侧都有墙壁。我们必须转身离开牢房。我们通过向相反方向移动返回到前一个单元格,因此这次右边的墙将成为三角形的不同边缘。
要遵循左手规则,我们在上图中的镜像上使用类似的推理。
接下来,我们需要网格单元格的数字表示。有多种方法可以对单元格和边缘进行编号。一种可能性如下图所示。每个三角形的边缘编号为0,1,2。左边是三角形的两个方向,显示每个三角形的边编号。在中心是每个三角形方向的八种可能的墙壁配置。右边是每个墙配置的十进制和二进制表示,使用边数来从右到左索引二进制数字即。,从最低有效数字到最高有效数字。
使用此编号方案,问题中显示的迷宫可以用以下文字表示。第一行包含网格中的行数和列数。第二行描述了我们的起点:行号,列号,交叉边。其余行包含单元格描述。
6 7
6 1 2
4 2 1 1 5 0 3
4 1 2 0 2 0 1
4 0 1 0 1 3 4
4 2 7 4 0 1 1
6 4 1 1 6 4 2
2 2 6 0 2 2 6
实现的最后一部分是一个转换矩阵,它允许我们在迷宫遍历中查找下一个状态,给定当前状态和我们正在越过的边缘。
在描述转换矩阵之前,让我非常清楚我们如何对网格进行编号。在外部,我们将从1开始对行和列进行编号,如图所示。这就是我们如何阅读起始位置以及我们如何向用户显示解决方案的方式。但是,在程序中,从零开始对行和列进行编号很方便,因为这是C语言如何索引数组的方式。例如,我们会说左上角的单元格位于行0
和列0
中。这意味着如果我们有一个名为maze
的二维整数数组,我们将左上角的单元格称为maze[0][0]
。
给定三角形网格单元的行索引r
和列索引c
,使用从零开始的编号,让我们从{{1}的奇偶校验中找出三角形方向}和r
。如果它们具有相同的奇偶校验,意味着它们都是奇数或两者都是偶数,则三角形指向下方。否则,它指向上方。实现此目标的一种简单方法是计算c
,如果奇偶校验相同,则为(r+c)%2
;如果奇偶校验不同,则为0
。
接下来,我们必须考虑到我们正在越过的边缘。如果我们知道我们要离开的三角形的方向以及我们正在越过的边缘的数量,我们可以解决:
我们正在进入的三角形的行号。
我们正在进入的三角形的列号。
我们在新输入的三角形的上下文中划过的边数。
所有这些信息都在以下三维数组中表示。
1
第一个索引用于三角形方向, moves[2][3][3] = {
{ {-1, 0, 1}, {0, 1, 2}, {0, -1, 0} },
{ {0, 1, 2}, {1, 0, 0}, {0, -1, 1} } };
表示向下三角形,0
表示向上三角形。第二个索引是我们正在越过的边缘的数量,使用我们要离开的三角形的边编号。第三个索引用于查找上面列出的三条信息。
0:行号的变化。
1:列号的变化。
2:我们刚刚越过的边数,使用新三角形的边编号。
例如,让我们看看样本迷宫中的第一步。我们从行1
,列5
开始。总和奇偶校验为0
,表示向上三角形。我们正越过边缘1
。因此,我们看一下0
。结果信息为maze[1][0]
,告诉我们在新单元格中:
行索引更改{0, 1, 2}
。
列索引按0
更改。
我们刚刚越过边缘1
。
现在我们可以在循环中应用算法,一旦离开迷宫的边界就会结束。
以下是我讨论过的概念的ANSI C实现。您必须将其调整为您用来表示迷宫的任何文件格式。请记住,在起始位置的描述中,我的格式指定了进入迷宫的交叉边缘。
2