结对作业

这个作业属于哪个课程 网工19-软件工程
这个作业的要求 作业要求
这个作业的目标 实现一个自动生成小学四则运算题目的命令行程序
小队成员 3119005340孙斌 3119005323黄宇洋
Github地址 Github链接

一、PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 15 10
· Estimate · 估计这个任务需要多少时间 15 10
Development 开发 1055 1220
· Analysis · 需求分析 (包括学习新技术) 200 270
· Design Spec · 生成设计文档 60 70
· Design Review · 设计复审 (和同事审核设计文档) 30 20
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 25 15
· Design · 具体设计 200 290
· Coding · 具体编码 400 440
· Code Review · 代码复审 70 60
· Test · 测试(自我测试,修改代码,提交修改) 70 55
Reporting 报告 85 65
· Test Report · 测试报告 35 30
· Size Measurement · 计算工作量 20 15
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 30 20
合计 1155 1295

二、模块设计

模块结构

FileWrite类:写文件,将生成的题目和答案写入文件Execrises.txt和Answer.txt中
FormulaCheck类:检查生成的式子是否重复
FormulaCreate类:生成随机的四则运算式子
ResultsCalculate类:计算生成的题目的答案

三、部分代码说明

FileWrite类

//生成并输出Exercises.txt、Answer.txt
public void createProblemSet(int n,int r){

    FormulaCheck temporarySet = new FormulaCheck();
    ArrayList returnList = temporarySet.generate(n,r);
    ArrayList<String> exercisesList = new ArrayList<>();
    ArrayList<String> answerList = new ArrayList<>();

    for (int i = 0;i < 2*n;i++) {
        if(i < n) exercisesList.add(returnList.get(i).toString());
        else answerList.add(returnList.get(i).toString());
    }
    createExercisesFile(exercisesList);
    createAnserFile(answerList);
}

//生成并输出Exercises.txt
public static void createExercisesFile(ArrayList txtList){
    try{
        File exercisesTxt = new File("Exercises.txt");

        //若文件存在,删除文件
        if (exercisesTxt.exists()) {
            exercisesTxt.delete();
        }
        if(exercisesTxt.createNewFile()){
            System.out.println("\n————生成Exercises.txt中————");
            FileOutputStream txtFile = new FileOutputStream(exercisesTxt);
            PrintStream q = new PrintStream(exercisesTxt);

            for(int i = 0;i < txtList.size();i++){
                q.println(i+1 + ". " +txtList.get(i));
            }
            txtFile.close();
            q.close();
            System.out.println("\n****** Exercises.txt 生成成功! ******");

        }
    }
    catch(IOException ioe) {
        ioe.printStackTrace();
    }
}

//生成并输出Answer.txt
public static void createAnserFile(ArrayList ansList){
    try{

        File answerTxt = new File("Answer.txt");

        //若文件存在,删除文件
        if (answerTxt.exists()) {
            answerTxt.delete();
        }

        if(answerTxt.createNewFile()){
            System.out.println("\n————生成Answer.txt中————");
            FileOutputStream ansFile = new FileOutputStream(answerTxt);
            PrintStream p = new PrintStream(answerTxt);
            for(int i = 0;i < ansList.size();i++){
                p.println(i+1 + ". " +ansList.get(i));
            }
            ansFile.close();
            p.close();
            System.out.println("\n****** Answer.txt 生成成功! ******");
        }
    }
    catch(IOException ioe) {
        ioe.printStackTrace();
    }
}

// 生成并输出Grade.txt
public void createGradeFile(String submitPath, String answersPath) {
    try {

        ArrayList<String> submitList = obtainAnswer(submitPath);
        ArrayList<String> answersList = obtainAnswer(answersPath);
        ArrayList<String> WQuesNum = new ArrayList<>();
        ArrayList<String> TQuesNum = new ArrayList<>();

        for (int i = 0; i < submitList.size(); i++) {
            if (submitList.get(i).equals(answersList.get(i)))
                WQuesNum.add(String.valueOf(i+1));
            else
                TQuesNum.add(String.valueOf(i+1));
        }

        File gradeTxt = new File("Grade.txt");

        //若文件存在,删除文件
        if (gradeTxt.exists()) {
            gradeTxt.delete();
        }

        if (gradeTxt.createNewFile()) {
            System.out.print("创建Grade.txt:");
            FileOutputStream gradeFile = new FileOutputStream(gradeTxt);
            PrintStream p = new PrintStream(gradeTxt);

            p.print("Correct:");
            output(p, TQuesNum);
            p.print("Wrong:");
            output(p, WQuesNum);

            gradeFile.close();
            p.close();
            System.out.println("Grade.txt 创建成功!");
        }
    }
    catch(IOException ioe) {
        ioe.printStackTrace();
    }
}

//输出答案
private void output(PrintStream p,ArrayList quesNum) {
    p.print(quesNum.size() +"(");
    for(int i = 0;i < quesNum.size();i++){
        System.out.print(">");
        if (i < quesNum.size()-1)
            p.print(" " + quesNum.get(i) + ",");
        else
            p.print(" " + quesNum.get(i));
    }
    p.println(" )\n");
}

//获取文件答案
private ArrayList<String> obtainAnswer(String path) throws IOException {
    ArrayList<String> answerList = new ArrayList<>();
    BufferedReader answerFile = new BufferedReader(new FileReader(path));
    String answerLine = null;

    while ((answerLine = answerFile.readLine()) != null) {
        answerLine = answerLine.replace(" ", "");
        if (answerLine.indexOf('.') >= 0) {
            if (answerLine.length() > 2)
                answerList.add(answerLine);
        }
    }
    return answerList;
}

ResultsCalculate类

public String[] checkout(String formula, int length) {
    Stack<String> stackN = new Stack<>();//操作数
    Stack<String> stackO = new Stack<>();//操作符
    String[] RPN = new String[length];//逆波兰表达式

    // 哈希表存放运算符优先级
    HashMap<String, Integer> hashmap = new HashMap<>();
    hashmap.put("(", 0);
    hashmap.put("+", 1);
    hashmap.put("-", 1);
    hashmap.put("×", 2);
    hashmap.put("÷", 2);

    for (int i = 0, j = 0; i < formula.length(); ) {
        StringBuilder num = new StringBuilder();
        //切割式子
        char c = formula.charAt(i);
        //若c为数字,存入num
        while (Character.isDigit(c) || c == '/' || c == '\'') {
            num.append(c);
            i++;
            c = formula.charAt(i);
        }
        //num里无数字,处理符号
        if (num.length() == 0) {
            switch (c) {
                //如果是“(”转化为字符串压入字符栈
                case '(': {
                    stackO.push(String.valueOf(c));
                    break;
                }
                //遇到“)”了,进行计算
                case ')': {
                    String operator = stackO.pop();
                    //符号栈里有符号时,取操作数运算
                    while (!stackO.isEmpty() && !operator.equals("(")) {
                        String a = stackN.pop();
                        String b = stackN.pop();
                        //后缀表达式变形
                        RPN[j++] = a;
                        RPN[j++] = b;
                        RPN[j++] = operator;
                        String ansString = calculate(b, a, operator);
                        if (ansString == null)
                            return null;
                        //将结果压入栈
                        stackN.push(ansString);
                        //符号指向下一个计算符号
                        operator = stackO.pop();
                    }
                    break;
                }
                //遇到了“=”,计算最终结果
                case '=': {
                    String operator;
                    while (!stackO.isEmpty()) {
                        operator = stackO.pop();
                        String a = stackN.pop();
                        String b = stackN.pop();
                        //后缀表达式变形
                        RPN[j++] = a;
                        RPN[j++] = b;
                        RPN[j++] = operator;
                        String ansString = calculate(b, a, operator);
                        if (ansString == null)
                            return null;
                        stackN.push(ansString);
                    }
                    break;
                }
                //其他
                default: {
                    String operator;
                    while (!stackO.isEmpty()) {
                        operator = stackO.pop();
                        if (hashmap.get(operator) >= hashmap.get(String.valueOf(c))) { //比较优先级
                            String a = stackN.pop();
                            String b = stackN.pop();
                            //后缀表达式变形
                            RPN[j++] = a;
                            RPN[j++] = b;
                            RPN[j++] = operator;
                            String ansString = calculate(b, a, operator);
                            if (ansString == null)
                                return null;
                            stackN.push(ansString);
                        } else {
                            stackO.push(operator);
                            break;
                        }

                    }
                    stackO.push(String.valueOf(c));  //将符号压入符号栈
                    break;
                }
            }
        }
        //处理数字,直接压栈
        else {
            stackN.push(num.toString());
            continue;
        }
        i++;
    }
    //栈顶数字为答案
    RPN[length - 3] = "=";
    RPN[length - 2] = stackN.peek();
    RPN[length - 1] = formula;
    return RPN;
}


//计算式子
private String calculate(String m, String n, String operator) {
    String ansFormula = null;
    char op = operator.charAt(0);
    int[] indexFraction = {m.indexOf('\''), m.indexOf('/'), n.indexOf('\''), n.indexOf('/')};//分数 各部分 切割位置

    //处理分数运算
    if (indexFraction[1] > 0 || indexFraction[3] > 0) {
        int[] denominator = new int[3];
        int[] molecule = new int[3];
        int[] integralPart = new int[3];

        //切割分数
        if (indexFraction[1] > 0) {
            for (int i = 0; i < m.length(); i++) {
                if (i < indexFraction[0]) {
                    integralPart[0] = Integer.parseInt(integralPart[0] + String.valueOf(m.charAt(i) - '0'));
                } else if (i > indexFraction[0] && i < indexFraction[1]) {
                    molecule[0] = Integer.parseInt(molecule[0] + String.valueOf(m.charAt(i) - '0'));
                } else if (i > indexFraction[1]) {
                    denominator[0] = Integer.parseInt(denominator[0] + String.valueOf(m.charAt(i) - '0'));
                }
            }
        } else {
            integralPart[0] = Integer.parseInt(m);
            denominator[0] = 1;
            molecule[0] = 0;
        }

        if (indexFraction[3] > 0) {
            for (int i = 0; i < n.length(); i++) {
                if (i < indexFraction[2]) {
                    integralPart[1] = Integer.parseInt(integralPart[1] + String.valueOf(n.charAt(i) - '0'));
                } else if (i > indexFraction[2] && i < indexFraction[3]) {
                    molecule[1] = Integer.parseInt(molecule[1] + String.valueOf(n.charAt(i) - '0'));
                } else if (i > indexFraction[3]) {
                    denominator[1] = denominator[1] + n.charAt(i) - '0';
                }
            }
        } else {
            integralPart[1] = Integer.parseInt(n);
            denominator[1] = 1;
            molecule[1] = 0;
        }

        //分数运算
        switch (op) {
            case '+': {
                denominator[2] = denominator[0] * denominator[1];
                molecule[2] = integralPart[0] * denominator[2] + molecule[0] * denominator[1] + integralPart[1] * denominator[2] + molecule[1] * denominator[0];
                break;
            }
            case '-': {
                denominator[2] = denominator[0] * denominator[1];
                molecule[2] = integralPart[0] * denominator[2] + molecule[0] * denominator[1] - integralPart[1] * denominator[2] - molecule[1] * denominator[0];
                break;
            }
            default:
                return null;
        }

        //提取整数部分
        if (molecule[2] >= denominator[2] && molecule[2] > 0) {
            integralPart[2] = molecule[2] / denominator[2];
            molecule[2] = Math.abs(molecule[2] % denominator[2]);
        } else if (molecule[2] < 0) {
            return null;
        }

        //化简分数
        if (molecule[2] != 0) {
            ansFormula = greatFraction(integralPart[2], molecule[2], denominator[2]);
        } else ansFormula = String.valueOf(integralPart[2]);

    } else { //处理整数运算
        int a = Integer.parseInt(m);
        int b = Integer.parseInt(n);

        switch (op) {
            case '+': {
                ansFormula = String.valueOf(a + b);
                break;
            }
            case '-': {
                if (a - b >= 0)
                    ansFormula = String.valueOf(a - b);
                else
                    return null;
                break;
            }
            case '×': {
                ansFormula = String.valueOf(a * b);
                break;
            }
            case '÷': {
                if (b == 0) {
                    return null;
                } else if (a % b != 0) {
                    ansFormula = a % b + "/" + b;
                    if (a / b > 0) ansFormula = a / b + "'" + ansFormula;
                } else
                    ansFormula = String.valueOf(a / b);
                break;
            }
        }
    }
    return ansFormula;
}

//化简分数
private String greatFraction(int integralPart, int molecule, int denominator) {
    String ansFormula;
    int commonFactor = 1;

    //求最大公约数
    FormulaCreate create = new FormulaCreate();
    commonFactor = create.commonFactor(denominator, molecule);

    //化简分数
    denominator /= commonFactor;
    molecule /= commonFactor;

    //带分数
    if (integralPart == 0 && molecule > 0) {
        ansFormula = String.valueOf(molecule) + '/' + String.valueOf(denominator);
    } else if (molecule == 0)
        ansFormula = String.valueOf(integralPart);
    else {
        ansFormula = String.valueOf(integralPart) + "'" + String.valueOf(molecule) + '/' + String.valueOf(denominator);
    }
    return ansFormula;
}

四、性能分析


五、测试实例

10道题目

输入指令

生成的Execrises.txt文件

生成的Answer.txt文件

10000道题目

指令输入

生成的Execrises.txt文件

生成的Answer.txt文件

六、项目小结

黄宇洋:这是我第一次进行多人共同编程,没有太多的协同合作的经验,再加上我们两个人的水平很低很低,所以这一次的编程进行的磕磕绊绊,从进行分工到各自完成完成任务经历了很多的困难,也从网上找了许多资料参考。通过了这次的结对作业,充分认识到了编程能力的不足,以及了解到了协同合作的重要性和艰难,也更多的了解了软件工程这门课程。
孙斌:本次结对项目对于我们而言,其意义是更多地去考验我们的分工协调和如何高效合作。通过这次结对项目,我们明白了好搭档一起合作对于项目的进程有很大的帮助外,也让我们更加有责任心,知道项目不只是一个人的事情。

posted @ 2021-10-26 00:36  Hysty  阅读(60)  评论(0)    收藏  举报