数独计算(C#)
计算零到多个可能的数独结果,并打印到Console中。
调用方法
MainController mc = new MainController(); mc.Do();
输入
数独数据 类型为int[,],-1表示空。
通过Sudu.Setup()方法设置。
输出
同输入格式。
通过Sudu.PrintResult()方法打印。
概述
该方法属于穷举的搜索算法。将完整过程分解为重复的往一个空里填一个数字的过程,每填一个空,尝试所有可用数字,找到与已填数字不冲突的数字。如果找不到合适的数字,修改已填数字,既回溯到上一步。
代码实现分两部分,一个是填充循环,一个是填充位置改变和填充操作。分别实现为两个类。
填充循环
思路
循环主体是执行操作(填写一个数字)。
如果操作失败(没有有效的数字能够填入),则移动到上一步。如果操作成功,则移动到下一步。
如果无法移动到下一步,则认为完成所有步骤,获得了一个有效的结果。
如果无法移动到上一步,则认为无法修改步骤,结果查找完毕,退出执行循环。
代码
public class MainController
{
public Sudu sudu = new Sudu(); /// <summary>
/// 执行循环
/// </summary>
/// <param name="findmulti">是否寻找多个解</param>
public void Do(bool findmulti = true)
{
sudu.PrintResult();
DateTime dt = DateTime.Now;
int resultcount = 0;
int actioncount = 0;
while (true)
{
// 执行
bool actionresult = sudu.TakeAction();
actioncount++;
if (actionresult)
{
// 执行成功则移动到下一步
if (sudu.MoveNext() == false)
{
// 无法移动到下一步,则已经完成
Console.WriteLine("尝试次数:" + actioncount);
Console.WriteLine("结果个数:" + resultcount);
Console.WriteLine("耗时(s):" + (DateTime.Now - dt).TotalSeconds);
sudu.PrintResult();
resultcount++;
if (findmulti)
{
continue;
}
else
{
return;
}
}
}
else
{
// 执行失败则退回上一步
if (sudu.MovePrev() == false)
{
// 无法移动到上一步,则已经结束搜索
Console.WriteLine("结束");
Console.WriteLine("尝试次数:" + actioncount);
Console.WriteLine("结果个数:" + resultcount);
Console.WriteLine("耗时(s):" + (DateTime.Now - dt).TotalSeconds);
sudu.PrintResult();
return;
}
} }
}
}
填充位置改变和填充操作
思路
数字填充:每次往数组中填充一个数字,如果能填充不冲突的数字则返回True,否则返回False。
填充位置改变:当前填充位置表示为行序号和列序号,初始状态都为0。移动到下一步,上一步时,修改填充位置,即修改此序号对。
代码
public class Sudu
{
public Sudu()
{
int[,] data = new int[,] {
{ -1,-1,2,9,-1,-1,-1,-1,-1},
{ -1,-1,-1,-1,-1,-1,8,-1,5},
{ -1,5,8,-1,-1,-1,7,-1,-1},
{ 1,-1,9,-1,3,-1,-1,-1,-1},
{ -1,-1,-1,-1,7,8,-1,-1,-1},
{-1,-1,6,-1,-1,-1,-1,3,-1 },
{9,4,-1,-1,5,-1,-1,-1,1 },
{-1,-1,-1,-1,-1,7,-1,-1,9 },
{6,8,-1,-1,-1,3,5,-1,-1 },
};
Setup(data);
}
/// <summary>
/// 初始化数独数据。data中-1表示可填入,其他值表示固定值
/// </summary>
/// <param name="data"></param>
public void Setup(int[,] data)
{
int c = 0;
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
if (data[i, j] == -1)
{
filleddata[i, j] = 0;
canfill[i, j] = 1;
}
else
{
c = c + 1;
filleddata[i, j] = data[i, j];
canfill[i, j] = 0;
}
}
}
col = 0;
row = 0;
Console.WriteLine("已填数字:" + c);
}
/// <summary>
/// 初始值为0,表示未开始填充
/// </summary>
int[,] filleddata = new int[9, 9];
/// <summary>
/// 0代表不能填充,1代表能填充
/// </summary>
int[,] canfill = new int[9, 9]; int col = 0;
int row = 0;
/// <summary>
/// 移动到上一个可填空位置
/// </summary>
/// <returns>是否有上一个可填充位置</returns>
public bool MoveNext()
{
while (true)
{
if (col == 8 && row == 8)
return false;
if (col == 8)
{
row++;
col = 0;
}
else
{
col++;
}
if (canfill[row, col] == 0)
continue;
return true;
}
}
/// <summary>
/// 移动到下一个可填空位置
/// </summary>
/// <returns>是否有下一个可填充位置</returns>
public bool MovePrev()
{
while (true)
{
if (col == 0 && row == 0)
return false;
if (col == 0)
{
row--;
col = 8;
}
else
{
col--;
}
if (canfill[row, col] == 0)
continue;
return true;
}
}
/// <summary>
/// 填充当前位置
/// </summary>
/// <returns>如果正常填充则返回true,无法填充或填充无效则返回false</returns>
public bool TakeAction()
{
if (canfill[row, col] == 0)
return false;
//尝试填充
while (true)
{
// 填充下一个值
if (filleddata[row, col] < 9)
filleddata[row, col] = filleddata[row, col] + 1;
else
{
// 重置该值
filleddata[row, col] = 0;
return false;
}
if (Check())
return true;
}
}
/// <summary>
/// 检查冲突
/// </summary>
/// <returns></returns>
private bool Check()
{
for (int i = 0; i < 9; i++)
{
if (col != i
&& filleddata[row, col] == filleddata[row, i])
return false;
if (row != i
&& filleddata[row, col] == filleddata[i, col])
return false;
if (((row / 3 * 3 + i / 3) != row
&& (col / 3 * 3 + i % 3) != col)
&& filleddata[row / 3 * 3 + i / 3, col / 3 * 3 + i % 3] == filleddata[row, col])
return false;
}
return true;
}
/// <summary>
/// Console方式输出数独结果
/// </summary>
public void PrintResult()
{
Console.WriteLine("data");
Print(filleddata);
}
private void Print(int[,] data)
{
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
Console.Write(data[i, j] + ", ");
}
Console.WriteLine();
}
}
public void PrintCurrent()
{
Console.WriteLine("col: " + col + " row: " + row + " data: " + "data:" + filleddata[row, col]);
}
}
如需尝试新的数独,替换Sudu类构造函数中的数据即可。
have fun.
数独计算(C#)的更多相关文章
- java程序计算数独游戏
兴趣来了,写了个简单的数独游戏计算程序,未做算法优化. 通过文件来输入一个二维数组,9行,每行9个数组,数独游戏中需要填空的地方用0来表示.结果也是打印二维数组. import java.io.Fil ...
- python 实现计算数独
输入文件格式: 008309100900060004007504800036000540001000600042000970005907300600010008004608200 输出结果: yuan ...
- 用C++实现的解数独(Sudoku)程序
我是一个C++初学者,控制台实现了一个解数独的小程序. 代码如下: //"数独游戏"V1.0 //李国良于2016年11月11日编写完成 #include <iostream ...
- codevs 2924 数独挑战
2924 数独挑战 http://codevs.cn/problem/2924/ 题目描述 Description "芬兰数学家因卡拉,花费3个月时间设计出了世界上迄今难度最大的数独游戏,而 ...
- 用html5 canvas和JS写个数独游戏
为啥要写这个游戏? 因为我儿子二年级数字下册最后一章讲到了数独.他想玩儿. 因为我也想玩有提示功能的数独. 因为我也正想决定要把HTML5和JS搞搞熟.熟悉一个编程平台,最好的办法,就是了解其原理与思 ...
- Scrum4.0+5.0 数独游戏
1.题目: 1.准备看板. 形式参考图4. 2.任务认领,并把认领人标注在看板上的任务标签上. 先由个人主动领任务,PM根据具体情况进行任务的平衡. 然后每个人都着手实现自己的任务. 3.为了团队合作 ...
- 蓝桥杯---数独(模拟 || dfs)
[编程题](满分33分) "数独"是当下炙手可热的智力游戏.一般认为它的起源是"拉丁方块",是大数 学家欧拉于1783年发明的. 如图[1.jpg]所示:6x6 ...
- android数独游戏
最近没事干,照着视频教程写了一个数独游戏,很粗糙还有很多要修改的地方.下面就来说说这个游戏吧 1.自定义一个View控件,用来在屏幕上显示一个9*9的格子,其实就是横着画8条线,竖着画8跳线,然后将其 ...
- android开发——数独游戏
最近研究了一下android,写了一个数独游戏,具体如下: 游戏界面需要重写一个ShuduView继承View, 然后自定义一个Dialog: 1.需要继承 Dialog 类, 2.并要定义一个有参构 ...
随机推荐
- pytest学习--快速入门
一.pytest简介 Pytest是python的一种单元测试框架. pytest的特点: 入门简单,文档丰富 支持单元测试,功能测试 支持参数化,重复执行,部分执行,测试跳过 兼容其他测试框架(no ...
- python表格导出--xlwt的使用
xlwt可以用来导出excel表,下面介绍一下它的用法: 1. 安装xlwt模块 pip install xlwt 2. 使用xlwt模块:后端接口编写 import xlwt #导出表格接口 def ...
- Java框架spring 学习笔记(一):SpringBean、ApplicationContext 容器、BeanFactory容器
Spring容器是Spring框架的核心,容器可以创建对象并创建的对象连接在一起,配置和管理他们的整个生命周期.Spring 容器使用依赖注入(DI)来作为管理应用程序的组件,被称为 Spring B ...
- 解析ReentrantLock实现原理
在Java中通常实现锁有两种方式,一种是synchronized关键字,另一种是Lock(Lock的实现主要有ReentrantLock.ReadLock和WriteLock).synchronize ...
- 超简单的全新win10安装
1.准备工作! 这里说一下需要装系统的东西: 至少8G的U盘或内存卡 一台Windows电脑 在要安装的电脑上至少有16G的空间,最好至少64G. 2.现成电脑下载文件(已经有重装系统U盘跳过这一步) ...
- fmt.printf输出的格式
动 词 功 能 %v 按值的本来值输出 %+v 在 %v 基础上,对结构体字段名和值进行展开 %#v 输出 Go 语言语法格式的值 %T 输出 Go 语言语法格式的类型和值 %% 输出 % 本体 %b ...
- 设计模式学习心得<桥接模式 Bridge>
说真的在此之前,几乎没有对于桥接模式的应用场景概念. 桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变化.这种类型的设计模式属于结构型模式,它通过提供抽象化和实现化之间的桥接结构,来 ...
- UI设计学习之工具中的色彩模式分析
图像根据其呈现的颜色样式分为多种色彩模式,常见的为RGB模式.CMYK模式.灰度模式.位图模式和索引模式. RGB模式 这是Photoshop最常用的颜色模式,也称之为真彩色颜色模式,在RGB模式 ...
- Gym - 101848B Almost AP 暴力
题目链接:http://codeforces.com/gym/101848/problem/B 给出一串数字要你最多改动三个数字使这一串数字成为等差数列.因为最多改动三个数字所以可以先求出相邻两项的差 ...
- 一、PyQt5基础概念与安装配置
一.初识PyQt5 对于桌面程序开发,用户图形界面(GUI)的设计非常重要.一款美观.易用的用户界面可以很大程度上提高对使用这的友好度.由于Python最初是作为脚本语言开发,并没有GUI功能.但Py ...