虽然循环卡在代码

时间:2017-04-01 15:17:35

标签: c# loops multidimensional-array random

我需要帮助,我让我的朋友帮我调试这段代码,我们发现代码停在代码上的随机点,有时是第一次循环,有时是最后一次循环,依此类推。 代码只是制作一个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);

2 个答案:

答案 0 :(得分:1)

这些循环看起来很致命:

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,它将永远循环播放。

答案 1 :(得分:1)

这不是一个真正的答案,但希望它可以帮助您调试程序。在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);

(请注意,您可以简化此操作,因为行除以3然后乘以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. 从每行,每列,每个数字1-9开始
  2. 从单元格的可用数字列表中,随机分配其中一个,一次分配一个单元格
  3. 从该行,列和块
  4. 的可用数字中删除该数字
  5. 如果我们遇到没有可用于该单元的有效号码的情况,请重置所有内容并重试。
  6. 请注意,这可能会运行并且永远不会完成,但在我的测试中,它通常会在不到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();
    }
    

    输出继电器:

    enter image description here