用于int [,]的数独求解器算法

时间:2013-05-21 13:51:48

标签: c# multidimensional-array int sudoku solver

大家好日子,

我一直在研究C#Sudoku Solver应用程序,但我真诚地低估了算法解决数独游戏的难度。我一直在网上搜索可以实现的算法,但是我没有找到一个简单易用的算法,我可以随时了解。

我找到了一个可以在我的应用程序中运行的算法,但是这个人正在使用一维数组来解决它。 我试图改变它以使其适用于多维数组,但我无法让它正常工作。

有人可以给我建议或告诉我如何更改代码以便它可以使用多维数组(int [,])吗?我似乎无法自己找到它。代码可在此处找到:http://blah.winsmarts.com/2007-1-sudoku_solver_in_c-.aspx

如果你有另一种算法可以使用int [,],那当然也很精彩。

自从我搜索了很长时间以来,非常感谢帮助。 提前谢谢!

2 个答案:

答案 0 :(得分:1)

您链接的代码已经逻辑上使用了2D数组,它只使用1D数组作为支持。改变这个:

private int[] vals = new int[81];
public int this[int row, int column]
{
    get { return vals[FindIndex(row, column)]; }
    set
    {
        vals[FindIndex(row, column)] = value;
    }
}

private int FindIndex(int row, int column)
{
    return (((column - 1) * 9) + row - 1);
}

要:

private int[,] vals = new int[9,9];
public int this[int row, int column]
{
    get { return vals[row - 1, column - 1]; }
    set
    {
        vals[row - 1, column - 1] = value;
    }
}

(当前代码的其余部分需要- 1,因为rowcolumn从1开始而不是0。)

答案 1 :(得分:0)

递归回溯,蛮力,算法。

public class SudokoSolver
{
    private readonly Grid _grid;

    public SudokoSolver(Grid grid)
    {
        _grid = grid;
        _grid.Validate();
    }

    public int?[,] SolvePuzzle()
    {
        Solve();
        Console.WriteLine(_grid.Assigns + " tries total.");
        return _grid.Data;
    }

    private bool Solve()
    {
        int row, col;
        if (!_grid.FindUnassignedLoc(out row, out col))
        {
            return true;
        }

        for (int num = 1; num <= 9; num++)
        {
            if (_grid.NoConflicts(row, col, num))
            {
                _grid.Assign(row, col, num);

                if (Solve())
                {
                    return true;
                }
                _grid.Unassign(row, col);
            }
        }

        return false;
    }

    public int?[,] Data
    {
        get { return _grid.Data; }
    }
}

public class Grid
{
    public int?[,] Data { get; private set; }
    private int _curC = 0;
    private int _curR = 0;
    private int _assigns = 0;

    public Grid(int?[,] data)
    {
        Data = data ?? new int?[9,9];
    }
    public bool FindUnassignedLoc(out int row, out int col)
    {
        while (Data[_curR, _curC].HasValue)
        {
            _curC++;

            if (_curC == 9)
            {
                _curR++;
                _curC = 0;
            }

            if (_curR == 9)
            {
                row = -1;
                col = -1;
                return false;
            }
        }

        row = _curR;
        col = _curC;

        return true;
    }

    public bool NoConflicts(int row, int col, int num)
    {
        for (int r = 0; r < 9; ++r)
        {
            if (Data[r, col] == num)
            {
                return false;
            }
        }

        for (int c = 0; c < 9; c++)
        {
            if (Data[row, c] == num)
            {
                return false;
            }
        }

        int fromC = 3 * (col/3);
        int fromR = 3 * (row / 3);

        for (int c = fromC; c < fromC + 3; c++)
        {
            for (int r = fromR; r < fromR + 3; r++)
            {
                if (Data[r, c] == num)
                {
                    return false;
                }
            }
        }

        return true;
    }

    public void Assign(int row, int col, int num)
    {
        _assigns++;
        Data[row, col] = num;
    }

    public void Unassign(int row, int col)
    {
        Data[row, col] = null;
        _curC = col;
        _curR = row;
    }

    public int Assigns
    {
        get { return _assigns; }
    }

    public void Validate()
    {
        if (Data.Length != 81)
        {
            throw new Exception("Invalid dimentions!");
        }

        if (!IsLegal())
        {
            throw new Exception("Illigal numbers populated!");
        }
    }

    public bool IsLegal()
    {
        var container = new HashSet<int>();
        //vertical check 
        for (int c = 0; c < 9; ++c)
        {
            container.Clear();
            for (int r = 0; r < 9; ++r)
            {
                if (Data[r, c].HasValue)  
                {
                    if (container.Contains(Data[r, c].Value))
                    {
                        return false;
                    }
                    container.Add(Data[r, c].Value);
                }
            }
        }
        // horizontal check
        for (int r = 0; r < 9; ++r)
        {
            container.Clear();
            for (int c = 0; c < 9; ++c)
            {
                if (Data[r, c].HasValue)
                {
                    if (container.Contains(Data[r, c].Value))
                    {
                        return false;
                    }
                    container.Add(Data[r, c].Value);
                }
            }
        }

        // square check
        var topLeftCorners = new List<Tuple<int, int>>
        {
            new Tuple<int, int>(0,0),
            new Tuple<int, int>(0,3),
            new Tuple<int, int>(0,6),
            new Tuple<int, int>(3,0),
            new Tuple<int, int>(3,3),
            new Tuple<int, int>(3,6),
            new Tuple<int, int>(6,0),
            new Tuple<int, int>(6,3),
            new Tuple<int, int>(6,6)
        };

        foreach (var topLeftCorner in topLeftCorners)
        {
            int fromC = topLeftCorner.Item2;
            int fromR = topLeftCorner.Item1;

            container.Clear();

            for (int c = fromC; c < fromC + 3; c++)
            {
                for (int r = fromR; r < fromR + 3; r++)
                {
                    if (Data[r, c].HasValue)
                    {
                        if (container.Contains(Data[r, c].Value))
                        {
                            return false;
                        }
                        container.Add(Data[r, c].Value);
                    }
                }
            }
        }

        return true;
    }
}