【发布时间】:2011-01-15 20:11:47
【问题描述】:
我正在为游戏Dwarf Fortress 开发一个名为Quickfort 的工具。 Quickfort 将 csv/xls 格式的电子表格转换为一系列命令,供 Dwarf Fortress 执行,以便在游戏中绘制“蓝图”。
我目前正在尝试以最佳方式解决此工具 2.0 版本的区域绘图问题。
考虑以下定义二维网格的绘图命令的“蓝图”。网格中的每个单元格都应该被挖出(“d”)、引导(“c”)或不作图(“.”)。实际使用中可能存在任意数量的不同绘图命令。
. d . d c c
d d d d c c
. d d d . c
d d d d d c
. d . d d c
为了尽量减少需要发送到 Dwarf Fortress 的指令数量,我想找到一组最大的连续矩形,这些矩形可以完全覆盖或“绘制”所有可绘制的单元格。为了有效,给定矩形的所有单元格必须包含相同的命令。
这是一种比 Quickfort 1.0 更快的方法:将每个单元格单独绘制为 1x1 矩形。 This video 显示了两个版本的性能差异。
对于上面的蓝图,解决方案是这样的:
. 9 . 0 3 2
8 1 1 1 3 2
. 1 1 1 . 2
7 1 1 1 4 2
. 6 . 5 4 2
上面每个相同编号的矩形表示一个连续的矩形。最大的矩形优先于也可以在其区域中形成的较小的矩形。编号/矩形的顺序并不重要。
我的current approach 是迭代的。在每次迭代中,我构建了一个最大矩形列表,这些矩形可以通过从单元格向所有 4 个方向延伸,由每个网格的可绘制单元格形成。在将列表排序为最大之后,我从找到的最大矩形开始,将其底层单元格标记为“已绘制”,并将该矩形记录在列表中。在绘制每个矩形之前,检查其底层单元格以确保它们尚未绘制(与先前的绘图重叠)。然后我们重新开始,找到可以形成的最大剩余矩形并绘制它们,直到所有单元格都被绘制为某个矩形的一部分。
我认为这种方法比愚蠢的蛮力搜索稍微优化了一些,但我浪费了很多周期(重新)计算单元格的最大矩形并检查底层单元格的状态。
目前,这个矩形发现例程占据了该工具总运行时间的最大份额,尤其是对于大型蓝图。为了速度,我牺牲了一些准确性,只考虑单元格中的矩形,这些单元格似乎形成了一个矩形的角(使用一些并不总是正确的相邻单元格启发式方法确定)。由于这种“优化”,我当前的代码实际上并没有正确生成上述解决方案,但它已经足够接近了。
更广泛地说,我认为最大矩形优先的目标是该应用程序的“足够好”的方法。但是我观察到,如果目标是找到矩形的最小集(最少数量)以完全覆盖多个区域,则解决方案将如下所示:
. 3 . 5 6 8
1 3 4 5 6 8
. 3 4 5 . 8
2 3 4 5 7 8
. 3 . 5 7 8
第二个目标实际上代表了问题的更优化解决方案,因为更少的矩形通常意味着更少的命令发送到 Dwarf Fortress。然而,基于我有限的数学知识,这种方法让我觉得更接近 NP-Hard。
如果您想更好地了解整体策略,请观看the video;我没有解决 Quickfort 过程的其他方面,例如找到绘制所有矩形的最短光标路径。可能有解决这个问题的办法,将这些多种策略连贯地结合起来。
任何形式的帮助都将不胜感激。
【问题讨论】:
-
你试过遗传算法吗?听起来很适合这个问题。