繁体   English   中英

嵌套循环意外爆发

[英]Nested loops break out unexpectedly

我正在尝试为那些不知道它是什么的用户创建数独游戏。 您有一个9x9的框,需要用1-9之间的数字填充,每个数字在其行和列中都必须是唯一的,并且在3x3框中也必须是唯一的。 我最终在二维数组中进行循环加载。

但是在某个时刻,它只是停止了,没有任何异常,只是爆发了,什么也没有发生,而且它并不总是在同一位置,而是总是超过一半。

我至少期待一个堆栈溢出异常。

这是我的代码:

public class Engine
{
    public int[,] Create()
    {
        int[,] outer = new int[9, 9];


        for (int i = 0; i < 9; i++)
        {
            for (int j = 0; j < 9; j++)
            {
                 outer[i, j] = GetRandom(GetUsed(outer, i, j));
            }
        }

        return outer;

    }

    List<int> GetUsed(int[,] arr, int x, int y)
    {
        List<int> usedNums = new List<int>();
        for (int i = 0; i < 9; i++)
        {
            if (arr[x, i] != 0 && i != y)
            {
                if(!usedNums.Contains(arr[x, i]))
                    usedNums.Add(arr[x, i]);
            }
        }

        for (int i = 0; i < 9; i++)
        {
            if (arr[i, y] != 0 && i != x)
            {
                if (!usedNums.Contains(arr[i, y]))
                    usedNums.Add(arr[i, y]);
            }
        }

        int x2 = 9 - (x + 1);
        int y2 = 9 - (y + 1);

        if (x2 <= 3)
            x2 = 2;
        else if (x2 > 3 && x2 <= 6)
            x2 = 5;
        else x2 = 8;

        if (y2 <= 3)
            y2 = 2;
        else if (y2 > 3 && y2 <= 6)
            y2 = 5;
        else y2 = 8;

        for (int i = x2 - 2; i < x2; i++)
        {
            for (int j = y2 - 2; j < y2; j++)
            {
                if (arr[i, j] != 0 && i != x && j != y)
                {
                    if (!usedNums.Contains(arr[i, j]))
                        usedNums.Add(arr[i, j]);
                }
            }
        }

        return usedNums;
    }

    int GetRandom(List<int> numbers)
    {
        Random r;
        int newNum;
        do
        {
            r = new Random();
            newNum = r.Next(1, 10);
        } while (numbers.Contains(newNum));

        return newNum;
    }

}

它没有爆发 ,它陷入了无限循环。

如果我没看错,似乎您正在尝试创建数独板以继续玩。 麻烦的是,这并不像您想的那么简单。 据我所知,您只是在用随机未使用的值填充它; 问题是,并非所有这样的配置都是有效的-大多数情况下,您的随机输入最终会使您陷入无法解决的电路板配置中。

然后,当您尝试为某个正方形选择随机值时,内部的GetRandom函数将无限循环以尝试选择一个数字(因为getUsed已经具有所有1 - 9 ,所以do..while将永远不会退出)。

亲自查看此内容的简单方法:在GetRandom函数顶部添加以下内容:

if (Enumerable.Range(1, 9).All(i => numbers.Contains(i)))
    Console.WriteLine("PROBLEM!");

现在,如果numbers全是1到9,它会告诉您。 (然后仍然会陷入无限循环,但这是您的问题;))

另外,作为一个旁注,保持这种new Random()对象不是一个好习惯。 最好只拥有一个Random实例,在构造函数中对其进行初始化,然后继续使用Random.Next 至少,在函数顶部具有Random r = new Random() ,然后在循环内部具有r.Next

好的,这是一个非常简单的示例,仅在前两行就处于无法解决的位置:

123|456|789
456|123|X

标记X的位置上没有可用的有效数字-看看情况如何?
用随机未使用的数字填充网格与用“答案”填充网格不同-这样思考,如果您使用常规的数独游戏并尝试通过仅将满足条件的任意随机数字放入每个数独游戏来解决该问题空白方块-您很快就会陷入困境,对吧? 这就是您的程序正在发生的事情。

我建议您先尝试编写一个数独求解器 ,它需要有效的初始电路板配置并尝试对其进行求解-然后您可以继续尝试自己制作电路板。

如果在GetRandom ,您的numbers列表已经满了1-10,会怎样?

我认为您的程序在GetRandom方法中处于冻结状态,因为您要告诉它无限循环,直到它找到不在列表中的1到10之间的数字为止。

您应该告诉它寻找0到9 (假设0为“空”),并且如果它得到0,则允许它离开,因为董事会上只有1-9的物质。 默认情况下,列表中默认为0,因此可以忽略它。

do
{
   r = new Random();
   newNum = r.Next(0, 9);
} while (numbers.Contains(newNum) && newNum != 0);

试一试,看看是否有效!

我调整了GetRandom以获得性能

static int GetRandom(List<int> usedNums)
{
    List<int> missingNums = new List<int>();
    for (int i = 1; i <= 10; i++)
    {
        if (!usedNums.Contains(i))
            missingNums.Add(i);
    }

    Random r = new Random();
    int rMissingNumIndex = r.Next(0, missingNums.Count - 1);

    return missingNums[rMissingNumIndex];
}

并由于使用了10个元素而传递了usedNums,因此出现了异常,这意味着没有解决方案。 尝试改用此方法,您会发现问题所在。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM