2010-05-15 51 views
1

我正在尝试创建一个数独游戏,对于那些不知道它是什么的人。你有一个9x9的盒子,需要用1-9的数字填充,每一个数字在其行和列中必须是唯一的,并且在3x3盒子中也是如此。我结束了在2维数组中循环的负载。嵌套环意外突然

但是在某个时候,它只是停下来,没有任何例外,只是爆发,没有任何反应,它并不总是处于相同的位置,但总是走到一半。

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

这里是我的代码:

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

你有没有试过,看看它停在哪里?另外,我们在谈论哪个功能?这里有半打循环.. – tzaman 2010-05-15 10:52:57

+0

我正在第一个循环的第一个循环中“创建()” 它永远不会相同,有时在4,7或5,3,总是处于不同的位置,它似乎很随机。 – 2010-05-15 11:00:43

+0

非常... *随机*你说? (我无法抗拒) – Phil 2010-05-15 11:23:06

回答

3

这不是打破了,它陷入无限循环。

如果我正在阅读这个权利,看起来你正在尝试创建一个Sudoku板来玩。麻烦是,它并不像你想象的那么简单。据我所知,你只是通过它填充随机未使用的值;麻烦的是,并不是每个这样的配置都是有效的 - 大多数时候你的随机条目最终会让你陷入无法解决的电路板配置。

然后,当您尝试选择一些方形的随机值,内GetRandom功能只会无限循环试图挑一些(因为getUsed将已经拥有的1 - 9do..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 - 怎么看这事?
用随机未使用的数字填充网格与用“答案”填充网格不同 - 想想这样,如果你采用了常规的数独游戏,并试图通过将任何随机数字满意的方式解决10每个空白广场的规则 - 你很快就会卡住了,对吧?这正是你的程序发生的情况。

我建议你尝试写一个数独求解首先,需要一个有效的初始板配置,并试图解决它 - 那么你可以继续尝试自己做板。

+0

+1表示这种创建电路板的方式会导致无法解决/多个解决方案电路板。 – Phil 2010-05-15 11:21:45

+0

嗯,起初我试图用答案填充它,然后我将使用它并删除一些值。如果数字在其行,列和3x3框中独一无二,它如何无法解决或具有多种解决方案? – 2010-05-15 11:32:32

+0

请参阅我的编辑回答。 – tzaman 2010-05-15 13:30:04

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); 

给一个镜头,看看它是否工作!

+0

minValue时,maxValue不应包含在范围内。 我试过了,以防万一,它用0填充我的数组。 我不明白的是它怎么会进入无限循环。我看到它的方式是填充已在单元格的行,列和框中使用的数字列表,因此该方法不会返回它,在内部循环的最后一次迭代中,它应该有一个数字, 9没有用过,还是我错过了什么? 请注意,我不是在质疑你的推理。 – 2010-05-15 11:41:29

+0

你有没有试过@ tzaman的建议把检查放在'GetRandom'的顶部?你的代码没有收集1个单元格的数字列表(总是只有1个数字)。它收集在行,列和3x3封闭框中使用的数字列表。在第一行中,不存在任何问题。之后,所有投注都关闭。第二行的最后一个元素可能有问题,因为前面有8个单元格,上面有1个单元格,左上角有1个单元格。这就是'Random.Next'中允许的10个数字。 – Phil 2010-05-15 12:34:15

+0

我打印了它设法创建的数字,并注意到了该问题。 – 2010-05-15 14:25:13

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个元素传递,这意味着不可能有任何解决方案。尝试使用这种方法,而你会看到这个问题。

+0

这不是说问题出现在GetUsed函数中吗? – 2010-05-15 11:52:21