C# 解数独算法实现并使用Asp.net制作小工具

前言

这一段时间在学习MATLAB。MATLAB是一个强大的数学软件,而其基本数据单位是矩阵。既然是学习,总要找一个比较容易入手且比较有趣的需求加以实现,我认为这样的学习方式是比较合理的。说到矩阵,我非常感兴趣的就是幻方,从幻方的巧妙之处让我联想到我喜欢玩的一个游戏,没错,就是这篇博客要说的数独(Sudoku)

 

正文

按照惯例,我们先看一下成品效果。

下个数独游戏app直接上困难模式,如图。

将这些已知数字填到计算界面。

然后计算,秒出结果。

将结果数字填入到数独游戏app中,大功告成,因为演示截图耽搁,不然2分钟足够了。

做好的工具我发布到个人测试服务器了,有兴趣的可以去看看。解数独工具

 

下面说方法。

网上有很多解数独的算法了,思路也很明确,我就照本宣科将算法用C#的方式写出来。数独游戏的规则是根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个粗线宫(3*3)内的数字均含1-9。根据这个规则,我们可以先设计三个方法。

        /// <summary>
        /// 检查行是否能放入数字num
        /// </summary>
        /// <param name="_quesArr">数独二维数组</param>
        /// <param name="i">行</param>
        /// <param name="j">列</param>
        /// <param name="num">数字</param>
        /// <returns></returns>
        private bool check_row(int[,] _quesArr,int i, int j, int num)
        {            
            for (int col = 1; col <= 9; col++) {
                if (_quesArr[i - 1, col - 1] == num)
                {
                    return false;                    
                }
            }
            return true;
         }
//检查列是否能放入数字num
private bool check_col(int[,] _quesArr, int i, int j, int num) {
   for (int row = 1; row <= 9; row++) {
      if (_quesArr[row - 1, j - 1] == num)
      {                    
         return false;
      }
    }
    return true;
}
        //检查3*3宫格是否能放入数字num
        private bool check3_mul_3(int[,] _quesArr, int i, int j, int num)
        {
            // 检查(i,j)能否放num       
            int block_row = (i - 1) / 3 + 1;
            int block_col = (j - 1) / 3 + 1;

            int block_row_to = block_row * 3;
            int block_row_from = block_row_to - 2;
            int block_col_to = block_col * 3;
            int block_col_from = block_col_to - 2;

            for (int row = block_row_from; row <= block_row_to; row++) {
                for (int col = block_col_from; col <= block_col_to; col++) {
                    if (_quesArr[row - 1, col - 1] == num)
                        return false;
                }
            }
            return true;
        }

        //同时满足三个条件的,可以在格子内放入num数字
        private bool check(int[,] _quesArr,int i, int j, int num)
        {
             if(check_row(_quesArr,i, j,num) && check_col(_quesArr, i, j, num) && check3_mul_3(_quesArr, i, j, num))
                 return true;
             else
                return false;                    
        }

这三个方法设计好后,基本就完成一半了,后面就需要递归调用check()检查每一个数字了。先贴代码。

int[,] _ansArr;

//按编号逐一填充,递归
public void Solve(int[,] _quesArr, int id)
        {

            if (id > 81)//当递归到9*9最后一个格子后,完成递归出结果
                _ansArr = _quesArr;
            else
            {
                int row = (id - 1) / 9 + 1;
                int col = (id - 1) % 9 + 1;
                if (_quesArr[row - 1, col - 1] != 0)//0代表空,需要填充
                {
                    var temparr =new int[9,9];
                    temparr=(int[,])_quesArr.Clone();//注意引用类型的递归传递 需要克隆副本进行传递
                    Solve(temparr, id + 1);
                }
                else
                {
                    for (int i = 1; i <= 9; i++)
                    {
                        if (check(_quesArr, row, col, i))//如果校验合格,将数字i放到指定行列
                        {
                            _quesArr[row - 1, col - 1] = i;
                            var temparr = new int[9, 9];
                            temparr = (int[,])_quesArr.Clone();
                            Solve(temparr, id + 1);                            
                        }
                    }//循环结束还没找到合适的数字,则说明前面的数字找错了,那前面的递归函数将继续找
                }
            }
        }

大功告成,最后调用这个方法

        //Sudoku构造器
        public Sudoku(int[,] ques)
        {            
            Solve(ques,1);
            ques = _ansArr;
        }

好了。二维数组由前端传递,做一个WebApi接口。

        [HttpPost,Route("resultsudoku")]
        public string ResultSudoku([FromBody]string ques)//二维数组  
        {
            int[,] arr = (int[,])JsonConvert.DeserializeObject(ques, typeof(int[,]));               
            Sudoku shudu = new Sudoku(arr);         
            return JsonConvert.SerializeObject(arr);
        }

有兴趣的点击上方链接食用吧。解数独工具

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值