分享一个解数独的小程序,继续普及LINQ。

threenewbee 2012-05-08 01:24:54
加精
分享一个解数独的小程序,继续普及LINQ。

欢迎更好的算法,有可用分赠送。

数独游戏的规则可以Google下。

感谢反馈,现简要介绍算法和给代码做一点注释:

算法大致是,依次尝试给空格填入数字。首先寻找一个空格(我选择找从上到下,从左到右第一个空格(为0的元素)),作为进行试探的空格。首先看这个空格,对应的行、列、宫已经有的数字,根据它们的并集和0-9的差集求得可以尝试的数字。我们依次试探填入,并且将填入的数字作为已知的盘面求解下一个空格……这样找下去,最终会出现两种可能,一个是对于某个空格,没有可以选择的候选数字了,那么进入死胡同,就需要对上一个空格回溯,选择下一个尝试,如果上一个空格的所有选择用完还不行,就再回溯到上上个……还有一种情况,最后一个空格有且只有一个选择,这种情况下,填入这个数字,数独解算完成。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int[] source =
{
5, 4, 0, 2, 9, 0, 0, 1, 0,
0, 2, 0, 0, 0, 6, 3, 0, 0,
3, 0, 0, 1, 0, 0, 0, 5, 4,
0, 6, 0, 0, 0, 8, 9, 0, 0,
2, 5, 0, 6, 7, 0, 0, 3, 1,
0, 0, 1, 0, 2, 0, 0, 6, 0,
8, 3, 0, 0, 0, 4, 0, 0, 6,
0, 0, 5, 9, 0, 0, 0, 8, 0,
0, 7, 0, 0, 3, 1, 0, 4, 2
}; // http://www.sudoku.name/index-cn.php #10332 数独来自这个网站
int[] result = source.ToArray(); // result数组保存解算中间数据和结果
Func<bool> IsFinished = () => result.Where(x => x == 0).Count() == 0; // 判断是否解算完成
Func<int> NextNumber = () => result.Select((x, i) => new { x, i }).First(x => x.x == 0).i; // 取下一个空格(这个算法不是唯一的,你也可以从后往前填写,或者别的方法)
Func<IEnumerable<int>> TryValues = () =>
{
int pos = NextNumber(); // 获取空格
int col = pos % 9; // 行号
int row = pos / 9; // 列号
int group = (row / 3) * 3 + col / 3; // 宫号
var colnums = Enumerable.Range(1, 9).Except(Enumerable.Range(0, 81).Where(x => x % 9 == col).Select(x => result[x]).Where(x => x != 0)); // 让1-9和本列已有数据对比,求差集,差集是对于列,允许填入的数字,下面类似
var rownums = Enumerable.Range(1, 9).Except(Enumerable.Range(0, 81).Where(x => x / 9 == row).Select(x => result[x]).Where(x => x != 0));
var groupnumbers = Enumerable.Range(1, 9).Except(Enumerable.Range(0, 81).Where(x => ((x / 9) / 3) * 3 + (x % 9) / 3 == group).Select(x => result[x]).Where(x => x != 0));
return colnums.Intersect(rownums).Intersect(groupnumbers); //数据是行、列、宫的交集
}; // 找出填写这个空格的所有可能尝试的数据

Action DisplayResult = () => Console.WriteLine(string.Join("\r\n", result.Select((x, i) => new { x, i }).GroupBy(x => x.i / 9).Select(x => string.Join(" ", x.Select(y => y.x)))) + "\r\n"); // 显示结果
Action Solve = () => { }; // 递归Lambda必须先定义一个空的。
Solve = () =>
{
if (IsFinished())
{
DisplayResult(); //如果全部填满,就输出结果(严格地,应该考虑无解的情况,这里忽略)
}
else
{
int pos = NextNumber(); // 获取空格位置
foreach (int item in TryValues()) // 依次尝试所有可能的数字
{
result[pos] = item; // 将盘面设置为尝试数字
Solve(); //下一层解算
}
result[pos] = 0; // 尝试完还不行,恢复盘面,回溯上一层
}
}; // 算法主体
Solve(); // 开始解算
}
}
}
...全文
4532 93 打赏 收藏 转发到动态 举报
写回复
用AI写文章
93 条回复
切换为时间正序
请发表友善的回复…
发表回复
chenruoyun 2014-09-08
  • 打赏
  • 举报
回复
好东西.学习一下.
  • 打赏
  • 举报
回复
受益匪浅
_小黑_ 2013-12-06
  • 打赏
  • 举报
回复
我还是个初学者
安异 2013-12-02
  • 打赏
  • 举报
回复
牛!
光与影的嬉戏 2012-07-05
  • 打赏
  • 举报
回复
谢谢分享,学习
lucasgift 2012-05-15
  • 打赏
  • 举报
回复
这个已经是很好的了吧!
barga520620 2012-05-14
  • 打赏
  • 举报
回复
非常好的帖子
dragon_cheng 2012-05-14
  • 打赏
  • 举报
回复
这分享……
wangliroot 2012-05-14
  • 打赏
  • 举报
回复
[Quote= 64 楼 的回复:]

https://forum.csdn.net/PointForum/ui/scripts/csdn/Plugin/003/monkey/0.gif /
[/Quote]成功
liuxibei1987 2012-05-14
  • 打赏
  • 举报
回复
[Quote=引用 71 楼 的回复:]

学习了,只能在VS2010下编译,2008不行。
[/Quote]
修改一下就可以编译了
csnotdn 2012-05-13
  • 打赏
  • 举报
回复
不错的资源
warcao 2012-05-13
  • 打赏
  • 举报
回复
不懂。。
BurningBright 2012-05-12
  • 打赏
  • 举报
回复
顶。喜欢数独。
NewUser2008 2012-05-11
  • 打赏
  • 举报
回复
谢谢分享,学习
51715dididada 2012-05-11
  • 打赏
  • 举报
回复
不错啊,读书时玩过数独。
yangchun1213 2012-05-11
  • 打赏
  • 举报
回复
必须赞一个~~
ONE-PIECE 2012-05-11
  • 打赏
  • 举报
回复
https://forum.csdn.net/PointForum/ui/scripts/csdn/Plugin/003/monkey/0.gif /
nsdwn 2012-05-11
  • 打赏
  • 举报
回复
学习了,只能在VS2010下编译,2008不行。
LAONINGA098 2012-05-11
  • 打赏
  • 举报
回复
谢谢分享,学习
Zouhh 2012-05-11
  • 打赏
  • 举报
回复
感谢分享,学习了。。。
加载更多回复(44)

110,567

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧