软件工程实践2019第三次作业

- Github项目地址

https://github.com/33lc/031702211


- PSP表格

PSP Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划
Estimate 估计这个任务需要多少时间 15 15
Development 开发
Analysis 需求分析 (包括学习新技术) 120 180
Design Spec 生成设计文档 60 90
Design Review 设计复审 30 40
Coding Standard 代码规范 (为目前的开发制定合适的规范) 60 45
Design 具体设计 60 60
Coding 具体编码 240 180
Code Review 代码复审 60 60
Test 测试(自我测试,修改代码,提交修改) 120 150
Reporting 报告
Test Repor 测试报告 150 180
Size Measurement 计算工作量 40 30
Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 60 100
合计 1015 1130

- 计算模块接口的设计与实现过程

void clear(int m);
void input(int m);
void output(int m);
int check(int step,int i,int j,int x);
int build(int step,int i,int j);
int search0(int step);

1. clear函数
由于存在多个盘面需要求解,故在每次解之前需将程序中原数组进行清零,clear函数便用于执行清零操作。

void clear(int step)            //step为阶数
{
	int i, j;
	for (i = 0; i < step; i++)
		for (j = 0; j < step; j++)
			sd[i][j] = 0;
}

2. input函数
用于从文件输入需要解的盘面。

void input(int step)            //step为阶数
{
	int i, j;
	for (i = 0; i < step; i++)
		for (j = 0; j < step; j++)
			cin >> sd[i][j];                //从文件输入sd[i][j]
}

3. output函数
用于向文件输出解出的盘面答案。

void output(int step)           //step为阶数
{
	int i, j;
	for (i = 0; i < step; i++)
	{
		for (j = 0; j < step; j++)
		{
			cout << sd[i][j];           //向文件输出盘面,
			if (j < step - 1)
				cout << " ";
		}
		cout << endl;
	}
	cout << endl;
}

4. check函数
先检测横纵方向是否存在与即将输入的数相同的数,而后检查每一宫内是否存在与即将输入的数相同的数,若存在相同的数则返回,反之返回1。

 int check(int step, int i, int j, int x)           //阶数=step,待填的数横坐标=i,纵坐标=j,待填的数=x
{
	int k, r, c, l;
	for (k = 0; k < step; k++)                  //判断横纵是否存在相同的数
	{
		if (sd[i][k] == x || sd[k][j] == x)
			return 0;                           //存在则返回0
	}
	if (step == 4)                              //判断四宫格内2*2小方格是否存在相同的数
	{
		r = i / 2;
		c = j / 2;
		for (k = r * 2; k < r * 2 + 2; k++)
		{
			for (l = c * 2; l < c * 2 + 2; l++)
				if (sd[k][l] == x)
					return 0;
		}
	}
	else if (step == 9)                     //判断九宫格内3*3小方格是否存在相同的数
	{
		r = i / 3;
		c = j / 3;
		for (k = r * 3; k < r * 3 + 3; k++)
		{
			for (l = c * 3; l < c * 3 + 3; l++)
				if (sd[k][l] == x)
					return 0;
		}
	}
	else if (step == 6)                     //判断六宫格内3*2小方格是否存在相同的数
	{
		r = i / 2;
		c = j / 3;
		for (k = r * 2; k < r * 2 + 2; k++)
		{
			for (l = c * 3; l < c * 3 + 3; l++)
				if (sd[k][l] == x)
					return 0;
		}
	}
	else if (step == 8)                     //判断八宫格内2*4小方格是否存在相同的数
	{
		r = i / 4;
		c = j / 2;
		for (k = r * 4; k < r * 4 + 4; k++)
		{
			for (l = c * 2; l < c * 2 + 2; l++)
				if (sd[k][l] == x)
					return 0;
		}
	}
	return 1;               //若均不存在则返回1
}

5.build函数
看到题目的第一反应是回溯,但是由于不太熟练就不太想打...打了一个暴力版的三宫格,讨论了几种错误情况,逐渐麻烦...然后回来乖乖打回溯。
首先寻找需要填的空位,若该位置已存在数字,继续向下搜索。发现空位后,调用check函数检验1~9中那个数字填入是合法的,若存在合法的数填充后继续向下搜索填充,反之不存在合法的数则将该位置清零,并回溯。填充完毕时标志位op置1并退出。

int build(int step, int i, int j)
{
	int x;
	if (i > step - 1)               //已填充完毕
	{
		op = 1;                 //标志位置1
		return 0;
	}
	else if (sd[i][j] > 0)                  //该位置已存在数字,填充下一个
	{
		if (j < step - 1)                 //未填充到改行末,继续该行填充
			build(step, i, j + 1);
		else                                //已填充到行末,开始填充下一行
			build(step, i + 1, 0);
	}
	else
	{
		for (x = 1; x <= step; x++)         //尝试填入
		{
			if (check(step, i, j, x) == 1)  
			{
				sd[i][j] = x;               //该数字x未冲突,可以填入
				if (j < step - 1)           //未填充到改行末,继续该行填充
					build(step, i, j + 1);
				else                           //已填充到行末,开始填充下一行
					build(step, i + 1, 0);
				if (op == 1)                //标志位已置1,结束
					return 0;
				sd[i][j] = 0;               //出现冲突,清零
			}
		}
	}
	return 0;
}

6. search0函数
经过build和check函数运行后,若盘面仍有部分格子未被填充,说明题目本身是无解的,将通过search0函数进行查找并报错。

int search0(int step)
{
	int i, j;
	for (i = 0; i < step; i++)
	{
		for (j = 0; j < step; j++)
			if (sd[i][j] == 0)
				return -1;
	}
	return 0;
}

7.主函数

int sd[10][10],op=0;        //全局变量
int main(int argc, char *argv[])
{
	int step = atoi(argv[2]), repeat = atoi(argv[4]);
	FILE *stream1, *stream2;
	freopen_s(&stream1,argv[6], "r", stdin);                //输入重定向
	freopen_s(&stream2,argv[8], "w", stdout);            //输出重定向
	while (repeat--)
	{
		op = 0;
		clear(step);                    //清零
		input(step);                    //从文件输入
		build(step, 0, 0);                 //回缩填充
		if (search0(step) == -1)            //无解题判断
			cout << "error:no answer" << endl << endl;
		else
			output(step);
	}
	fclose(stdin);              //关闭输入文件
	fclose(stdout);            //关闭输出文件
	return 0;
}

- 计算模块接口部分的性能


主要的消耗还是在check和build函数,但是还没想到怎么优化...


- 单元测试

- 3阶,5阶,7阶

- 4阶,6阶,8阶

- 9阶


- 异常处理

做了一个无解的异常处理...
无解的情况下,build函数调用完毕后,宫图仍保持输入时有空位的情况,调用search0函数进行判断。


- 心得体会

数独从小就在玩,甚至现在手机里还有app(虽然因为有段时间没开它不兼容了...),但从未站在另一个角度去思考在解数独时会遇到什么?无解?多解?计算机应该怎么去处理这些情况?以后看问题也可以尝试从程序设计的角度去思考,或许会有不一样的发现。
这次实验一开始蛮迷茫的,int main(int argc,char *argv[])、文件输入输出,这些看着熟悉但是并没有用过的东西...文件输入输出本是c语言的内容,但当时这一章被跳过,自己也没有继续去学习。在这次实验中才开始学习,开始尝试寻找适合这次题目的输入方式。
在翻看《构建之法》时看到“这些同学是真的懂软件工程,是一个合格的软件工程师吗?”是啊,我也常常想过去的两年时光究竟学了什么,看似学了很多,却又像什么都不会...许多人都在追求完美,但完美真的存在吗?存在的只有相应时间空间下的“足够好”罢了。

posted @ 2019-09-25 16:50  咕叽  阅读(234)  评论(0编辑  收藏  举报