zoukankan      html  css  js  c++  java
  • 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/Yura-hub/homework/tree/master/20177638/src/soduku/src

    二、PSP表格

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

    三、思路描述

    • 初始思考

    刚拿到题目,我整个人是懵圈的,第一反应是题目好长好长(是真的很长)一时不知从何下手,然后把网页×掉了...×掉..了

    第二次鼓起勇气打开作业,沉住气看了一遍,了解了这是个编写数独程序的任务,要求是经过分析消除错误警告,再进行单元测试以及改进...然后我发现我不懂算法....学!于是开始到处找资料...确定用回溯。

    • 需求

    实现一个命令行程序,不妨称之为Sudoku。

    • 规则

      • 百度百科简介:
        数独盘面是个九宫,每一宫又分为九个小格。在这八十一格中给出一定的已知数字和解题条件,利用逻辑和推理,在其他的空格上填入1-9的数字。使1-9每个数字在每一行、每一列和每一宫中都只出现一次,所以又称“九宫格”。
      • 题目要求:
        1.程序能生成不重复的数独终局至文件;
        2.程序能读取文件内的数独问题,求一个可行解并将结果输出到文件;
      • 查找资料:
        首先我去网上搜索了一下解决数独问题有哪些方法,网上有很多什么回溯算法、三链数法、侯选数法、频率法等等balabala一堆。最后决定用比较常规的方法——回溯。我并不熟悉这个算法的使用,参考了这里的资料:LeetCode 31:递归、回溯、八皇后、全排列一篇文章全讲清楚
        还有在实现过程中遇到了很多不会的,百度了n次。

    四、实现过程

    分为了两个部分Sudoku和Lib类,也就是解数独和FileIO两部分。

    • 结构图

    • 测试用例

    五、改进过程

    • Code Quality Analysis工具分析

    • 性能测试
      原谅我使用JProfiler还不熟练...分析的还是看不太明白(顺便bb一句,英语有必要好好学一下..不然就像我一样——看不懂...微笑.jpg)

    六、代码说明

    • 回溯
    /**
         * 回溯填充方法
         * @param row
         * @param col
         */
        public void backtrack(int row, int col) {
    
    
            if(shudoPan[row][col] == 0) {
                for(int d = 1; d <= m; d++) {
                    int idx = 0;
                    if(boxRow > 0) {
                        idx = (row / boxRow ) * boxRow + col / boxCol;
                    }
    
                    if(couldPlace(d, row, col)) {
                        //填充数字,并设置填充限制
                        boxOccupied[idx][d]++;
                        rowOccupied[row][d]++;
                        colOccupied[col][d]++;
                        shudoPan[row][col] = d;
                        //是否填充到最后一格
                        if ((col == m-1) && (row == m-1)) {
                            sudokuSolved = true;
                        }
                        else {
                            //当到达最后一列的格子,下一个格子跳转到下一行
                            if (col == m-1) {
                                backtrack(row + 1, 0);
                            }else {
                                backtrack(row, col + 1);
                            }
                        }
                        if(!sudokuSolved) {//移除填充后无法进行后续填充的数
    
                            boxOccupied[idx][d]--;
                            rowOccupied[row][d]--;
                            colOccupied[col][d]--;
                            shudoPan[row][col] = 0;
                        }
                    }
                }
            }else {
                if ((col == m-1) && (row == m-1)) {
                    sudokuSolved = true;
                }
                else {
                    //当到达最后一列的格子,下一个格子跳转到下一行
                    if (col == m-1) {
                        backtrack(row + 1, 0);
                    }else {
                        backtrack(row, col + 1);
                    }
                }
            }
        }
    
    • 解数独
       /**
         * 解数独方法
         */
        public void solveSudoku(int[][] shudoPan) {
            setBox();//调用设置宫的行列数方法
            //System.out.println("boxRow,boxCol:"+boxRow+" "+boxCol);
    
            // 初始化某数所在行、列、宫
            for (int i = 0; i < m; i++) {
                for (int k = 0; k < m; k++) {
                    int num = shudoPan[i][k];
                    if (num != 0) {
                        int d = num;
                        if(boxRow > 0) {
                            int idx = (i / boxRow ) * boxRow + k / boxCol;
                            boxOccupied[idx][d]++;
                        }
                        rowOccupied[i][d]++;
                        colOccupied[k][d]++;
                    }
                }
            }
            backtrack(0, 0);
        }
    }
    
    • 写入文件
    /**
         * 写入文件
         */
        public void writeFile(boolean isDone){
            try {
                FileWriter bw = null;
                File newFile = new File(outputPath);
                if(!newFile.exists()) {
                    newFile.createNewFile();
                }
                if(isDone == true) {
                    bw = new FileWriter(newFile,isDone);
                    {
                        for(int i = 0;i < m; i++) {
                            for(int k = 0; k < m; k++) {
                                if(k != m-1) {
                                    bw.write(String.valueOf(shudoPan[i][k]));
                                    bw.write(" ");
                                }else {
                                    bw.write(String.valueOf(shudoPan[i][k]));
                                    bw.write("
    ");
                                }
                            }
                        }
                        bw.write("
    ");
                        bw.flush();
                        bw.close();
                    }
                }else {
                    bw = new FileWriter(newFile,isDone);
                    bw.write("");
                }
    
            }catch(IOException e) {
                e.printStackTrace();
            }
        }
    
    • 读文件
    /**
         * 读取
         * @param inputPath
         */
        public void readFile() {
             //判断文件是否存在
            if(inputPath==null||!(new File(inputPath).exists())){
                System.out.println("输入文件不存在……");
                System.exit(1);
            }
            //为了防止错误,用catch捕捉错误并打印
            try (FileReader reader = new FileReader("");
                 BufferedReader br = new BufferedReader(reader) 
            ) {
                while(true) {
                    try {
                        String line = br.readLine();
                        if(!line.equals("")) {
                            hang.add(line);
                        }else {
                            continue;
                        }
                    }catch(NullPointerException ex) {
                        break;
                    }
                }
                if(hang.size() < m*n) {
                    System.out.println("读取文件为空……");
                    System.exit(1);
                }
            }catch(IOException e) {
                e.printStackTrace();
            }
        }
    

    七、异常处理

    参数传入,输入格式不正确,或者找不到目标文件,还有读取对象创建失败都有可能报错。

    八、心路历程以及收获

    数独的解法我通过查资料,网上找到了许多方法,代码好不容易通过了。

    但是...文件输入输出流这里我又卡了....

    加了这个以后首先传不了参数,后来又找不到文件,最后改了很久很久,问了班上的大佬(哈哈打扰了很久,非常感谢!!)之后重新建了一遍类还有文件,才通过,关于代码我倒是没有改,不知道之前是错了哪里。做完之后,测试了一下三宫格和五宫格,成功用文本输出了。还存在很多问题没有完善,准备慢慢改,之前的基础不好,很多东西学了就忘了,导致这次作业从开始到结束都遇到了各种大大小小的问题,进行的很困难,中间一度中断过几次。目前这样还有很大的改进空间,比如对异常的处理,还有许多要学习的地方,面对错误现在还不够淡定非常抓狂,最后好好学习..天天向上..感谢大佬感谢百度!!

    九、自我评价

    作业头是否完整 2' 2
    Github地址 1' 1
    代码要求经过Code Quality Analysis工具的分析并消除所有的警告 2' 2
    PSP表格 2'(估计1'实际1') 2
    实际过程 2'(代码组织0.5'、关键函数画出流程图1'、单元测试0.5') 1
    改进程序性能 2'(展示关键代码1'、解释思路并说明1') 0.5
    结合构建之法谈心路历程和感想 1' 0.5
    总分 12' 9
  • 相关阅读:
    HEC-ResSim原文档
    水文模型大全
    用word发布博客到博客园
    给你的浏览器标题栏加上小图标
    系统性能调优必知必会学习
    系统性能调优必知必会学习
    容器化学习
    Redisson学习
    mysql回顾
    事物、源码学习,spring-tx
  • 原文地址:https://www.cnblogs.com/tang1/p/12584202.html
Copyright © 2011-2022 走看看