结对项目

结对编程:小学四则运算

这个作业属于哪个课程 软件工程课程
这个作业要求在哪里 个人项目 - 作业 - 计科22级34班 - 班级博客 - 博客园 (cnblogs.com)
这个作业的目标
成员一 迪力拜尔3222004889
成员二 坤杜孜阿依3222004768
github链接 https://github.com/dilibar-code/pair-item3222004889-4768

目录

  • 1.需求分析
  • 1.1题目
  • 1.2需求分析
  • 2.开发环境
  • 2.1工程结构
  • 2.2总体设计
  • 3.代码实现及设计
  • 3.1 Main类
  • 3.2 Create类
  • 3.3 CheckRepeat类
  • 3.4 CheckAnswer 类
  • 3.5 problemSet类
  • 4.测试
  • 4.1性能分析和内存分析
  • 4.2测试运行
  • 5.项目小结
  • 6.PSP表格
    1.需求分析
    1.1题目
    1.实现一个自动生成小学四则运算题目的命令行程序(也可以用图像界面,具有相似功能)。

2.生成的题目中计算过程不能产生负数,也就是说算术表达式中如果存在形如e1− e2的子表达式,那么e1≥ e2。

3.生成的题目中如果存在形如e1÷ e2的子表达式,那么其结果应是真分数。

4.每道题目中出现的运算符个数不超过3个。程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。例如,23 + 45 = 和45 + 23 = 是重复的题目,6 × 8 = 和8 × 6 = 也是重复的题目。3+(2+1)和1+2+3这两个题目是重复的,由于+是左结合的,1+2+3等价于(1+2)+3,也就是3+(1+2),也就是3+(2+1)。但是1+2+3和3+2+1是不重复的两道题,因为1+2+3等价于(1+2)+3,而3+2+1等价于(3+2)+1,它们之间不能通过有限次交换变成同一个题目。
1.2需求分析
1.读取命令行参数,随机生成符合参数的题目。

2.对输出的式子进行查重、计算。

3.生成并输出题集文本、答案文本。

4.命令行输入答案文本、答题文本路径,读取路径后与正确答案进行比对。

5.输出成绩文本,包括正确题号与错误题号。
2.开发环境

  • 编程语言:Java
  • IDE:eclipse
  • 性能分析工具:JProfile
    2.1工程结构

2.2总体设计

3.代码实现及设计
3.1 Main类
获取命令行参数,调用相应函数。

3.2 Create类
随机生成满足要求的题目。

createFormula方法用于生成整数、分数、运算符并将其合成式子,最后调用CheckAnswer方法检查运算结果。其中利用random.nextInt()语句随机确定生成整数/分数、括号起始位置、运算符。

commonFactor方法用于求两数的最大公因数,用于化简分数。

3.3 CheckRepeat类
对满足要求的式子进行查重,并将不重复的式子存储到题集文件。

generate方法用于生成临时题库和答案,并将不重复的题目添加到题集和答案集中。其中调用createFormula方法随机生成式子暂存于临时题库中,调用ifRepeat方法判断式子是否重复。

3.4 CheckAnswer 类
对式子进行计算并校验结果,生成式子的逆波兰表达式数组。

checkout方法用于生成逆波兰表达式(即后缀表达式),调用caculate方法计算并校验结果,其中分数结果用greatFraction方法(调用Create类里的commonFactor方法求分子分母的最大公因数)化简返回最简分数。
package fourcalculations;

public String[] checkout(String formula,int length){
// 操作数 && 操作符 && 逆波兰表达式
Stack stackNumber = new Stack<>();
Stack stackOperator = new Stack<>();
String[] reversePolishNotation = 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();) {
    //StringBuffer类中的方法主要偏重于对于字符串的变化,例如追加、插入和删除等,这个也是StringBuffer和String类的主要区别。
    StringBuilder digit = new StringBuilder();
    //将 式子 切割为 c字符
    char c = formula.charAt(i);
    //若 c字符 为10进制数字,将 c字符 加入digit(可以将多位数一起储存为一个数)
    while (Character.isDigit(c)||c=='/'||c=='\'') {
        digit.append(c);
        i++;
        c = formula.charAt(i);
    }

    if (digit.length() == 0){ //当前digit里面已经无数字,即当前处理符号
        switch (c) {
            //如果是“(”转化为字符串压入字符栈
            case '(': {
                stackOperator.push(String.valueOf(c));
                break;
            }
            //遇到“)”了,则进行计算,因为“(”的优先级最高
            case ')': {
                //将 stackOperator 栈顶元素取到 operator
                String operator = stackOperator.pop();
                //当前符号栈里面还有 + - × ÷时,取 操作数 并 运算
                while (!stackOperator.isEmpty() && !operator.equals("(")) {
                    //取操作数a,b
                    String a = stackNumber.pop();
                    String b = stackNumber.pop();
                    //后缀表达式变形
                    reversePolishNotation[j++] = a;
                    reversePolishNotation[j++] = b;
                    reversePolishNotation[j++] = operator;
                    //计算
                    String ansString = calculate(b, a, operator);
                    //如果 结果 不满足 要求 则 return -1,该式子不满足条件
                    if(ansString == null)
                        return  null;
                    //将结果压入栈
                    stackNumber.push(ansString);
                    //符号指向下一个计算符号
                    operator = stackOperator.pop();
                }
                break;
            }
            //遇到了“=”,则计算最终结果
            case '=': {
                String operator;
                //当前符号栈里面还有 + - × ÷时,即还没有算完,取 操作数 并 运算
                while (!stackOperator.isEmpty()) {
                    //取值 && 取操作数
                    operator = stackOperator.pop();
                    String a = stackNumber.pop();
                    String b = stackNumber.pop();
                    //后缀表达式变形
                    reversePolishNotation[j++] = a;
                    reversePolishNotation[j++] = b;
                    reversePolishNotation[j++] = operator;
                    //计算
                    String ansString = calculate(b, a, operator);
                    if(ansString == null)
                        return null;
                    stackNumber.push(ansString);
                }
                break;
            }
            //不满足之前的任何情况
            default: {
                String operator;
                //当前符号栈里面还有 + - × ÷时,取 操作数 并 运算
                while (!stackOperator.isEmpty()) {
                    //当前符号栈,栈顶元素
                    operator = stackOperator.pop();
                    if (hashmap.get(operator) >= hashmap.get(String.valueOf(c))) { //比较优先级
                        //取值
                        String a = stackNumber.pop();
                        String b = stackNumber.pop();
                        //后缀表达式变形
                        reversePolishNotation[j++] = a;
                        reversePolishNotation[j++] = b;
                        reversePolishNotation[j++] = operator;
                        //计算
                        String ansString =calculate(b, a, operator);
                        if(ansString == null)
                            return  null;
                        stackNumber.push(ansString);
                    }
                    else {
                        stackOperator.push(operator);
                        break;
                    }

                }
                stackOperator.push(String.valueOf(c));  //将符号压入符号栈
                break;
            }
        }
    }
    //处理数字,直接压栈
    else {
        stackNumber.push(digit.toString());
        //reversePolishNotation[j++] = digit.toString();
        continue; //结束本次循环,回到for语句进行下一次循环,即不执行i++(因为此时i已经指向符号了)
    }
    i++;
}
//获取 栈顶数字 即 等式的最终答案
reversePolishNotation[length-3] = "=";
reversePolishNotation[length-2] = stackNumber.peek();
reversePolishNotation[length-1] = formula;
return reversePolishNotation;

}
3.5 problemSet类
生成并输出相关文本。

createProblemSet方法用于定义题目与答案所在数组,并调用createEXEFile方法、cresteAnsFile方法生成相应文本文件。

createGradeFile方法用于生成成绩文本文件,先获取指定的答题文件和答案文件中的内容,调用output方法,输出正确/错误的题目题号。
public void createProblemSet(int n,int r){
CheckRepeat temporarySet = new CheckRepeat();
ArrayList returnList = temporarySet.generate(n,r);
ArrayList txtList = new ArrayList<>();
ArrayList ansList = new ArrayList<>();

//获取题集、答案集
for (int i =0;i<2*n;i++) {
    if(i<n) txtList.add(returnList.get(i).toString());
    else ansList.add(returnList.get(i).toString());
}
//输出题集、、答案集
createEXEFile(txtList);
createAnsFile(ansList);

}

/**

  • 生成并输出Exercises.txt

  • @param txtList 为 所得题集的 式子字符串
    */
    private void createEXEFile(ArrayList txtList){
    try{
    File exTXT = new File("../Exercises.txt");

     //如果文件已存在,则删除文件
     if (exTXT.exists()) {
         exTXT.delete();
     }
     //创建文件成功??
     if(exTXT.createNewFile()){
         System.out.println("创建Exercises.txt:");
         FileOutputStream txtFile = new FileOutputStream(exTXT);
         PrintStream q = new PrintStream(exTXT);
         q.println("学号:3220004889    姓名:迪力拜尔    成绩:\n");
    
         for(int i=0;i<txtList.size();i++){
             System.out.print(">");
             q.println(i+1 + ". " +txtList.get(i));
             //System.out.println(i+1 + ". " +txtList.get(i));
         }
    
         txtFile.close();
         q.close();
         System.out.println("Exercises.txt 创建成功!");
     }
    

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

4.测试
4.1性能分析和内存分析

4.2测试运行
项目运行,输入参数后出现以下界面


题库文档 Exercises.txt:


答案文档 Answer.txt:


录入答题文件:


在命令行输入文件路径

生成成绩文件 Grade.txt


5.项目小结
坤杜孜阿依——————个人总结
本次软件工程的双人合作项目是我第一次和别人合作完成的项目。在本次的合作中发现了不少问题。首先是前期需求分析,结构设计时花费了较多的时间,双方的想法意见没有及时交流。具体打代码因为没试过双人合作写代码,在合作上稍显慌乱,好在在一段时间后逐渐适应,合作逐渐流畅,各部分模块的思路对接比较顺畅。经过本次团队合作项目后,我对双人合作的模式有更深入的了解,更明白高效的交流在合作中的重要性。
迪力拜尔——————个人总结
此次结对编程作业我主要负责的是代码复审、测试以及报告内容。本次合作主要问题出现在前期沟通上,导致代码整体框架的构造花费了较长时间,但我们在意识到问题之后及时对合作模式进行改进,选择线下面对面交流,大大提升了工作效率,但在代码实现方面仍有不足,用户交互也只是简单地通过命令行方式,没有做出图形界面。

6.PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 30 25
Estimate 估计这个任务需要多少时间 300 250
Development 开发 70 70
Analysis 需求分析 (包括学习新技术) 60 65
Design Spec 生成设计文档 45 30
Design Review 设计复审 50 45
Coding Standard 代码规范 (为目前的开发制定合适的规范) 60 65
Design 具体设计 60 60
Coding 具体编码 100 100
Code Review 代码复审 30 25
Test 测试(自我测试,修改代码,提交修改) 50 60
Reporting 报告 40 30
Test Repor 测试报告 30 20
Size Measurement 计算工作量 20 15
Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 10 10
合计 715 955 935
posted @ 2024-09-28 21:19  dilibar  阅读(6)  评论(0编辑  收藏  举报