结对作业-四则运算计算器

个人项目

软件工程 <网工1934>
作业要求 <作业要求连接>
作业目标:完成四则运算计算器,实现并经过测试后上传到GitHub <Github连接>
队员:李文锋3119005379 李金锋3119005378

PSP表格

PSP Personal SoftwareProcess Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 30 35
Estimate 估计这个任务需要多少时间 80 100
Development 开发 2400 2800
Analysis 需求分析(包括学习新技术) 300 350
Design Spec 生成设计文档 80 60
Design Review 设计复审 30 30
Coding Standard 代码规范 (为目前的开发制定合适的规范) 30 30
Design 具体设计 120 100
Coding 具体编码 300 420
Code Review 代码复审 60 60
Test 测试(自我测试,修改代码,提交修改) 180 280
Reporting 报告 240 300
Test Report 测试报告 60 80
Size Measurement 计算工作量 60 60
Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 120 120
合计 4090 4790

需求分析

一个具有题目和其答案生成且能检查题目与答案是否正确的计算器

题目生成:

需要生成运算符在3个以内(包括3个)的计算式,并以中辍表达式的形式表达出来

答案生成:

答案要与题目一一对应

校验答案:

需要输入需要校验的两个文件的文件名用以校验

思路

随机生成一组含有n个数字和n-1个符号的中辍表达式
将中辍表达式转化成逆波兰式并进行计算
把中辍表达式和答案分别输出到Exercise.txt和Answer.txt两个文件中

部分关键代码

生成表达式

public static String expression(int r){//生成表达式
        String str;
        String ans;
        Random rand = new Random();
        do {
            str = "";
            int t = 0;
            t = rand.nextInt(3) + 2;//式子中用于运算的数的个数
            String[] number = new String[t];
            String[] symbol = new String[t-1];
            String[] expression = new String[4*t-3];//由于分数中/和运算中的/是一致的,为了区分运算符和操作数
                                                    // 将操作数和运算符用空格隔开


            for(int i=0;i<t;i++){//生成式子中的数
                number[i] = Num.produce(r);
            }
            for(int i=0;i<t-1;i++){//生成式子中的运算符
                symbol[i] = Operaction.symbol();
            }

            for(int i =0;i<4*t-3;i++){
                if(i%4==0) //字符中奇数位为符号(基0)
                    expression[i] = number[i/4];
                else if(i%4==2)
                    expression[i] = symbol[(i+2)/4-1];
                else
                    expression[i] = " ";
            }
            for(int i = 0;i<4*t-3;i++){
                if(expression[i].contains("'"))
                    expression[i] = Num.transformF(expression[i]);
            }
            for(int i=0;i<4*t-3;i++){
                str = str + expression[i];
            }
            ans = calculate.count(str);
        }while(ans.contains("-"));
        return str + "=" + ans;
    }

中辍表达式转为逆波兰式

public static String creat(String str){//中辍表达式转后辍表达式,逆波兰算法
        int tmp = 0;
        String expression = "";//输出的式子
        String[] str1 = str.split(" ");
        String str2 = "";
        for(int i = 0;i< str1.length;i++){
            str2 += str1[i];
        }
        Stack<Character> symbolStack = new Stack<Character>();
        for(int i=0;i<str2.length();i++){
            char c = str2.charAt(i);
            if(isNum(c)) {//如果是数字,直接加进表达式中
                tmp = (c-'0');
                expression += tmp;
            }
            else if(c == '/')
                expression += c;
            else if(c == '(')//如果是左括号,直接压入符号栈
                symbolStack.push(c);
            else if(c == ')'&& !symbolStack.empty()){//如果遇到右括号且符号栈不为空,那么把符号都添加到表达式中
                while(symbolStack.peek()!='('){
                    expression += symbolStack.pop();
                }
                symbolStack.pop();
            }else{//如果是非左/右括号的运算符
                expression += " ";
                if(!symbolStack.empty()){//如果符号栈不为空,将当前符号和符号栈栈顶的符号的优先度做对比,如果优先度高,则压入符号栈
                    if((priority(c)>priority(symbolStack.peek())))
                        symbolStack.push(c);
                    else{//如果优先度没有栈顶符号高,那么将符号栈里的符号都输出到表达式中,直到找到一个优先度低于当前符号的,再压入符号栈
                        while(!symbolStack.empty()){
                            if(priority(c)<=priority(symbolStack.peek())){
                                expression += symbolStack.pop();
                                expression += " ";
                            }
                            else
                                break;
                        }
                        symbolStack.push(c);
                    }
                }
                else
                {//如果符号栈为空,直接压入符号栈
                    symbolStack.push(c);
                }
            }
        }

        while(!symbolStack.empty()){//如果遍历完整个表达式后,扔存在运算符,则将符号都输出到表达式中
            expression += " ";
            expression += symbolStack.pop();
        }
        return expression;

    }

计算

 public static String count(String str1){
        String str = Transform.creat(str1);
        boolean haveNum = false;
        boolean haveFraction = false;
        int tmp = 0;
        int numer = 0;
        int gcd = 0;
        char x;

        Num a=null;
        Num b=null;
        Num c=null;

        Stack<Num> number = new Stack<Num>();
        for(int i=0;i<str.length();i++){
            x = str.charAt(i);
            if(Transform.isNum(x)){
                haveNum = true;
                tmp = tmp*10 + (x-'0');//每遇到一个数字就*10+x
            }
            else{
                if(haveNum){//如果遇到数字后跟着符号的情况
                    haveNum = false;
                    if(x!='/'){//跟着的符号不为‘/’,即+。-。*、÷和空格的情况
                        if(haveFraction){//如果判定前面的数字为分数
                            Num fraction = new Num(numer,tmp);//创建分数并压入栈
                            number.push(fraction);
                            tmp = 0;
                        }else {//整数情况
                            Num interger = new Num(tmp,1);//把整数压入栈
                            number.push(interger);
                            tmp = 0;
                        }
                    }else{//数字后跟着的符号为/,即前面数字为分子的情况
                        haveFraction = true;
                        numer = tmp;//tmp是分子
                        tmp = 0;
                        continue;
                    }
                }//如果跟着的符号是+。-。*、÷和空格的情况,压出栈中的数字并进行计算
                if(x == '+'){
                    b = number.peek();
                    number.pop();
                    a = number.peek();
                    number.pop();
                    c = add(a,b);
                }
                else if(x == '-'){
                    b = number.peek();
                    number.pop();
                    a = number.peek();
                    number.pop();
                    c = subtract(a,b);
                }
                else if(x == '×'){
                    b = number.peek();
                    number.pop();
                    a = number.peek();
                    number.pop();
                    c = mul(a,b);
                }
                else if(x == '÷'){
                    b = number.peek();
                    number.pop();
                    a = number.peek();
                    number.pop();
                    c = div(a,b);
                }
                else if(x == ' '){//如果跟着的符号是空格
                    if(haveFraction)
                        haveFraction = false;
                    continue;
                }
                number.push(c);//把运算结果压入栈,进行下一次的运算
            }
        }

生成表达式并输出到文件中

 public static void io(int n,int r)throws Exception{
        FileWriter fw = new FileWriter("./Exercises.txt");
        BufferedWriter Exercises = new BufferedWriter(fw);
        FileWriter fw1 = new FileWriter("./Answer.txt");
        BufferedWriter Answer = new BufferedWriter(fw1);

        Map<String, Set<Integer>> map = new HashMap<String, Set<Integer>>();
        String[] exercises = new String[n];
        String[] answers = new String[n];
        for(int i=0;i<n;i++) {//生成式子和答案并写入当前目录的文件中,生成n个
            String[] output = Operaction.expression(r).split("=");//output[0]是式子 output[1]是答案
            if(map.containsKey(output[1])){
                Set<Integer> set = map.get(output[1]);
                while (set.contains(output[0].length()))
                    output = Operaction.expression(r).split("=");
                set.add(output[0].length());
            }else {
                map.put(output[1],new HashSet<Integer>(Arrays.asList(output[0].length())));
            }
            exercises[i] = output[0];
            answers[i] = output[1];

            Exercises.write(i+1 + ". " + output[0]);
            Exercises.newLine();
            Exercises.flush();

            Answer.write(i+1 + ". " + calculate.count(output[0]));
            Answer.newLine();
            Answer.flush();
        }
        Exercises.close();
        Answer.close();

    }

测试


修改其中一题的答案再校验

小结

李文锋:在这个项目中,第一次接触两个人的合作。在这个过程中,两个人先讨论了计算器的一个大题架构,然后逐步细化每一个部分要做什么,再进行代码实现和审计工作。
李金锋:这是我第一次与别人合作开发,在这次项目中培养了我的团队协作能力和与他人沟通交流的能力,也提高了我的编程能力,项目过程中有时与伙伴的交流会解决我苦思的问题,合作提高了效率。

posted @ 2021-10-25 12:23  十天Eternal  阅读(35)  评论(0)    收藏  举报