你可以通过使用保持约束条件的转换来替换步骤1-6,从而开始一个已知的有效填充网格。
例如,你可以从这个网格开始,通过将
grid[i][j]
设置为
((i + j) % 5) + 1
来轻松生成它:
1 2 3 4 5
2 3 4 5 1
3 4 5 1 2
4 5 1 2 3
5 1 2 3 4
然后,如果你交换两行,你仍然会得到一个有效的网格,例如,交换第一行和第三行:
1 2 3 4 5
4 5 1 2 3 <
3 4 5 1 2
2 3 4 5 1 <
5 1 2 3 4
您还可以交换两列,仍然得到一个有效的网格,例如交换第2列和第4列:
1 2 5 4 3
4 5 3 2 1
3 4 2 1 5
2 3 1 5 4
5 1 4 3 2
^ ^
所以,首先使用常规网格,在循环内部生成随机行和列的对,并交换它们。您还可以交换数字(例如,将所有5更改为3,反之亦然)。您总是会得到有效的结果。
然后可以继续进行第7步。
但是,第7步比看起来更复杂,因为您需要使谜题可解。换句话说,每个时刻玩家都应该能够在不猜测的情况下逻辑推断出至少一个单元格的值。
因此,您需要编写一个函数,使用约束条件计算空单元格的有效值列表(您只需要一个所有未出现在同一行或列中的值的列表)。在第7步中删除数字时,在循环内部:
- 选择一个随机单元格
- 基于网格中的其他非空单元格计算该单元格的有效可能值
- 如果只有一个可能的值(即单元格中的值),则可以将其删除
单元格的值可以被推导出来的另一种方法是,如果它是该值在其行或列中唯一可能的单元格,则可以确定它。要验证这一点,您需要为该单元格所在行或列中的每个单元格计算一个有效值列表(不在同一行或列中的其他非空单元格中不存在的值),即使单元格包含多个可能的值,如果它是其行中包含该值列表的唯一单元格,或者是其列中的唯一单元格,则可以确定该值,因此可以将其删除。
您可以重复此过程,直到删除所需数量的单元格。因为每个已删除的单元格在其被删除时都能够被推导出来(因为它是单元格为空后仅可能的值),因此玩家应该能够通过以与删除顺序相反的顺序添加值来解决谜题。
如果这不产生足够“有趣”的谜题,则可以采用“欺骗”方法,即拥有一组手动创建的现有谜题数据库,然后选择一个并通过随机交换行和列或交换数字进行混淆。这可能会涉及某些版权问题,作为“衍生作品”,但这不是编程问题。