软工作业3_结对编程:四则运算

发布时间 2023-09-27 12:49:39作者: 镜流的剑鞘

1.软工作业3_结对编程:四则运算

软件工程 21计科34班
作业要求 结对项目
作业目标 结对设计实现一个生成四则运算题目的命令行程序
作业GitHub地址 第三次作业GitHub地址)
结对同学 赵俊宇3121005190 裴传传(找了外校同学组队)

2.PSP表格

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

3.效能分析

覆盖率:

性能分析图:

字符数组char[ ]和String类占用最多的内存,这主要与运算符号、题目文本及答案文本等的生成和文件写入时,调用了一系列List类方法、String类方法有关

cpu负载:

4.设计实现过程

主要分成了Run、Fraction、Creat、Calc、Checkanswer、Expression这几个类:

  1. Run类:包含了程序的入口点,即main方法。它负责启动整个程序,接受用户输入,调用其他类的方法来生成题目、计算答案和检查答案的正确性。它还负责输出结果到控制台或文件。
  2. Fraction类:表示分数,包含分子和分母的属性,以及一些用于操作分数的方法,如分数的加法、减法、乘法、除法等。
  3. Create类:生成题目。包含一些方法,用于生成随机的数学表达式,包括运算符、操作数和括号。生成的表达式可以以字符串的形式返回,供其他类使用。
  4. Calc类:计算数学表达式的结果。包含一些方法,用于将数学表达式转换为后缀表达式,并执行后缀表达式的计算。这个类可以处理各种运算符和括号。
  5. CheckAnswer类:检查用户提供的答案是否正确。包含一些方法,用于比较用户答案和正确答案,然后返回检查结果(正确或错误)。
  6. Expression类:表示数学表达式。包含一些属性,如操作数、运算符和括号的列表,以及一些方法,用于操作和转换表达式,如将中缀表达式转换为后缀表达式。

5.代码说明

Create类:生成题目。

public class Create {
   Expression expression=new Expression();
   Calc cal=new Calc();
   HashMap<String,String> map = new HashMap<String,String>();
   public void cr(int n,int r) throws IOException {
      BufferedWriter btex=new BufferedWriter(new FileWriter("Exercises.txt"));
      BufferedWriter btan=new BufferedWriter(new FileWriter("Answers.txt"));
      for(int i=1;i<n+1;i++){
         String exps=expression.getexp(r);
         List<String> cnkiexp1=cal.getcnki(exps);
         String cnki1=cal.list2String(cnkiexp1);    
         boolean contains2 =false;
         if(cnkiexp1.get(0).equals("+")||cnkiexp1.get(0).equals("×")) {
            List<String> cnkiexp2=cnkiexp1;
            String t1=cnkiexp2.get(1);
            String t2=cnkiexp2.get(2);
            cnkiexp2.set(1, t2);
            cnkiexp2.set(2, t1);
            String cnki2=cal.list2String(cnkiexp2);    
            contains2 = map.containsKey(cnki2);
         }
         if(i==1) {map.put(cnki1,"");}
         boolean contains = map.containsKey(cnki1);
         if(contains==true||contains2==true) {
            exps=expression.getexp(r);
            cnkiexp1=cal.getcnki(exps);
            cnki1=cal.list2String(cnkiexp1);
            contains2 =false;
            if(cnkiexp1.get(0).equals("+")||cnkiexp1.get(0).equals("×")) {
               List<String> cnkiexp2=cnkiexp1;
               String t1=cnkiexp2.get(1);
               String t2=cnkiexp2.get(2);
               cnkiexp2.set(1, t2);
               cnkiexp2.set(2, t1);
               String cnki2=cal.list2String(cnkiexp2);    
               contains2 = map.containsKey(cnki2);
            }
         }
         map.put(cnki1,"");
         Fraction answer=cal.calculate(exps);
         String answers=answer.toString();
         btex.write(i+". "+exps+"\r\n");
         btan.write(i+". "+answers+"\r\n");
      }
      btex.flush();
      btan.flush();
      btex.close();
      btan.close();
   }
}

Calc类:计算数学表达式的结果。

public class Calc {
    char[] oper6 = {'+', '-', '×', '÷', '(', ')'};
    String[] oper4 = {"+", "-", "×", "÷"};
    private static int ADDITION = 1;
    private static int SUBTRACTION = 1;
    private static int MULTIPLICATION = 2;
    private static int DIVISION = 2;

    public static int getValue(String op) {
        int value;
        switch (op) {
            case "+":
                value = ADDITION;
                break;
            case "-":
                value = SUBTRACTION;
                break;
            case "×":
                value = MULTIPLICATION;
                break;
            case "÷":
                value = DIVISION;
                break;
            default:
                value = 0;
        }
        return value;
    }


    //判断是否是操作符
    public boolean isoper(char c) {
        for (char op : oper6) {
            if (op == c) return true;
        }
        return false;
    }

    public boolean isoper(String s) {
        for (String op1 : oper4) {
            if (s.equals(op1)) return true;
        }
        return false;
    }

    //判断是否是数字
    public boolean isfra(char c) {
        if (c >= '0' && c <= '9') {
            return true;
        }
        return false;
    }

    public boolean isfraop(char c) {
        if (c == '\'' || c == '/') {
            return true;
        }
        return false;
    }

    //将String类型表达式转换成List<String>类型
    public List<String> Stringtolist(String str) {
        List<String> infix = new ArrayList<String>();
        str = str.replace(" ", "");
        char op;
        String temp = "";
        for (int i = 0; i < str.length(); i++) {
            op = str.charAt(i);
            if (isfra(op) || isfraop(op)) {
                temp += op;
            } else if (isoper(op)) {
                if (!temp.isEmpty()) {
                    infix.add(temp);
                    temp = "";
                }
                infix.add(op + "");
            }
        }
        if (!temp.isEmpty()) {
            infix.add(temp);
            temp = "";
        }
        return infix;
    }

    //将中缀表达式转换为后缀表达式
    public List<String> infixtopostfix(List<String> infix) {
        List<String> postfix = new ArrayList<String>();
        Stack<String> s1 = new Stack<String>();
        for (String str : infix) {
            if (str.equals("(")) {
                s1.push(str);
            } else if (str.equals(")")) {
                while (!s1.peek().equals("(")) {
                    postfix.add(s1.pop());
                }
                s1.pop();
            } else if (str.equals("+") || str.equals("-") || str.equals("×") || str.equals("÷")) {
                while (s1.size() != 0 && getValue(s1.peek()) >= getValue(str)) {
                    postfix.add(s1.pop());
                }
                s1.push(str);
            } else {
                postfix.add(str);
            }
        }
        while (s1.size() != 0) {
            postfix.add(s1.pop());
        }
        return postfix;
    }

    //对后缀表达式进行计算
    public Fraction calculate(String str) {
        List<String> linfix = Stringtolist(str);
        List<String> lpostfix = infixtopostfix(linfix);
        Stack<Fraction> s2 = new Stack<Fraction>();
        Fraction f1;
        Fraction f2;
        Fraction answer;
        for (String cal : lpostfix) {
            if (!isoper(cal)) {
                Fraction f = Fraction.tofraction(cal);
                s2.push(f);
            } else {
                switch (cal) {
                    case "+":
                        f1 = s2.pop();
                        f2 = s2.pop();
                        answer = f2.add(f1);
                        s2.push(answer);
                        break;
                    case "-":
                        f1 = s2.pop();
                        f2 = s2.pop();
                        answer = f2.sub(f1);
                        s2.push(answer);
                        break;
                    case "×":
                        f1 = s2.pop();
                        f2 = s2.pop();
                        answer = f2.mult(f1);
                        s2.push(answer);
                        break;
                    case "÷":
                        f1 = s2.pop();
                        f2 = s2.pop();
                        answer = f2.div(f1);
                        s2.push(answer);
                        break;
                }
            }
        }
        return s2.pop();
    }
  
    public String list2String(List<String> list) {
        String str1 = "";
        for (String s : list) {
            str1 = str1 + s + " ";
        }
        return str1;
    }
}

CheckAnswer类:检查用户提供的答案是否正确。

public class Checkanswer {
   
   public void check(String expath,String anpath) throws IOException{
      BufferedReader brex=new BufferedReader(new FileReader(expath));
      BufferedReader bran=new BufferedReader(new FileReader(anpath));
      BufferedWriter bwgrade=new BufferedWriter(new FileWriter(".\\Grade.txt"));
      List<String> Correct=new ArrayList<String>();
      List<String> Wrong=new ArrayList<String>();
      String an=null;
      String ex=null;
      while((an=bran.readLine())!=null) {
         ex=brex.readLine();
         int point=an.indexOf(".");
         String stran=an.substring(point+1);
         stran=stran.trim();
         String strex=ex.substring(point+1);
         strex=strex.trim();
         if(stran.equals(strex)) {        
            String cno=an.substring(0, point);
            Correct.add(cno);
         }else {
            String wno=an.substring(0, point);
            Wrong.add(wno);
         }
      }
      String corr=String.join(",",Correct); 
      String wr=String.join(",",Wrong); 
      bwgrade.write("Correct: "+Correct.size()+" ("+corr+")"+"\r\n");
      bwgrade.write("Wrong: "+Wrong.size()+" ("+wr+")");
      bwgrade.flush();
      bwgrade.close();   
   }
}

6.测试说明




一万条:


7.小结

在本次结对编程项目中,我们共同合作完成了一个四则运算题目生成和批改的Java应用程序。通过这次合作,我们获得了许多宝贵的经验和教训,以下是我们的项目小结:

项目概述: 本项目旨在开发一个四则运算题目生成器和答案批改器,可以生成一系列四则运算题目,并根据给定的答案文件来批改用户的答案。

项目分工: 我们在项目中交替担任主驱动者和导航者的角色,确保了代码的质量和可读性。这种协作方式帮助我们更好地理解和修复代码中的问题。

项目亮点:

  1. 功能完整:我们成功实现了题目生成和答案批改的核心功能。题目生成器可以生成多种类型的题目,答案批改器可以准确判断答案的正确性。
  2. 代码质量:通过结对编程,我们共同审查和改进了代码,确保其质量和可维护性。我们遵循了Java的最佳实践,使用了合适的命名和注释。

经验教训:

  1. 沟通至关重要:项目中充分的沟通非常重要。通过不断讨论和解释代码,我们能够更好地理解对方的思维和意图。
  2. 版本控制:及时提交和同步代码到版本控制系统(如Git)非常重要。这有助于避免代码冲突和数据丢失。
  3. 任务分解:我们应该更好地将任务分解为更小的子任务,以便更容易管理和实施。这有助于提高工作效率。