软件基础个人工程——数独3

GITHUB项目地址:

https://github.com/hhz-hhz/Sudoku_software_engineer.git

软工基础个人项目——数独1

软工基础个人项目——数独2

二、设计阶段

5、对于设计文档的补充

除了对于代码的设计外之前还需要对单元测试进行设计:

DefiningBeginning.cpp中:

1)int ChageStringToNumber(char s[])进行单元测试:测试输入字符串是数字的情况和输入字符串不是数字的情况

2)void WritePutsToFile(FILE* fp, SUDOKU m)进行单元测试:测试是否能够对文件进行写入

SolvingSudoku.cpp中:

1)inline bool CheckingForDFS(int n, int key)进行单元测试:需要进行符合数独规范和不符合数独规范的验证

2)inline int SolvingByDFS(int n)进行单元测试:对于一个带求解的数独进行测试

3)bool SolvingSudoku(FILE* rfp)进行单元测试:对于一个固定文件中的数独进行求解

GeneratingSudoku.cpp中:

1)inline void MovingStep()进行单元测试:查看是否能够运行出符合要求的位移矩阵

main.cpp中:

1)int main(int argc, char* argv[])进行单元测试:正确的命令和错误的命令、是否能够正确的求解数独,是否能够生成数独

三、编程阶段

1、代码说明

1)、DefiningBeginning.cpp

int ChageStringToNumber(char s[])\\利用isdigit()判断是否是数字字符
void WritePutsToFile(FILE* fp, SUDOKU m)\\由于生成数独和求解数独都需要写入文件,所以将它变成函数

2)、SolvingSudoku.cpp

检查数独:

inline bool CheckingForDFS(int n, int key)\\判断key是否能够填入
{
	for (int i = 0; i < 9; i++)\\判断n所在横列是否合格
	{
		int j = n / 9;
		if (DoSudoku.map[j][i] == key)return false;
	}

	for (int i = 0; i < 9; i++)\\判断n所在竖列是否合格
	{
		int j = n % 9;
		if (DoSudoku.map[i][j] == key)return false;
	}

	int x = n / 9 / 3 * 3;
	int y = n % 9 / 3 * 3;
	for (int i = x; i < x + 3; i++)\\判断n所在的9宫格是否合格
	{
		for (int j = y; j < y + 3; j++)
		{
			if (DoSudoku.map[i][j] == key)return false;
		}
	}

	return true;
}

 DFS求解数独:

inline int SolvingByDFS(int n)

 求解文件中的多个数独:

bool SolvingSudoku(FILE* rfp)
{
	FILE *wfp;
	errno_t err;
	err = fopen_s(&wfp, "sudoku.txt", "w");
	if (err != 0)
	{
		return false;
	}

	char blank;
	do {
		for (int i = 0; i < 9; i++)\\读入文件
		{
			for (int j = 0; j < 9; j++)
			{
				fscanf_s(rfp, "%d%c", &DoSudoku.map[i][j], &blank, sizeof(int) + sizeof(char));
			}
		}
		SolvingByDFS(0);
		sign = false;\\递归停止标志
		WritePutsToFile(wfp, DoSudoku);\\写入文件中

	} while (fscanf_s(rfp, "%c", &blank, sizeof(char)) != EOF);
	
	if (wfp != 0)fclose(wfp);
	return true;
}

3)GeneratingSudoku.cpp

生成平移步数矩阵:MovingStepDic[72][9]

inline void MovingStep()
{
     \\平移方式的种类 int MovingDic1[2][3] = { { 0,3,6 },{ 0,6,3 } }; int MovingDic2[6][3] = { { 1,4,7 },{ 1,7,4 },{ 4,1,7 },{ 4,7,1 },{ 7,4,1 },{ 7,1,4 } }; int MovingDic3[6][3] = { { 2,5,8 },{ 2,8,5 },{ 5,2,8 },{ 5,8,2 },{ 8,2,5 },{ 8,5,2 } }; int step[10]; int count = 0;
     \\求取2*6*6种变换方式矩阵 for (int i = 0; i < 6; i++) { for (int j = 0; j < 6; j++) { for (int k = 0; k < 2; k++) { memcpy_s(&step[0], 3 * sizeof(int), &MovingDic1[k][0], 3 * sizeof(int)); memcpy_s(&step[3], 3 * sizeof(int), &MovingDic2[j][0], 3 * sizeof(int)); memcpy_s(&step[6], 3 * sizeof(int), &MovingDic3[i][0], 3 * sizeof(int)); memcpy_s(&MovingStepDic[count], 9 * sizeof(int), &step[0], 9 * sizeof(int)); count++; } } } } 

生成数独:

bool GeneratingSudoku(int n)
{
	FILE *fp;
	errno_t err;
	err = fopen_s(&fp, "sudoku.txt", "w");
	if (err != 0) {
		return false;
	}
	MovingStep();
	int RequestFirstline[9] = { 8,9,1,2,3,4,5,6,7 };\\按照规定,第一位是8
	int JointLine[18];
	int num = 0;
	SUDOKU ResultingSudoku;
	memset(ResultingSudoku.map, 0, sizeof(ResultingSudoku.map));
	while (next_permutation(&RequestFirstline[1], &RequestFirstline[9]))\\生成全排列
	{
		if (num >= n)break;
		for (int i = 0; i < 72; i++)
		{
			if (num >= n)break;
              //生成例如891234567891234567的18位数组方便计算 memcpy(JointLine, RequestFirstline, sizeof(RequestFirstline)); memcpy(&JointLine[9], RequestFirstline, sizeof(RequestFirstline));
              //对JointLine数组进行截取 int j = num % 72; for (int k = 0; k < 9; k++) { int l = MovingStepDic[j][k]; memcpy(&ResultingSudoku.map[k], &JointLine[l], 9 * sizeof(int)); }
              //写入文件 WritePutsToFile(fp, ResultingSudoku); num++; } } if(fp!=0)fclose(fp); return true; }

2、代码质量分析 

 

 3、代码性能分析

1)、对于生成数独进行性能分析

 

 

 可以看到fprintf和WritePutsToFile()占用较大的比重,因为WritePutsToFile()中也较多使用fprintf,所以对写入文件函数WritePutsToFile进行优化比较合适。

原写入为:

 

 本来设计说这样的代码虽然有些粗鲁,但是比较快。因为会一次性写入9个数字及空格。如果要做优化,不如一次性写入所有元素。

优化后写入:

 

 再对其进行性能分析:

 

 

 经过优化后,时间上有了较大的改进。

2)、对于求解数独进行性能分析

软件基础个人工程——数独4

posted @ 2020-01-16 22:26  picaqiu  阅读(238)  评论(0编辑  收藏  举报