我正在尝试创建一个数独游戏,对于那些不知道它是什么的游戏。你有一个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;
}
}
答案 0 :(得分:3)
它不会突破,它会陷入无限循环。
如果我正确阅读,看起来你正在尝试创建一个数独游戏板。麻烦的是,它并不像你想象的那么简单。据我所知,你只是通过它填充随机未使用的值;问题是,并非每一个这样的配置都是有效的 - 大多数时候你的随机条目最终会让你进入一个无法解决的板配置。
然后,当您尝试为某个方块选择随机值时,内部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
的位置 - 看看是怎么发生的?
使用随机未使用的数字填充网格与填写“答案”不一样 - 想一想,如果你采用常规的数独游戏并尝试通过随机放置解决它满足每个空白方块规则的数字 - 你很快就会陷入困境,对吧?这正是您的计划正在发生的事情。
我建议你首先尝试编写一个数独的解算器,这需要一个有效的初始板配置并尝试解决它 - 然后你可以继续尝试自己制作板。
答案 1 :(得分:1)
如果在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);
给它一个镜头,看它是否有效!
答案 2 :(得分:1)
我调整了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];
}
并得到一个例外,因为usedNums传递了10个元素,这意味着没有解决方案。尝试使用此方法,您将看到问题。