数独的优化回朔算法(四)

FillCell

这个方法是填充数独表的递归方法,看长长滴代码:

ExpandedBlockStart.gif 代码
///   <summary>
///  填充单元格
///   </summary>
///   <param name="table"> </param>
///   <param name="index"> 索引 </param>
///   <returns> 返回结果 </returns>
private   bool  FillCell(Cell[,] table,  int  index)
{
    RelativeCellMethod removeCandidateMethod 
=   new  RelativeCellMethod(RemoveCellCandidate);
    RelativeCellMethod recoverCandidateMethod 
=   new  RelativeCellMethod(RecoverCellCandidate);

    
if  (index  >=   81 )
    {
// 如果索引超出范围,则表示数独已成功生成,直接返回
         return   true ;
    }
    
if  (table[index  /   9 , index  %   9 ].Value  !=   0 )
    {
// 如果索引的单元格已赋值,则直接跳到下一个索引赋值
         return  FillCell(table, index  +   1 );
    }
    
bool  flag  =   true ;
    List
< int >  nextCandidates  =   new  List < int > ();
    
// 预先保存好改单元格的候选数序列,如果所有候选数都不成功,则把候选数全部还原之后再返回
    nextCandidates.AddRange(table[index  /   9 , index  %   9 ].Candidate);

    
while  (table[index  /   9 , index  %   9 ].Candidate.Count  >   0   &&  flag)
    {
// 如果单元格候选数个数大于0,且标记为真,则循环试探候选数
        SetValue(table[index  /   9 , index  %   9 ]); // 为单元格赋值
        flag  &=  DealRelativeCell(removeCandidateMethod, table, index); // 移除相关单元格的对应这个值的候选数
         if  ( ! flag)
        {
// 如果移除候选数失败,则恢复候选数,并继续下个循环
            DealRelativeCell(recoverCandidateMethod, table, index);
        }
        
else
        {
// 如果移除候选数成功,则继续试探填充下一个单元格
            flag  &=  FillCell(table, index  +   1 );
            
if  ( ! flag)
            {
// 如果填充下一个单元格失败,则恢复候选数,并继续下个循环
                DealRelativeCell(recoverCandidateMethod, table, index);
            }
            
else
            {
// 如果填充下一个单元格成功,则直接返回(运行到这里肯定表示整个数独已成功生成!)
                 return   true ;
            }
        }
        flag 
=   ! flag; // 把标志取反,继续下个循环
    }
    
if  (table[index  /   9 , index  %   9 ].Candidate.Count  ==   0 )
    {
// 如果所有候选数都是过了且全部失败,恢复此单元格的候选数,并返回false
        table[index  /   9 , index  %   9 ].Candidate.AddRange(nextCandidates);
        
return   false ;
    }
    
return  flag;
}

 

前两行定义了两个代理方法,在while方法中,一个一个的试单元格的候选数填入到单元格中,如果填入失败,则恢复候选数,继续尝试下一个候选数,如果所有候选数都不能正确生成数独,那么跳出while循环,函数返回false,返回到上一个单元格,将上一个单元格的值重置为0,试另外的候选数,以此类推。直到索引index大于等于81,则表示所有单元格都已成功赋值,那么全部返回true。

接下来只需要写一个显示数独的方法:

 

Show

如下:

ExpandedBlockStart.gif 代码
///   <summary>
///  显示数独
///   </summary>
///   <param name="table"> </param>
private   void  Show(Cell[,] table)
{
    
for  ( int  i  =   0 ; i  <   9 ; i ++ )
    {
        
for  ( int  j  =   0 ; j  <   9 ; j ++ )
        {
            Console.Write(
" {0,2} " , table[i, j].Value);

        }
        Console.WriteLine();
    }
    Console.WriteLine(
" ---------------------------------------------- " );

}

 

 

还有一个初始化数独表,然后开始填充数独的方法:

 

StartFillTable

 

ExpandedBlockStart.gif 代码
///   <summary>
///  开始生成数独
///   </summary>
public   void  StartFillTable()
{
    Cell[,] table 
=   new  Cell[ 9 9 ];
    
while  ( true )
    {
        
for  ( int  i  =   0 ; i  <   9 ; i ++ )
            
for  ( int  j  =   0 ; j  <   9 ; j ++ // 初始化数独表
                table[i, j]  =   new  Cell();

        
bool  flag  =  FillCell(table,  0 ); // 填充数独表
         if  (flag) // 如果生成数独成功,则显示这个数独
            Show(table);
        Console.ReadKey();
    }
}

 

 

我是用控制台应用程序编写的,如果是用Silverlight或者其他的呈现会更好看!,下面是Main方法和结果显示:

 

 

class  Program
{
    
static   void  Main( string [] args)
    {
        CellMethod method 
=   new  CellMethod();
        method.StartFillTable();
    }
}

 

只要按回车键就可以生成一个不一样的新数独!

对于有兴趣的读者,如果是要继续开发成数独游戏,可以随机的遮罩一定数量的格子,难度越高遮罩的格子越多,这样能保证的是数独游戏一定有解,但是解不一定唯一。如果要保证解唯一,那么就需要再用一个类似这个的解数独的方法,让计算机先做我们遮罩后的数独,看是不是有且仅有一个解,如果不是,那么重新选择遮罩区域,直到计算机发现解唯一为止,然后输出到前端,给玩家来玩!

下一篇是整个程序的源代码。

转载于:https://www.cnblogs.com/cdts_change/archive/2010/01/25/1656260.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值