C#Sudoku难题解算器在尝试回溯时被卡住以避免错误值

时间:2016-11-23 03:42:53

标签: c# recursion backtracking sudoku

我试图更好地理解递归,并且我正在研究一个应该通过迭代拼图中的每个单元并从可能列表中尝试一个值来解决数独难题的程序值。在它下降一个值后,它会检查这样做是否解决了这个难题。如果没有,它会继续添加值并检查这样做是否解决了这个难题。但是有一个问题 - 我可以在我的应用程序的GUI中看到它最终会混淆或卡住,并开始一遍又一遍地尝试相同的值插入。例如,这里有一些日志显示它被卡住的例子:

Possible values: F
Old string: 086251B7D93+++C4
New string: 086251B7D93F++C4

正如您所看到的,它正在寻找在3之后可能进入单元格的值,而不会违反行,列或框约束。唯一可能的值是F,因此它将它放在那里。但是它会一遍又一遍地做同样的事情,并且随机开始尝试编辑其他行中的其他单元格,即使第一行中仍然存在+。它会尝试将行向下编辑几行,然后在执行此操作之间进行交换,然后重复尝试同一场景,直到应用程序崩溃,因为Visual Studio认为是ContextSwitchDeadlock错误。

我的算法错过了什么?这是我试图填写数独谜题的方法:

public bool SolveGrid(List<Row> rows, List<Box> boxes)
{
    textBox1.Clear()
    foreach (var row in rows)
    {
        textBox1.AppendText(row.content + "\n");
    }

    if (ValidatorAgent.IsGridSolved(rows, boxes))
    {
        textBox2.AppendText("Success!");
        successGrid = rows; 
        return true;
    }

    foreach (var row in rows)
    {
        foreach (var cell in row.content)
        {
            if (cell.Equals('+'))
            {
                var possibleValues = availableValues.Where(v => !ValidatorAgent.AreGridConstraintsBreached(cell, v, row, rows, boxes)).ToList();
                if (!possibleValues.Any())
                {
                    return false;
                }
                Console.WriteLine("Possible values: ");
                possibleValues.ForEach(v => Console.Write(v.ToString()));

                List<char> values = new List<char>();
                possibleValues.ForEach(v => values.Add(v));

                foreach (var possibleValue in values)
                {
                    var oldContent = row.content;
                    var stringBuilder = new StringBuilder(row.content);
                    var indexToChange = row.content.IndexOf(cell);
                    stringBuilder[indexToChange] = possibleValue;

                    Console.WriteLine("Old string: " + oldContent);
                    Console.WriteLine("New string: " + stringBuilder.ToString());
                    var alteredPuzzle = BuilderAgent.BuildPuzzleCopy(rows);
                    alteredPuzzle.Single(r => r.yCoord == row.yCoord).content = stringBuilder.ToString();
                    var newBoxes = BuilderAgent.BuildBoxes(alteredPuzzle);
                    SolveGrid(alteredPuzzle, newBoxes);
                }
            }
        }
   }

   return false;
}

我非常有信心我的IsGridSolved方法正常工作,因为我已经在拼图解决方案上进行了测试,并发现它报告了拼图是否已经解决。我还使用单元测试以及通过观察代码的结果来测试我的AreGridConstraintsBreached方法,因此我对该代码非常有信心。它基本上检查单元的潜在值是否是冗余的,因为相关的行,列或框已经具有该值。在Sudoku中,当您放置一个值时,您需要确保值1)在行中已经存在2)并不存在于列中且3)已经存在在细胞周围的小盒子里。我觉得我在算法本身中遗漏了一些明显的东西,并且它没有正确地回溯。我试图摆弄SolveGrid方法,以便它接收一个基于availableValues的validValues列表,并进行一些修剪,以便在每次递归调用SolveGrid之后修剪失败的值但是没有。做任何事情,除了让谜题甚至达到目前的水平。任何提示将不胜感激。

0 个答案:

没有答案