软件基础个人工程——数独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)、对于求解数独进行性能分析



浙公网安备 33010602011771号