数独求解

最近公司大肆流行数独之风,自从学会了编程之后,人就变得越来越懒了,能用计算机算的东西就不大愿意用人脑来算了,记得我以前写过一个数独求解的文章,现在看来,觉得当时写得有点烂,就把它重写了一下。

     class Sudoku
    {
        int[,] Numbers { getset; }

        Sudoku(int[,] numbers)
        {
            this.Numbers = numbers.Clone() as int[,];
        }

        bool Process()
        {
            var point = GetAvaiblePoints().FirstOrDefault();
            if (point == null)   //
所有空格都已经填充
                return true;

            foreach (var item in GetAvaibleNumbers(point))
            {
                Numbers[point.X, point.Y] = item;
                if (Process())
                    return true;
            }

            //
填遍所有可用数字(无可用数字),仍不能正确求解
            Numbers[point.X, point.Y] = 0;
            return false;
        }

        readonly int[] avaible = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        IEnumerable<int> GetAvaibleNumbers(Point p)
        {
            return avaible.Except(Horizontal(p))
                .Except(Vertical(p))
                .Except(Rectangle(p));
        }

        readonly int[] indexs = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 };

        IEnumerable<int> Horizontal(Point p) { return indexs.Select(i => Numbers[i , p.Y]); }

        IEnumerable<int> Vertical(Point p) { return indexs.Select(i => Numbers[p.X, i]); }

        IEnumerable<int> Rectangle(Point p)
        {
            var x = p.X - p.X % 3;
            var y = p.Y - p.Y % 3;

            for (int i = 0; i < 3; i++)
                for (int j = 0; j < 3; j++)
                    yield return Numbers[x + i, y + j];
        }

        IEnumerable<Point> GetAvaiblePoints()
        {
            return from x in indexs
                   from y in indexs
                   where Numbers[x, y] == 0
                   select new Point(x, y);
        }

        /// <summary>
        ///
数独求解
        /// </summary>
        /// <param name="numbers">
9*9数组,空格用0代替,已有值的范围1~9,本函数不对参数有效性检测,不要测试程序的健壮性</param>
        /// <returns>
返回一个可行的数独解,无解返回null</returns>
        public static int[,] Process(int[,] numbers)
        {
            var soudu = new Sudoku(numbers);
           
            if (soudu.Process())
                return soudu.Numbers;
            else
                return null;
        }

        //
坐标点,可以用Tuple<int,int>代替
        class Point
        {
            public int X { get; set; }
            public int Y { get; set; }

            public Point(int x, int y)
            {
                this.X = x;
                this.Y = y;
            }

            public override string ToString() { return X + "," + Y; }
        }
    }

两个算法没有什么本质上的区别,但这个更容易看懂,并且这个大量使用了linq,算法是更加容易改造(改顺序尝试为随机尝试,改线性求解为并发)的,有点函数式编程的影子,什么时候有空再用F#来写一下。

原文地址:https://www.cnblogs.com/TianFang/p/1827674.html