我正在尝试制作一个谜题,让玩家使用n个连接的n-minos将n×n网格拼凑在一起(定义:连接的n个1×1块,例如每个俄罗斯方块片段是4-mino) 。然而,尽管看起来对人类来说似乎很容易,但是生成切割网格的方法首先证明是一种挑战。
对于人类来说,通过递归地遵循以下逻辑/伪代码来生成这样的解决方案是相对容易的任务:
:start_of_recursion:
从一个随机的“连接最少”的部分(结尾,角落,连接最少成员的边缘部分)开始作为起始的mino块
:start_of_recursion:
:end_of_recursion:
如果已填写董事会,则退出递归
:end_of_recursion:
执行此例程似乎生成了一种O(n ^ 2)解决方案生成方法,但条件检查证明对计算机来说确实很昂贵。为了确定是否要连接电路板,人类只是检查剩余区域内的任何“间隙”,并以几乎O(1)的方式处理简单的非重叠图,而我的代码实现需要“从图表上的一个点扩散到其邻近地区,并在扩散完成后进行检查,以检查是否有任何点位于可达范围之外(O(n)最多)。由于每次在最里面的迭代中都会执行此检查,因此它会将复杂性退化为O(n ^(3+))问题,并且变得非常低效。
是否有一种方法以类似于人类认知的方式检查“缺口”?或者可以从根本上考虑问题并简化为计算机更容易解决的问题?
答案 0 :(得分:0)
您的问题听起来像bin packing problem的变体。我会通过约束满足方法来解决这个问题。下面我将使用Minizinc伪代码。
电路板由电池组成,每个电池可以从几个颜色中分成一种颜色。我们可以表示如下:
int: rows;
int: cols;
int: colors_num;
array [1...colors_num] of int: colors;
array [1..rows,1..cols] of var colors: board;
接下来,我们添加约束。例如,如果单元格具有颜色A,则至少1个相邻单元格必须具有相同的颜色A:
constraint forall (c in colors) (
if board[i, j] == c then
at_least (1, [board[i-1, j], board[i+1, j], board[i, j-1], board[i,j+1]], c)
else
true
endif
您可以将所有允许/禁止的形状描述为约束,或使用其他智能方法引入可能的切割。
约束满意度应该 比递归方法更有效。然而,它不是很可扩展 - 如果你试图为一个巨大的棋盘(数百或数千个细胞/颜色)生成游戏,生成迷你将需要相当长的时间和记忆。