【问题标题】:Why is my sudoku solver in C# not working?为什么我在 C# 中的数独求解器不起作用?
【发布时间】:2022-09-23 03:15:20
【问题描述】:

这是我的第一篇文章,如果我做错了,我深表歉意。几个月前我开始用 python 编码,现在我已经转向 C#。为了学习回溯,我尝试编写数独求解器。但是,对于我的一生,我无法理解为什么我的代码不起作用。当然,有很多解决方案。我觉得我现在进步的最好方法是了解我在我的个人代码中缺少什么。所以,如果你有时间:

为什么我的代码不会返回一个已解决的数独板?我怀疑错误在于递归。

主程序:

using System;

namespace Sudoku
{
    class Program
    {
        static void Main(string[] args)
        {          
            
            var sudokuTemplate = new SudokuTemplate();
            var sudoku = sudokuTemplate.CreateSudoku();
            Print.print(sudoku);
            Console.WriteLine();
            Print.print(driver(sudoku));
        }    

        static int[,] driver(int[,] board)
        {
            var check = new ErrorCheck();

            for (int i = 0; i < 9; i++)
            {
                for (int j = 0; j < 9; j++)
                {
                    if (board[i,j] == 0)
                    {   
                        for (int n = 1; n <= 9; n++)
                        {
                            if (check.legal(board, i, j, n))
                            {
                                board[i, j] = n;  
                                driver(board); 
                            }   
                            else
                            {
                                board[i, j] = 0;
                            }                         
                        } 
                        return board;                      
                    }                  
                }
            }
            return board;
        }
    }
}

未解的数独

    namespace Sudoku
{
    class SudokuTemplate
    {
        public int[,] CreateSudoku()
        {
            var array = new int[,] 
            {
                {5,3,0,0,7,0,0,0,0},  
                {6,0,0,1,9,5,0,0,0},  
                {0,9,8,0,0,0,0,6,0},  
                {8,0,0,0,6,0,0,0,3},  
                {4,0,0,8,0,3,0,0,1},  
                {7,0,0,0,2,0,0,0,6},  
                {0,6,0,0,0,0,2,8,0},  
                {0,0,0,4,1,9,0,0,5},  
                {0,0,0,0,8,0,0,7,9}  
            };
            return array;
        }
    }
}

错误检查器查看数字 n 是否可以合法放置在板上:

namespace Sudoku
{
    public class ErrorCheck
    {
        public bool legal(int[,]array, int row, int col, int n)
        {   //check col & rw
            for (int i = 0; i < 9; i++)
            {
                if (array[row, i] == n)
                {
                    return false;
                }
                if (array[i, col] == n)
                {
                    return false;
                }
            }

            //check boxes
            int valRow = 0;
            if (row < 6 && row > 2)
            {
                valRow = 3;
            }
            else if (row < 9 && row > 5)
            {
                valRow = 6;
            }

            int valCol = 0;
            if (col < 6 && col > 2)
            {
                valCol = 3;
            }
            else if (col < 9 && col > 5)
            {
                valCol = 6;
            }
            
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    if (array[(j+valRow), (i+valCol)] == n)
                        {
                            return false;
                        }
                }
            }
            return true;
        }   
        
    }
}

最后是打印功能:

    namespace Sudoku
{
    class Print
    {
        public static void print(int[,] array)
        {
            // prints sudoku
            for (int i = 0; i < 9; i++)
            {
                for (int j = 0; j < 9; j++) 
                {
                    Console.Write(\"{0} \", array[i, j]);
                    Console.Write(\"|\");     
                }
                Console.WriteLine();
            }
            
        }
    }
}

编辑:

代码导致打印原始未解决的数独板两次。它最初似乎工作正常,但在某个地方,一切都只是重置为原始未解决的板。

  • 您是否遇到了异常,或者只是没有给出正确的结果?
  • 我得到错误的结果。该代码将原始未解决的数独打印两次。谢谢,我会在帖子中澄清。
  • 您是否尝试过调试并单步执行代码以查看其行为方式?
  • 是的,阿斯特丽德我试过了。它最初似乎工作正常。但是在递归循环的某个地方出了点问题。我不得不承认我没有点击整个事情,因为上帝知道这需要多长时间哈哈......

标签: c# solver sudoku


【解决方案1】:

存在三个问题。

第一个是 sgmoore 的回答,数独是无效的。尝试从互联网上复制现有的数独。

第二个是在 ErrorCheck 类中:

if (array[(i+valCol), (j+valRow)] == n)

您必须反转矩阵的两个索引才能获得正确的框。

if (array[(j+valRow), (i+valCol)] == n)

第三个错误出现在 Program 类中:您在单元格中输入了第一个有效数字。在数独中,您必须输入唯一有效的数字。因此,在我看来,对于每个单元格,您必须检查所有九个数字并将所有可能的值保存在一个列表中,然后如果只有一个可能的值,您就输入它。这种方法对于简单的数独来说已经足够了,但如果复杂度增加,您将不得不使用其他高级技术,如双对或 X-Wing。

除了错误,我认为您的代码非常清晰易读。我要做的唯一更改是在 Program 类中用“row”和“col”重命名“i”和“j”。

【讨论】:

  • 感谢您的回复和批评。我已根据您的前两点进行了更新,但仍然存在相同的问题。我会研究第三个建议,但我认为这需要一些时间。再次感谢 :)
【解决方案2】:

谢谢大家的回复。正如 Astrid 所建议的,我在调试器中花费了更多时间并修复了一堆逻辑错误。我搞混了||以 && 为例(我认为这些错误现在已被删除)。 尽管如此,这还不足以让代码正常工作。因此,我将回溯移出驱动程序函数中的 for 循环。这是因为我认为该方法可能会解决所有问题,然后自动将所有内容改写为 0。更改后,它看起来像这样:

static int[,] driver(int[,] board)
        {
            var check = new ErrorCheck();

            for (int row = 0; row < 9; row++)
            {
                for (int col = 0; col < 9; col++)
                {
                    if (board[row, col] == 0)
                    {   
                        for (int n = 1; n <= 9; n++)
                        {
                            if (check.legal(board, row, col, n))
                            {
                                board[row, col] = n;  
                                driver(board); 
                            }             
                        }                         
                        board[row, col] = 0;   
                        return board; 
                    }                  
                }
            }   
            return board;
        }

尽管如此,它还是没有奏效。我尝试通过打印控制台发生的事情来进行调试,但是我的打印函数没有打印方法中发生的事情!我尝试从方法和 BAM 中打印!它似乎奏效了。

static int[,] driver(int[,] board)
        {
            var check = new ErrorCheck();

            for (int row = 0; row < 9; row++)
            {
                for (int col = 0; col < 9; col++)
                {
                    if (board[row, col] == 0)
                    {   
                        for (int n = 1; n <= 9; n++)
                        {
                            if (check.legal(board, row, col, n))
                            {
                                board[row, col] = n;  
                                driver(board); 
                            }             
                        }                         
                        board[row, col] = 0;   
                        return board; 
                    }                  
                }
            }   
            Print.print(board); 
            return board;
        }

我没有按照 Samuele Coassin 的建议实现花哨的优化,但至少它似乎有效。但是,我不知道为什么 Print.print() 方法不能在驱动程序方法之外工作。如果有人有线索,请随时回复。如果没有,无论如何感谢您对您表现出的兴趣。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-05-09
    • 1970-01-01
    • 1970-01-01
    • 2012-02-29
    • 1970-01-01
    • 1970-01-01
    • 2014-08-18
    相关资源
    最近更新 更多