簡體   English   中英

為什么我在 C# 中的數獨求解器不起作用?

[英]Why is my sudoku solver in C# not working?

這是我的第一篇文章,如果我做錯了,我深表歉意。 幾個月前我開始在 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;
        }   
        
    }
}

最后打印 function:

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

編輯:

代碼導致打印原始未解決的數獨板兩次。 它最初似乎工作正常,但在某個地方,一切都只是重置為原始未解決的板。

存在三個問題。

第一個是在 sgmoore 的回答中,數獨是無效的。 嘗試從互聯網復制現有的數獨。

第二個是在 ErrorCheck class 中:

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

您必須反轉矩陣的兩個索引才能獲得正確的框。

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

第三個錯誤出現在程序 class 中:您在單元格中輸入了第一個有效數字。 在數獨中,您必須輸入唯一有效的數字。 因此,在我看來,對於每個單元格,您必須檢查所有九個數字並將所有可能的值保存在一個列表中,然后如果只有一個可能的值,則將其放入。 這種方法對於簡單的數獨來說已經足夠了,但如果復雜度增加,您將不得不使用其他高級技術,例如雙對或 X-Wing。

除了錯誤,我認為您的代碼非常清晰易讀。 我要做的唯一更改是在程序 class 中用“row”和“col”重命名“i”和“j”。

謝謝大家的回復。 正如 Astrid 所建議的,我在調試器中花費了更多時間並修復了一堆邏輯錯誤。 我搞混了|| 以 && 為例(我認為這些錯誤現在已被刪除)。 盡管如此,這還不足以讓代碼正常工作。 因此,我將回溯移出驅動程序 function 中的 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() 方法不能在驅動程序方法之外工作。 如果有人有線索,請隨時回復。 如果沒有,無論如何感謝您對您表現出的興趣。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM