2020软件工程作业03

这个作业属于哪个课程 https://edu.cnblogs.com/campus/zswxy/software-engineering-2017-1
这个作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/software-engineering-2017-1/homework/10494
这个作业的目标 编写数独小程序,并对其进行性能优化,单元测试
作业正文 下文
其他参考文献 百度

Github地址:https://github.com/Dagenjun-kami/Sudoku

PSP表格

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

思路描述

数独是我日常喜欢玩的一款游戏,但是玩的时候基本上是凭经验和感觉的,要我解释我是如何解数独,以我的表达能力也说不出什么。电脑解数独的话,我认为就是一格一格1-9不断尝试,无法填入就返回上一格,直到盘面全部填满为止,通过百度,我了解到这应该是叫做回溯法。

大致思路是有了,但是编程不仅仅是有了思路即可的,技术不达标,一切都是空话。

要实现数独程序,需要解决以下问题:

1.如何使用命令行传入参数

2.如何实现txt文件读入并存入数组及txt文件的写出

3.如何实现解数独

通过我的不懈努力(百度),找出了各种各样的解决方法,接下来就剩领悟这些代码了,看了大佬们的博客之后越来越觉得自己就是个废物

好在最后终于!还是把代码给逼了出来!

在此感谢那些网络上的大佬们!要不然咱这样的渣渣哪能够按时完成作业呢

功能模块设计

  • 读取指令模块

    主函数的String args[]可以传入命令行的参数,用load()函数对args[]进行处理

    public static void load(String args[])
    {
        m = Integer.valueOf(args[1]);
        n = Integer.valueOf(args[3]);
        inputFileName = args[5];
        outputFileName = args[7];
    }
  • 文件IO模块

    这部分对我来说是最困难的。

    事实证明有关IO的知识,我是完全没有学好,哎,没法,只能慢慢仔细研究网上大佬的代码了,研究了老半天,总算有了点头绪

    用split()将txt文件分割保存为字符串数组,再通过Integer.parseInt()保存为m*m整型二维数组

        static void fileIO()
        {
            try
            {
                BufferedReader br = new BufferedReader(new FileReader(inputFileName));
                PrintStream ps  = new PrintStream(new FileOutputStream(outputFileName,true));
                System.setOut(ps);
                for(int p=0 ; p<n ; p++)
                {
                    int i=0;String s;
                    boolean first = true;
                    int emptyRow = 0,emptyCol = 0;
                    //读入文件写入数组循环
                    for(int k=0 ; k < m ; k++) {
                        if ((s = br.readLine()) != null);
                        {
                            String[] temp = s.split(" ");
                            for (int j = 0; j < m; j++) {
                                sudoku[i][j] = Integer.parseInt(temp[j]);
                                if (sudoku[i][j] == 0)
                                {
                                    if (first) {
                                        emptyRow = i;
                                        emptyCol = j;
                                        first = false;
                                    }
                                    emptyNum++;
                                }
                            }
                            i++;
                        }
                    }
                    backTrace(emptyRow,emptyCol);
                    if(p<n-1) {
                        System.out.println();
                    }
                    br.readLine();
                }
                br.close();
                ps.close();
            }
            catch (FileNotFoundException e1)
            {
                e1.printStackTrace();
                System.exit(-1);
            }
            catch (IOException e2)
            {
                e2.printStackTrace();
                System.exit(-1);
            }
        }
    
  • 判断行列宫有无重复模块

    先判断行列,重复则返回false,再判断宫,3,5,7没有宫就直接返回true,4,6,8,9有宫的先定义宫的大小,计算每个宫第一格坐标,再用两个For循环判断

    public static Boolean judge(int a[][],int row, int col, int num,int m) {
        for (int i = 0; i < m; i++) {
            if (i != row && a[i][col] == num) {
                return false;
            }
            if (i != col && a[row][i] == num) {
                return false;
            }
        }
        int x, y, px = 0 , py = 0;
        //宫的大小
        if (m == 3 || m == 5 || m == 7) {
            return true;
        }
        if (m == 4) {
            px = 2;
            py = 2;
        } else if (m == 6) {
            px = 2;
            py = 3;
        } else if (m == 8) {
            px = 4;
            py = 2;
        } else if (m == 9) {
            px = 3;
            py = 3;
        }
        //(x,y)是(row,col)所属小宫格第一格的坐标
        x = row / px * px;
        y = col / py * py;
        for (int i = x; i < x + px; i++) {
            for (int j = y; j < y + py; j++) {
                if (i != row && j != col && a[i][j] == num) {
                    return false;
                }
            }
        }
        return true;
    }
  • 回溯法解数独模块
    画了一个简单的流程图

        static void backTrace(int row , int col)
        {
            for(int i = 1 ; i <= m ;i++)
            {
                //填上行列宫不重复数字
                if(judge(sudoku,row,col,i,m))
                {
                    sudoku[row][col] = i ;
                    emptyNum--;
                    //填完所有空缺
                    if(emptyNum==0)
                    {
                        print();
                        break;
                    }
                    int tempArray[] ;
                    tempArray = nextEmpty(row,col);
                    backTrace(tempArray[0] ,tempArray[1]);
                    //回溯
                    sudoku[row][col] = 0;
                    emptyNum++;
                }
            }
        }
    
    
  • 待填空缺定位模块

    用两个for循环嵌套,找出为零的坐标

    测试过程

在测试过程中出现这样的情况,开始以为代码有错,检查了老半天,结果发现是输入数独第一个和第三个无解!

不过,这也告诉我程序缺少报错功能!

用flag判断结果是否输出即可解决此问题

测试结果

编写有且只有一个结果的数独太麻烦了,所以就挑选几条有代表性的进行测试

就酱吧!

性能优化

嗯......完全看不懂!还全是英文,百度了也百思不得其解

慢慢研究吧

总结

这次作业让我明白了自己的不足,也促使我去学习新知识,关于单元测试和性能分析优化啥的,真是一窍不通,完成作业的过程是很痛苦的,交作业的紧迫感使得我这名养生的中年少女开始熬夜,每天醒来只想搞学习,结果……还算愉快?编写出程序还是有些成就感的,希望我可以进步吧!交作业截止时间迫在眉睫,先这样吧,没有完成的部分,希望我能够在后续完成。

编程技术得到提高的话,熬的夜应该会少点了……吧?

自评

原文地址:https://www.cnblogs.com/kami233/p/12591556.html