软件基础个人工程——数独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

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

2)、SolvingSudoku.cpp

检查数独:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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求解数独:

1
inline int SolvingByDFS(int n)

 求解文件中的多个数独:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
inline void MovingStep()
{<br>     \\平移方式的种类
    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;<br>     \\求取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++;
            }
        }
    }
} 

生成数独:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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;<br>              //生成例如891234567891234567的18位数组方便计算
            memcpy(JointLine, RequestFirstline, sizeof(RequestFirstline));
            memcpy(&JointLine[9], RequestFirstline, sizeof(RequestFirstline));<br>              //对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));
            }<br>              //写入文件
            WritePutsToFile(fp, ResultingSudoku);
            num++;
        }
    }
    if(fp!=0)fclose(fp);
    return true;
}

2、代码质量分析 

 

 3、代码性能分析

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

 

 

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

原写入为:

 

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

优化后写入:

 

 再对其进行性能分析:

 

 

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

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

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

posted @   picaqiu  阅读(243)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示