Excel中的数独生成器和求解器

数独是一种流行的数字游戏,它要求玩家在9x9的网格中填入数字,使得每行、每列以及每个3x3的小方格内的数字均不重复。Excel作为一个强大的电子表格工具,非常适合用来处理这种基于网格的数字游戏。本文将介绍如何使用C#语言结合Excel-DNA库,在Excel中创建数独的生成器和求解器。

Excel-DNA是一个开源库,它允许开发者将.NET代码直接嵌入到Excel中,从而扩展Excel的功能。通过这种方式,可以创建自定义的Excel函数,用于生成和解决数独谜题。这些函数可以直接在Excel单元格中调用,使得数独游戏的生成和求解变得异常简单。

使用代码

在Excel中,实现了几个函数来解决数独谜题:

  • acq_sudoku_generate - 生成随机数独谜题。可选地接受一个种子参数。如果未指定种子,它将使用计算机的时钟作为种子。该函数产生一个9x9的矩阵,因此需要在Excel中作为数组公式输入(Ctrl+Shift+Enter)。
  • acq_sudoku_solve - 解决数独谜题。接受9x9的数独谜题作为输入参数,并产生解决后的9x9矩阵。需要在Excel中作为数组公式输入(Ctrl+Shift+Enter)。
  • acq_sudoku_solution_count - 返回指定谜题的可能解的数量。通常,应该只有一个解,但如果手动从谜题中删除数字,可能的解的数量会增加。该函数在找到1024个解后停止计数。

数独生成器的实现

数独生成器的实现位于ACQ.Math.Sudoku.Generate中。通过Excel包装函数调用它,首先检查种子参数。生成函数产生一个9x9的数组。在这个数组中,元素等于零代表空的数独单元格。由于不希望Excel显示零,将整数数组转换为对象数组,并将零替换为空字符串。

public static object[,] acq_sudoku_generate(object seed) { int[,] grid; if(seed != null && seed is double) { grid = ACQ.Math.Sudoku.Generate((int)(double)seed); } else { grid = ACQ.Math.Sudoku.Generate(); } object[,] result = new object[grid.GetLength(0), grid.GetLength(1)]; for(int i = 0; i < grid.GetLength(0); i++) { for(int j = 0; j < grid.GetLength(1); j++) { if(grid[i, j] == 0) result[i, j] = String.Empty; else result[i, j] = grid[i, j]; } } return result; }

数独求解器的实现

求解器使用了一个非常基础的递归算法。函数返回所有解,直到指定的最大值(代码中为1)。

public static object[,] acq_sudoku_solve(object[,] grid) { const int size = 9; int[,] sudoku = acq_sudoku_convertgrid(grid, size); if(sudoku != null) { List solutions = new List(); ACQ.Math.Sudoku.Solve(sudoku, solutions, 1); if(solutions.Count > 0) { return ExcelHelper.BoxArray(solutions[0]); } } return ExcelHelper.CreateArray(1, 1, ExcelError.ExcelErrorNull); }

数独解的数量

以下代码用于返回数独谜题的可能解的数量。该函数的实现与acq_sudoku_solve几乎相同。这个函数可以用来跟踪在Excel中手动解决数独谜题的进度。当犯错时,可能的解的数量会变成零。

public static int acq_sudoku_solution_count(object[,] grid) { const int size = 9; const int max_count = 1024; int[,] sudoku = acq_sudoku_convertgrid(grid, size); int count = 0; if(sudoku != null) { List solutions = new List(); ACQ.Math.Sudoku.Solve(sudoku, solutions, max_count); count = solutions.Count; } return count; }

算法细节

用于解决数独谜题的算法是简单的递归。存在更好的算法,因此这里没有列出(搜索代码中的ACQ.Math.Sudoku.Solve以获取更多细节)。

谜题生成稍微有趣一些。首先,使用Knuth洗牌(也称为Fisher-Yates洗牌)来填充对角线3x3的块(如图示)。这些块是独立的,因此可以随机填充。然后解决谜题,并在仍然存在唯一解的情况下随机移除数字。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485