数独(sudoku)游戏的程序求解
9x9的正方形方格可以分成9个3×3的九宫格。
数独游戏是在这样的正方形中,首先事先给某些方格填入1-9的数字,然后要求在余下的方格中也填入1-9的数字,要求每一行,每一列,以及每个九宫格中,都正好包含1-9这九个数字。
解算 sudoku 的方法很多,前段时间闲的无聊我也写了一个。算法很简单,就是试填+递归穷举。方法有些暴力,不过很有效,程序也非常的简洁。
实际上,写完程序后我才发现,sudoku 的难点其实不在解算,而是如何生成数独题目,并且保证生成的题目解是唯一的。这个问题还要再思考思考,现在还没有什么思路。
下面是源程序,C语言写的,尽可能的使其保持 KISS (keep it simple and stupid)
sudoku 函数求出一个解。
sudoku_all 函数则试图穷举所有可行解。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 9
void display(char mat[SIZE][SIZE], char mes[]);
void copy(char src[SIZE][SIZE], char des[SIZE][SIZE]);
bool containInRow(char mat[SIZE][SIZE], int element, int row);
bool containInCol(char mat[SIZE][SIZE], int element, int col);
bool containInBlock(char mat[SIZE][SIZE], int element, int row, int col);
bool findFirstEmptyPos(char mat[SIZE][SIZE], int pos[2]);
void load(char mat[SIZE][SIZE]);
bool sudoku(char mat[SIZE][SIZE]);
bool sudoku_all(char mat[SIZE][SIZE]);
static int solution_count = 0;
static char message[] = "the number of possible solution is 9999999:";
int main(void)
{
int i, j, t, ret;
bool isOk;
char mat[SIZE][SIZE];
solution_count = 0;
load(mat);
display(mat, "origin matrix is ");
isOk = sudoku_all(mat);
if( isOk )
display(mat, "solved matrix is ");
// else
// puts("No valid solution");
printf("the number of possible solution is %d:", solution_count);
// puts(message);
return 0;
}
bool sudoku(char mat[SIZE][SIZE])
{
char b[SIZE][SIZE];
bool isOk;
int pos[2], j;
copy(mat, b);
isOk = findFirstEmptyPos(b, pos); // 找到第一个需要填的位置
if(isOk == false) return true; // 如果都填满了,返回 true. 表示成功的找到解了
for(j = 1; j <= SIZE; j ++)
{
if( containInRow(b, j, pos[0]) ) continue;
if( containInCol(b, j, pos[1]) ) continue;
if( containInBlock(b, j, pos[0], pos[1]) ) continue;
b[ pos[0] ][ pos[1] ] = j; // j 是一个可以填的值,试填之
isOk = sudoku( b );
if(isOk == true)
{
copy(b, mat); // 到这里了说明 j 填对了,并且后面的数也都填好了
return true; // 因此将结果拷贝到 mat 中。
}
copy(mat, b); // 到这里说明 j 填的不对,恢复 b ,重新填
}
return false; // 到这里了说明 1-9都试了全都不对,表明当前状态无解
}
bool sudoku_all(char mat[SIZE][SIZE]) //解出所有的可行解
{
char b[SIZE][SIZE];
bool isOk = false;
int pos[2];
copy(mat, b);
// display(mat, "inter");
isOk = findFirstEmptyPos(b, pos); // 找到第一个需要填的位置
if(isOk == false)
{
solution_count ++;
sprintf(message, "A possible solution (%d):", solution_count);
// puts(message);
display(mat, message);
return false; //找到一组解后,仍然返回 false, 让程序继续找下一组解
}
for(int j = 1; j <= SIZE; j ++)
{
if( containInRow(b, j, pos[0]) ) continue;
if( containInCol(b, j, pos[1]) ) continue;
if( containInBlock(b, j, pos[0], pos[1]) )continue;
b[ pos[0] ][ pos[1] ] = j; // j 是一个可以填的值,试填之
isOk = sudoku_all( b ); // 无论找到解没有,都还原成原始状态,接着找下一组解
copy(mat, b); // 因为如果找到解了,解就已经用 display 函数输出了,接着找下一组解就可以了。
} // 如果没找到解,同样也要恢复原始状态,试下一个可能的数
return false; // 到这里了说明 1-9都试了全都不对,表明当前状态无解,返回到上一步,试下一个可能的数
}
void load(char mat[SIZE][SIZE])
{
int i, j, t;
for ( i = 0; i < SIZE; i++)
{
for (j = 0; j < SIZE ; j++)
{
scanf("%d", &t);
mat[i][j] = t;
}
}
}
void display(char mat[SIZE][SIZE], char mes[])
{
int i, j, t;
puts(mes);
for ( i = 0; i < SIZE; i++)
{
for (j = 0; j < SIZE ; j++)
{
t = mat[i][j];
printf("%2d ", t);
}
puts("");
}
}
/**
* @brief 判断一个数是否已经在这一行出现过了
*/
bool containInRow(char mat[SIZE][SIZE], int element, int row)
{
int i;
for (i = 0; i < SIZE; i++)
{
if (mat[row][i] == element) return true;
}
return false;
}
/**
* @brief 判断一个数是否已经在这一列出现过了
*/
bool containInCol(char mat[SIZE][SIZE], int element, int col)
{
int i;
for (i = 0; i < SIZE; i++)
{
if (mat[i][col] == element) return true;
}
return false;
}
/**
* @brief 判断一个数是否已经在这一3*3的小方块中出现过了
*/
bool containInBlock(char mat[SIZE][SIZE], int element, int row, int col)
{
int i = row / 3;
int j = col / 3;
for (int ii = 0; ii < SIZE / 3; ii++)
{
for(int jj = 0; jj < SIZE / 3; jj++)
{
if (mat[i * 3 + ii][j * 3 + jj] == element) return true;
}
}
return false;
}
void copy(char src[SIZE][SIZE], char des[SIZE][SIZE])
{
int i, j;
for (i = 0; i < SIZE; i++)
{
for (j = 0; j < SIZE; j++)
{
des[i][j] = src[i][j];
}
}
}
/**
* @brief 找到第一个需要填数字的位置
* @para pos 通过 pos 返回位置坐标, pos[0] 为行号, pos[1] 为列号
*/
bool findFirstEmptyPos(char mat[SIZE][SIZE], int pos[2])
{
int i, j;
for (i = 0; i < SIZE; i++)
{
for (j = 0; j < SIZE; j++)
{
if (mat[i][j] == 0)
{
pos[0] = i;
pos[1] = j;
return true;
};
}
}
return false;
}
数独(sudoku)游戏的程序求解相关推荐
- java数独游戏_java 数独sudoku游戏
有大佬帮帮看下这个数独游戏程序么,检测为空.有效都成功了,就是不能把赋值更新到数组里面,一直重复打印原数组 package pro1; import java.util.Scanner; public ...
- 【2019.09.19】数独(Sudoku)游戏之我见(软工实践第三次作业)
Github项目地址:https://github.com/MokouTyan/suduku_131700101 [2019.09.20]更新:代码经过Code Quality Analysis工具的 ...
- 一段代码,求解数独(九宫格)游戏
数独(Sudoku)游戏是从1-9共9个数字中,装在3x3x3x3的单元格内 每个小的3x3内的数值只能重复一遍,同时每行及每列的数值也只能重复一遍 每个单元格都必须有数值,不能留空 解法简介: 创建 ...
- 独数游戏android程序,Android 数独小游戏
先看看效果图 sudoku-o3.gif 数独设计思路 先看布局,我们可以看到数独由9x9的格子组成,每个格子中间有一个数字. Cell (单个格子.android 中我们可以先用TextView代替 ...
- 谈谈数独(Sudoku)
谈谈 Sudoku (数独) 除特别说明外,本文提到的Sudoku是指9x9的经典Sudoku.本文大量参考了维基百科的相关条目. Sudoku 介绍 Sudoku 是一种数学游戏,把一个9行9列的棋 ...
- 数独终局生成及残局求解
文章目录 一.项目地址 二.各模块开发时间预估 三.学习过程.解题思路 3.1 开发语言及运行环境 3.2 项目要求分析 3.2.1 需求建模 3.2.2 数据流设计方法 3.3 解题思路 3.3.1 ...
- BIT软件工程个人项目——数独sudoku
BIT软件工程个人项目--数独sudoku 目录: (点击可页内跳转) 1. 项目地址 2. PSP表格 3. 解题思路描述 --3.1初期思考 --3.2数独终局生成 --3.3求解数独 4. 设计 ...
- Java黑皮书课后题第8章:*8.24(检验数独的解决方案)程序清单8-4通过检测棋盘上的每个数字是否是有效的,从而检验一个解决方案是否是有效的。重写该程序,通过检验是否每行、每列、每个小方盒中具有
*8.24(检验数独的解决方案)程序清单8-4通过检测棋盘上的每个数字是否是有效的,从而检验一个解决方案是否是有效的.重写该程序 题目 题目描述 程序清单8-4 破题 代码 题目 题目描述 *8.24 ...
- Android Studio实现数独小游戏,休闲益智
文章目录 一.项目概述 二.开发环境 三.详细设计 3.1 界面设计 3.2 逻辑设计 四.运行演示 五.源码获取 一.项目概述 数独是一种逻辑解谜游戏,它规则稍复杂,解题过程富有挑战性.本次安卓数独 ...
最新文章
- 22.调用delay()方法延时执行动画效果
- 443 ERROR [main] client.ConnectionManager$HConnectionImplementation: Can‘t get connection to ZooKeep
- VTK:Picking之HighlightSelectedPoints
- MS CRM 2011 汇总更新4已经发布
- VisualSVN Server 和 SVN 服务器架设
- cartographer编译过程遇到未定义的dlclose@@GLIBC_2.2.5
- Kaldi AMI数据集脚本学习7---train_deltas.sh
- pythonmysql包_[Python] MySQLdb(即 MySQL-python 包)在 OS X 中安装指南
- Mac便笺基本操作|便笺使用太鸡肋?那是你不知道这几个快捷键!
- mybatis自动生成代码
- ios vue 添加本地音乐_vue怎么添加自己的音乐
- WAP1.x协议栈浅析
- Geek(一个好用的强力卸载软件工具,包括注册表所有依赖项全部清理掉)
- mindoc mysql_MinDoc 配置文件详解
- zabbix配置方糖微信推送报警
- python中np是什么意思_了解python中np是做什么的
- VS2022无法启动程序,系统找不到指定文件
- the sip module implements API v12.0 to v12.8 but the PyQt5.QtGui module requires API v12.9
- android+获取电池信息,Delphi XE5 Android应用程序获取电池信息
- Git 之三 常用命令:仓库创建、提交、分支等
热门文章
- Windows平台的x64dbg插件合集
- 【微生物研究】微生物交互关系研究论文摘要集锦
- 诗经2 国风-周南-葛覃
- 鸿蒙系统北斗导航系统,这个“北斗导航” App,竟欺骗了几百万人!
- 经常忘记的--jsp被转成servlet放在哪个目录下呢 2、日志路径3、AdminServer.lok
- 音乐雷达 shazam算法_Shazam之类的音乐识别应用程序如何工作?
- 一个流氓软件会有哪些典型特征?
- echarts自定义legend样式
- python 的csr_python稀疏矩阵(CSR型)操作
- recat 基本学习