如何创建像数独这样的合乎逻辑的纸笔游戏?
How to create a logical paper and pencil game like Sudoku?
本题不仅限于数独,还可能包括数郎、一鸟、涂壁等
我了解解决数独和其他类似谜题的算法,但我很难弄清楚如何创建他们。
说我想要一个数独生成器(取最流行的)。我猜它需要分两步工作:
- 创建有效的解决方案
- 删除部分解决方案,直到留下所需数量的线索。
创建解决方案并非易事,如果您随机进行直到到达最后一步并最终陷入僵局,通常效果会很好。
删除解决方案的某些部分需要确保只删除多余的部分,这也不是微不足道的。
是否有通用算法可以解决这个问题?我怎样才能实现这样的事情?
我知道我的问题是 "broad" 并且我没有展示很多我到目前为止的内容(将问题一分为二),但我没有任何线索可以开始思考算法。我不是在寻求解决方案,而是在寻求如何开始的提示。
您可以通过解决一开始没有指定任何内容的数独谜题来创建一个数独谜题。如果您的求解器通过填充正方形来进行,您可以通过在适当的点停止(或回滚)该过程来 "remove" 它们。
You could in general approach this as follows:
Define a set of rules which can assist a human in progressing in a game. For instance, in Sudoku, one of those rules could be:
- Call the "field of influence" of a given cell, the cells that are either in the same row, the same column or in the same 3x3 block as that given cell. The rule is that this cell cannot have any of the values that are already used in its field of influence. If that means there is only one valid value left, then place that value in this cell.
Another rule could be:
- If there is a value that cannot be used anywhere else in the same 3x3 block, then place that value in this cell. Similarly if a value cannot be used anywhere else in the cell's row; or cannot be used anywhere else in the cell's column.
There are obviously other rules. These rules can be more complicated. Rank the rules by how difficult it is for a human to verify and apply them. Try to be as complete as you can, by looking how you, as a human, reason when solving the game. Implement these rules as functions in the program. In the Sudoku example, such a rule function can be applied to a given cell, and return success (i.e. the cell gets a value) or failure (the rule cannot be used to deduct its value).
Let's say the program should generate a Sudoku of a given difficulty. We will interpret that to mean that solving the Sudoku will require the player to use at least once a rule that has at least that difficulty, or an exotic rule that was never foreseen.
Now start from a solved Sudoku. Remove randomly 50% of the values. Check if the Sudoku can be solved by only using known rules that are within the difficulty range. If not, restore 25% of the removed cells, and repeat. If it could be solved, remove 25% more cells randomly. Continue halving the number of involved cells (either restoring them or removing them), much like a binary search algorithm, until you arrive at the end of this search. For a Sudoku game, this process would take about 7 iterations. Then you will have a kind of "local minimum", where the rules can be applied to get to a solution.
This is far from perfect, as it could well be there is some other cell that could be cleared, while still allowing the rules to work towards a solution. So, if you want to refine this search, you could add some additional iterations to remove random cells as long as the resulting board can still be solved by applying the rules.
本题不仅限于数独,还可能包括数郎、一鸟、涂壁等
我了解解决数独和其他类似谜题的算法,但我很难弄清楚如何创建他们。
说我想要一个数独生成器(取最流行的)。我猜它需要分两步工作:
- 创建有效的解决方案
- 删除部分解决方案,直到留下所需数量的线索。
创建解决方案并非易事,如果您随机进行直到到达最后一步并最终陷入僵局,通常效果会很好。
删除解决方案的某些部分需要确保只删除多余的部分,这也不是微不足道的。
是否有通用算法可以解决这个问题?我怎样才能实现这样的事情?
我知道我的问题是 "broad" 并且我没有展示很多我到目前为止的内容(将问题一分为二),但我没有任何线索可以开始思考算法。我不是在寻求解决方案,而是在寻求如何开始的提示。
您可以通过解决一开始没有指定任何内容的数独谜题来创建一个数独谜题。如果您的求解器通过填充正方形来进行,您可以通过在适当的点停止(或回滚)该过程来 "remove" 它们。
You could in general approach this as follows:
Define a set of rules which can assist a human in progressing in a game. For instance, in Sudoku, one of those rules could be:
- Call the "field of influence" of a given cell, the cells that are either in the same row, the same column or in the same 3x3 block as that given cell. The rule is that this cell cannot have any of the values that are already used in its field of influence. If that means there is only one valid value left, then place that value in this cell.
Another rule could be:
- If there is a value that cannot be used anywhere else in the same 3x3 block, then place that value in this cell. Similarly if a value cannot be used anywhere else in the cell's row; or cannot be used anywhere else in the cell's column.
There are obviously other rules. These rules can be more complicated. Rank the rules by how difficult it is for a human to verify and apply them. Try to be as complete as you can, by looking how you, as a human, reason when solving the game. Implement these rules as functions in the program. In the Sudoku example, such a rule function can be applied to a given cell, and return success (i.e. the cell gets a value) or failure (the rule cannot be used to deduct its value).
Let's say the program should generate a Sudoku of a given difficulty. We will interpret that to mean that solving the Sudoku will require the player to use at least once a rule that has at least that difficulty, or an exotic rule that was never foreseen.
Now start from a solved Sudoku. Remove randomly 50% of the values. Check if the Sudoku can be solved by only using known rules that are within the difficulty range. If not, restore 25% of the removed cells, and repeat. If it could be solved, remove 25% more cells randomly. Continue halving the number of involved cells (either restoring them or removing them), much like a binary search algorithm, until you arrive at the end of this search. For a Sudoku game, this process would take about 7 iterations. Then you will have a kind of "local minimum", where the rules can be applied to get to a solution.
This is far from perfect, as it could well be there is some other cell that could be cleared, while still allowing the rules to work towards a solution. So, if you want to refine this search, you could add some additional iterations to remove random cells as long as the resulting board can still be solved by applying the rules.