为了让您了解我的意思,请为您自己创建一个枚举,如下所示:
[Flags]
public enum SudokuValue
{
None = 0,
One = 1,
Two = 2,
Three = 4,
Four = 8,
Five = 16,
Six = 32,
Seven = 64,
Eight = 128,
Nine = 256
}
Flags 属性很重要,我们稍后会看到。您现在可以在类似以下的类中利用此枚举:
public class SudokuHelper
{
private SudokuValue[,] gridValues;
private bool[,] gridFills;
public SudokuHelper()
{
gridValues = new SudokuValue[9, 9];
gridFills = new bool[9, 9];
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
gridValues[i, j] = (SudokuValue)511;
gridFills[i, j] = false;
}
}
}
public void UpdateGrid(int row, int col, int val)
{
gridFills[row, col] = true;
SudokuValue sudoku = (SudokuValue)(Math.Pow(2, val - 1));
gridValues[row, col] = sudoku;
//Update same col
for (int i = 0; i < 9; i++)
{
if (!gridFills[i, col] && gridValues[i, col].HasFlag(sudoku))
{
gridValues[i, col] -= sudoku;
}
}
//Update same col
for (int i = 0; i < 9; i++)
{
if (!gridFills[row, i] && gridValues[row, i].HasFlag(sudoku))
{
gridValues[row, i] -= sudoku;
}
}
//Update same block
int startBlockRow;
int startBlockCol;
if (row < 3)
{
startBlockRow = 0;
}
else if (row < 6)
{
startBlockRow = 3;
}
else
{
startBlockRow = 6;
}
if (col < 3)
{
startBlockCol = 0;
}
else if (col < 6)
{
startBlockCol = 3;
}
else
{
startBlockCol = 6;
}
for (int i = startBlockRow; i < startBlockRow + 3; i++)
{
for (int j = startBlockCol; j < startBlockCol + 3; j++)
{
if (!gridFills[i, j] && gridValues[i,j].HasFlag(sudoku))
{
gridValues[i, j] -= sudoku;
}
}
}
}
public string GetStringRepresentation(int row, int col)
{
var sB = new StringBuilder();
if (gridValues[row, col].HasFlag(SudokuValue.One))
{
sB.Append(",1");
}
if (gridValues[row, col].HasFlag(SudokuValue.Two))
{
sB.Append(",2");
}
if (gridValues[row, col].HasFlag(SudokuValue.Three))
{
sB.Append(",3");
}
if (gridValues[row, col].HasFlag(SudokuValue.Four))
{
sB.Append(",4");
}
if (gridValues[row, col].HasFlag(SudokuValue.Five))
{
sB.Append(",5");
}
if (gridValues[row, col].HasFlag(SudokuValue.Six))
{
sB.Append(",6");
}
if (gridValues[row, col].HasFlag(SudokuValue.Seven))
{
sB.Append(",7");
}
if (gridValues[row, col].HasFlag(SudokuValue.Eight))
{
sB.Append(",8");
}
if (gridValues[row, col].HasFlag(SudokuValue.Nine))
{
sB.Append(",9");
}
//remove leading comma
return sB.ToString().Substring(1);
}
}
构造函数创建一个 SudokuValues 的初始二维数组,并用一个初始值填充它,该初始值表示所有可能的值 1 ... 9 (511)。请注意,虽然 511 未在枚举中列出,但我们仍然可以将其转换为 SudokuValue。这是因为默认情况下所有枚举都是整数。它还创建并填充一个二维布尔数组,以表示已为其提供值的那些单元格。
如果在其中一个单元格中输入了值,它会提供一种更新网格中值的方法。此方法采用三个参数,更新单元格的行和列,以及作为整数输入到单元格中的值(必须是 1 .. 9)。首先,它更新网格中的单元格本身(有效地消除所有其他可能性),并设置布尔标志。然后,它继续删除在同一列、同一行和同一 3x3 块中的其他单元格中可能输入的值。在这里,它在删除值之前检查之前的值是否仍然存在(使用 HasFlags 方法 - 可用,因为我们在上面设置了 Flags 属性),以避免单元格被输入两次。这里有一个小技巧:输入的值 (1 .. 9) 可以通过将其减 1 然后取 2 的结果幂来转换为其等效的枚举。
最后,帮助器提供任何给定单元格包含的内容的文本表示(如果设置了单个值,或者剩余的可能性)。
要对此进行测试,我们可以这样做(我使用 WinForms 应用程序进行测试,因此使用 MessageBox.Show()):
var sH = new SudokuHelper();
for (int i = 0; i < 9; i++)
{
var sB = new StringBuilder();
for (int j = 0; j < 9; j++)
{
sB.Append(" ; " + sH.GetStringRepresentation(i, j));
}
MessageBox.Show($"Row {i}: " + sB.ToString().Substring(3));
}
sH.UpdateGrid(4, 7, 9);
for (int i = 0; i < 9; i++)
{
var sB = new StringBuilder();
for (int j = 0; j < 9; j++)
{
sB.Append(" ; " + sH.GetStringRepresentation(i, j));
}
MessageBox.Show($"Row {i}: " + sB.ToString().Substring(3));
}
如果是我构建这个应用程序,我会使用一个 9x9 的 TextBoxes 网格(而不是 DataGridView),全部带有一个 KeyDown/KeyPress 事件,如果其中一个键 1 .. 调用 SudokuHelper 来更新网格9 被按下。但也许您出于其他原因需要 DataGridView?