虽然循环卡在代码
随机点我需要帮助,我有我的朋友来帮我调试此代码,并且我们发现代码停止在代码上的随机点,有时在第一个循环,有时在最后一个循环等等。代码只是制作一个应用了所有规则的9x9数独板。当我分别测试每个模块时,它工作并打印出了一个出色的数独板,但是这里的问题在于某种程度上被卡住了。 帮助将不胜感激。虽然循环卡在代码
int[,] helpblock = new int[10, 10];
int[,] helplines = new int[10, 10];
int[,] helpcols = new int[10, 10];
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
helplines[i, j] = 0;
helpcols[i, j] = 0;
helpblock[i, j] = 0;
}
}
Random rnf = new Random();
int help1;
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
help1 = rnf.Next(1, 10);
if (i == 0 || i == 1 || i == 2) {
if (j == 0 || j == 1 || j == 2) {
if (helplines[i, help1] != 0 || helpblock[0, help1] != 0 || helpcols[j, help1] != 0) {
while (helplines[i, help1] != 0 || helpblock[0, help1] != 0 || helpcols[j, help1] != 0) {
System.Threading.Thread.Sleep(1);
help1 = rnf.Next(1, 10);
}
}
map[i, j] = help1;
helplines[i, help1]++;
helpcols[j, help1]++;
helpblock[0, help1]++;
} else if (j == 3 || j == 4 || j == 5) {
if (helplines[i, help1] != 0 || helpblock[1, help1] != 0 || helpcols[j, help1] != 0) {
while (helplines[i, help1] != 0 || helpblock[1, help1] != 0 || helpcols[j, help1] != 0) {
System.Threading.Thread.Sleep(1);
help1 = rnf.Next(1, 10);
}
}
map[i, j] = help1;
helplines[i, help1]++;
helpcols[j, help1]++;
helpblock[1, help1]++;
} else if (j == 6 || j == 7 || j == 8) {
if (helplines[i, help1] != 0 || helpblock[2, help1] != 0 || helpcols[j, help1] != 0) {
while (helplines[i, help1] != 0 || helpblock[2, help1] != 0 || helpcols[j, help1] != 0) {
System.Threading.Thread.Sleep(1);
help1 = rnf.Next(1, 10);
}
}
map[i, j] = help1;
helplines[i, help1]++;
helpcols[j, help1]++;
helpblock[2, help1]++;
}
} else if (i == 3 || i == 4 || i == 5) {
if (j == 0 || j == 1 || j == 2) {
if (helplines[i, help1] != 0 || helpblock[3, help1] != 0 || helpcols[j, help1] != 0) {
while (helplines[i, help1] != 0 || helpblock[3, help1] != 0 || helpcols[j, help1] != 0) {
System.Threading.Thread.Sleep(1);
help1 = rnf.Next(1, 10);
}
}
map[i, j] = help1;
helplines[i, help1]++;
helpcols[j, help1]++;
helpblock[3, help1]++;
} else if (j == 3 || j == 4 || j == 5) {
if (helplines[i, help1] != 0 || helpblock[4, help1] != 0 || helpcols[j, help1] != 0) {
while (helplines[i, help1] != 0 || helpblock[4, help1] != 0 || helpcols[j, help1] != 0) {
System.Threading.Thread.Sleep(1);
help1 = rnf.Next(1, 10);
}
}
map[i, j] = help1;
helplines[i, help1]++;
helpcols[j, help1]++;
helpblock[4, help1]++;
} else if (j == 6 || j == 7 || j == 8) {
if (helplines[i, help1] != 0 || helpblock[5, help1] != 0 || helpcols[j, help1] != 0) {
while (helplines[i, help1] != 0 || helpblock[5, help1] != 0 || helpcols[j, help1] != 0) {
System.Threading.Thread.Sleep(1);
help1 = rnf.Next(1, 10);
}
}
map[i, j] = help1;
helplines[i, help1]++;
helpcols[j, help1]++;
helpblock[5, help1]++;
}
} else if (i == 6 || i == 7 || i == 8) {
if (j == 0 || j == 1 || j == 2) {
if (helplines[i, help1] != 0 || helpblock[6, help1] != 0 || helpcols[j, help1] != 0) {
while (helplines[i, help1] != 0 || helpblock[6, help1] != 0 || helpcols[j, help1] != 0) {
System.Threading.Thread.Sleep(1);
help1 = rnf.Next(1, 10);
}
}
map[i, j] = help1;
helplines[i, help1]++;
helpcols[j, help1]++;
helpblock[6, help1]++;
} else if (j == 3 || j == 4 || j == 5) {
if (helplines[i, help1] != 0 || helpblock[7, help1] != 0 || helpcols[j, help1] != 0) {
while (helplines[i, help1] != 0 || helpblock[7, help1] != 0 || helpcols[j, help1] != 0) {
System.Threading.Thread.Sleep(1);
help1 = rnf.Next(1, 10);
}
}
map[i, j] = help1;
helplines[i, help1]++;
helpcols[j, help1]++;
helpblock[7, help1]++;
} else if (j == 6 || j == 7 || j == 8) {
if (helplines[i, help1] != 0 || helpblock[8, help1] != 0 || helpcols[j, help1] != 0) {
while (helplines[i, help1] != 0 || helpblock[8, help1] != 0 || helpcols[j, help1] != 0) {
System.Threading.Thread.Sleep(1);
help1 = rnf.Next(1, 10);
}
}
map[i, j] = help1;
helplines[i, help1]++;
helpcols[j, help1]++;
helpblock[8, help1]++;
}
}
}
}
PrintSudoku(map);
这不是一个真正的答案,但希望它可以帮助您调试程序。里面你for
循环您有if
报表一大堆,看起来是这样的:
if (i == 0 || i == 1 || i == 2) {
if (j == 0 || j == 1 || j == 2) {
它看起来像你使用这个逻辑,以确定哪些阻碍你的,因为这是一个数组,你正在使用第一个索引的硬编码值。
不要这样做,请考虑使用基于当前行和列值的公式计算块。
网格目前看起来是这样的:
| 0 1 2 | 3 4 5 | 6 7 8 |
--+-------+-------+--------
0 | | | |
1 | [0] | [1] | [2] |
2 | | | |
--+-------+-------+--------
3 | | | |
4 | [3] | [4] | [5] |
5 | | | |
--+-------+-------+--------
6 | | | |
7 | [6] | [7] | [8] |
8 | | | |
---------------------------
什么,你可能会注意到的是,如果你把行号和3做一个整数除法,你会得到Block
行数(0,1 ,或2)。将此数字乘以3会得到每行中的第一个块(0,3和6)。现在,如果我们将当前列和整数除以3,我们将得到当前块列(0,1或2)。添加“块行”到“块列”,那么将会给我们的块索引:
int block = ((row/3) * 3) + (column/3);
(请注意,它看起来像你可以简化这个,因为行被分成三部分,然后乘以三,但请记住,整数除法舍去,所以2/3 == 0
,而不是.6667
)
通过这种方式计算块,您可以大幅减少你必须走过的行数。
此外,使用一些更有意义的变量名将有助于提高可读性。
我将你的代码简化为我认为完全一样的东西。也许这会帮助你分析:
int[,] blocks = new int[10, 10];
int[,] rows = new int[10, 10];
int[,] columns = new int[10, 10];
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
rows[i, j] = 0;
columns[i, j] = 0;
blocks[i, j] = 0;
}
}
Random rnd = new Random();
int randomNumber;
for (int row = 0; row < 9; row++)
{
for (int column = 0; column < 9; column++)
{
int block = ((row/3) * 3) + (column/3);
randomNumber = rnd.Next(1, 10);
while (rows[row, randomNumber] != 0 ||
blocks[block, randomNumber] != 0 ||
columns[column, randomNumber] != 0)
{
System.Threading.Thread.Sleep(1);
randomNumber = rnd.Next(1, 10);
}
map[row, column] = randomNumber;
rows[row, randomNumber]++;
columns[column, randomNumber]++;
blocks[block, randomNumber]++;
}
}
玩这个当然,以后,我感兴趣的问题。下面是我想出了解决这个问题,这是一个很值得穷举法:
- 开始用数字1-9可用于每个行,列,并阻止
- 从可用列表数字为一个单元格,随机分配其中一个,一次一个单元格
- 从该行,列和块的可用数字中删除该数字
- 如果我们遇到没有有效数字的情况可用于单元格,重置所有内容并重试。
请注意,这可能会运行,永远不会完成,但在我的测试中,它通常会在少于400次尝试(从用户的角度来看相对较快)中找到解决方案。
我做的不同之处在于,我不是使用数组来存储行/列/块信息,而是决定使用存储行/列/块索引作为关键字的Dictionary<int, List<int>>
,以及每个关键字的值是该索引的可用数字的List
。
然后在我们的循环中,我只将当前行,列和块的剩余可用数字交叉到List
。然后我在该列表中选择一个随机索引并将该值分配给单元格(并将其从该行,列和块中的可用项目中移除)。
我还添加了一些日志记录来找出在找到解决方案之前失败了多少次。
下面的代码,这也打印在最后的解决方案:
static void Main()
{
int[,] map = new int[9, 9];
var blocks = new Dictionary<int, List<int>>();
var rows = new Dictionary<int, List<int>>();
var columns = new Dictionary<int, List<int>>();
// initialize lists of available numbers
for (int i = 0; i < 9; i++)
{
blocks.Add(i, new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 });
rows.Add(i, new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 });
columns.Add(i, new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 });
}
Random rnd = new Random();
int failCount = 0;
// For each row
for (int row = 0; row < 9; row++)
{
// For each column in this row
for (int column = 0; column < 9; column++)
{
// Calculate block based on current row and column
int block = ((row/3) * 3) + (column/3);
// Get set of available numbers for this cell by getting the intersection
// of available numbers for the row, column, and block
var availableItems =
rows[row].Intersect(
columns[column].Intersect(
blocks[block])).ToList();
// If we reach a point where there are no availableItems, then this is
// not a valid Sudoku pattern. Reset everything and try again
if (availableItems.Count == 0)
{
failCount++;
Console.WriteLine($"Failed {failCount} times. Trying again...");
// Reset to the first cell
row = 0;
column = 0;
block = 0;
// Initialize data
for (int i = 0; i < 9; i++)
{
blocks[i] = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
rows[i] = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
columns[i] = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
}
availableItems = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
}
// Grab a number from the available numbers by choosing a random index
var randomNumber = availableItems[rnd.Next(0, availableItems.Count)];
// Update our map with this item
map[row, column] = randomNumber;
// Remove this item from our lists
rows[row].Remove(randomNumber);
columns[column].Remove(randomNumber);
blocks[block].Remove(randomNumber);
}
}
// Print our Sudoku map:
Console.WriteLine(new string('-', 25));
for(int i = 0; i < 9; i++)
{
Console.Write("|");
for (int j = 0; j < 9; j++)
{
Console.Write($" {map[i, j]}");
if ((j + 1) % 3 == 0) Console.Write(" |");
}
Console.WriteLine();
if ((i + 1) % 3 == 0) Console.WriteLine(new string('-', 25));
}
Console.Write("\nDone!\nPress any key to exit...");
Console.ReadKey();
}
输出继电器:
谢谢你,帮助我 – EliKatz
这些循环看起来致命的:
while (helplines[i, help1] != 0 || helpblock[5, help1] != 0 || helpcols[j, help1] != 0) {
System.Threading.Thread.Sleep(1);
help1 = rnf.Next(1, 10);
}
如果help1
新值不会改变while
条件false
,它会永远循环下去。
在C# – EliKatz
请注明您所使用的语言进行编程。 – Rajesh
了解如何使用调试器。它会准确显示发生了什么,特别是当它“有时”发生时。还有,为什么只使用9x9时分配10x10数组? –