软件工程基础个人项目——数独(5)

软件工程基础个人项目——数独

点击这里可看github上的具体代码
本次个人项目关于数独的生成与求解

PSP表格

PSP2.1Personal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划
Estimate估计这个任务需要多少时间1520
Development开发
Analysis需求分析20
Design Spec生成设计文档60
Design Review设计复审
Coding Standard代码规范
Design具体设计120
Coding具体编码600
Code Review代码复审200
Test测试(自我测试,提交代码,代码修改)400
Reporting报告30
Test Report测试报告30
Size Measurement计算工作量30
Postme & Process Improvement Plan事后总结并提出过程改进计划30
合计1520

思路描述

最开始看到题目的时候,感觉压力很大,因为在此之前我从未了解过数独,担心自己不能很好的理解数独,更不要说通过代码编写让计算机完成数独的求解和生成了。但是在网上是可以找到很多之前学姐学长们智慧的结晶,在本次个人项目上为我提供了很多帮助。我先从网上找寻了关于数独的有关内容,大致明白了数独的概念,也尝试的自己手动解了解数独。那么怎么更好的通过计算机实现数独的生成与求解呢。我看了很多相关博客,找到了我能理解也觉得比较简单的方法。
生成数独:先生成一个1-9的无重复的排列,再将此排列平移。除了第一行之外的每一行,都是通过第一行向右平移某位生成,出去的数字回到排列左端。
求解数独:
使用回溯方法,同时设立vis来确定是否可以将某数字放在某位置上,参考了之前某位学长或者学姐的博客,最终确定这个方法。

程序实现过程

数独的生成:
写一个函数Create_sudoku(),
这是我最开始的想法,后来为了方便管理,我写了一个class Sudo,在其中创建了create 函数。

数独的求解:
求解是solve函数,中心思想回溯由Traceback()执行,其中设立的vis数组判断数字是否可以放在某位置上。需要setvis(),resetvis(),checkvis(),共同完成其功能。

设计图

Created with Raphaël 2.2.0 开始 打开文件 判断数独 打印一个数独 确认为0标记vis数组 对非0位置进行标记 回溯 关闭文件 结束 yes no yes

性能分析

进行数独的生成时,根据生成不同数量的数独的命令行进行分析,生成了不同的分析图。可能由于我把函数都写在一个大类中,进行分析时发现,时间占比最多的函数并不是我写的,而是存在于动态链接库中的函数。最终分析工具并没有指出函数名,显示说是调用堆栈的底部的函数
在这里插入图片描在述在这里插入图片描述在这里插入图片描述在这里插入图片描述

代码说明

主要是将运用的函数装在Sudo类里

class Sudo
{
	public:
		void create(int num);
		void solve(char* file);
		void setvis(int m, int n, int num);
		void resetvis(int m, int n, int num);
		bool checkvis(int m, int n, int num);
		void TraceBack(int n);
};

move对应的是以第一行为基准平移的位数可能情况的排列。13代表一到三行,36代表四到六行,69代表七到九行。

int a[15] = { '1','2','3','4','5','6','7','9' };//生成所用 
char move13[10][5] = { "036", "063" };
char move36[10][5] = { "258", "285", "528", "582", "825", "852" };
char move69[10][5] = { "147", "174", "417", "471", "714", "741" };

应有2 * 6* 6种可能,在每种可能下进行如下操作,最终生成这样一个数独

					for (int ii = 0;ii < 3;ii++)
					{
						move[rows] = move13[i][ii] - '0';
						rows++;
					}
					for (int jj = 0;jj < 3;jj++)
					{
						move[rows] = move36[j][jj] - '0';
						rows++;
					}
					for (int kk = 0;kk < 3;kk++)
					{
						move[rows] = move69[k][kk] - '0';
						rows++;
					}
					for (int l = 0;l < 9;l++)
					{
						int m = move[l];
						fputc(a[(8 + m) % 9], fout);
						for (int n = 1;n < 17;n++)
						{
							fputc(' ', fout);
							fputc(a[((16 - n) / 2 + m) % 9], fout);
							++n;
						}
						fputc('\n', fout);
					}

数独的求解部分,首先要判断数独,之后针对每一个数字字符,进行输入,组成矩阵数组,进行vis判断。最终进行回溯

	while (fscanf(fp1, "%d", &res[t / 9][t % 9]) != EOF)
	{
		if (count != 0)//代表数独数量 
		{
			sudokuu[p++] = '\n';
		}
		for (int t = 1;t < 81;t++)     //读入一个需要求解的数独
			fscanf(fp1, "%d", &res[t / 9][t % 9]);
		suc = 0;
		memset(vis, 0, sizeof(vis));
		for (int t = 0;t < 81;t++)
			if (res[t / 9][t % 9] != 0)   //当前格子有数字,跳到下一格
			{
				setvis(t / 9, t % 9, res[t / 9][t % 9]);
			}
		TraceBack(0);   //回溯求解
		count++;
	}

vis数组中的操作判断

void Sudo::setvis(int m, int n, int num)  //[m,n]有num,则vis对应为1 
{
	vis[0][m][num] = 1;
	vis[1][n][num] = 1;
	int nn;
	nn = m / 3 * 3 + n / 3;
	vis[2][nn][num] = 1;
}
void Sudo::resetvis(int m, int n, int num) //[m,n]无num,则vis对应为0 
{
	vis[0][m][num] = 0;
	vis[1][n][num] = 0;
	int nn;
	nn = m / 3 * 3 + n / 3;
	vis[2][nn][num] = 0;
}
bool Sudo::checkvis(int m, int n, int num)  //检查[m,n]中是否可放num 
{
	int nn;
	nn = m / 3 * 3 + n / 3;
	if (vis[0][m][num] == 0 && vis[1][n][num] == 0 && vis[2][nn][num] == 0)
		return true;
	else
		return false;
}

最终时间

PSP2.1Personal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划
Estimate估计这个任务需要多少时间1520
Development开发
Analysis需求分析2030
Design Spec生成设计文档6060
Design Review设计复审
Coding Standard代码规范
Design具体设计120140
Coding具体编码600700
Code Review代码复审200150
Test测试(自我测试,提交代码,代码修改)400400
Reporting报告3050
Test Report测试报告3050
Size Measurement计算工作量3030
Postme & Process Improvement Plan事后总结并提出过程改进计划3020
合计15201630

项目体会

这次作业我收获很大,随着自己的琢磨,向同学们进行了求助,也帮助了同学,非常开心。其实在考试周之前就开始进行了设计,但是比较大比重的工作都是在最后做的。这也是我第一次独立完成这种比较完整的工作,从设计到实现再到测试,收获很多。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值