结对项目——四则运算

这个作业属于哪个课程 软件工程
这个作业要求在哪里 课程要求
代码文件 GitHub
这个作业的目标 在结对编程中总结经验和教训
参与者 黄梦莎 3221005240,古丽波斯旦·艾比布拉 3221005328

1. PSP表格

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

2. 主要函数

  • subject() // 生成表达式
  • change(int n, int d) // 将假分数转换为真分数,第一个参数为分子,第二个为分母
  • ifExist(List s) // 用于检查是否有相同的题目,并处理
  • save(List s) // 用于将题目存入当前目录下的Exercises.txt文件
  • answer(List a) // 用于将题目答案存入当前目录下的Answer.txt文件
  • check(File e, File a,File g) // 用于对给定的题目文件和答案文件判断答案文件中的对错并统计至Grade.txt
  • count(List list) // 构建树计算表达式,并存入题目列表

3. 部分代码

产生随机数

 // 产生随机数
    public static String createnum() {
        ThreadLocalRandom rand = ThreadLocalRandom.current();
        int a = rand.nextInt(range);
        int b = rand.nextInt(range);
        if (a == 0) {
            a += (int) (Math.random()*range + 1);
        }
        if (b == 0) {
            b += (int) (Math.random()*range + 1);
        }
        if (b == range) {
            b = b-1;
        }
        num n = new num(a,b);
        easy(n);
        if (n.a == n.b) {
            return Integer.toString(1);
        }
        if (n.b == 1) {
            return Integer.toString(n.a);
        }
        System.out.println(n.tostring());
        return n.tostring();
    }
	

生成随机运算符

// 随机产生运算符
    public static String createopr1() {
        return opr[(int) (Math.random()*4)];
    }
    // 只产生 x 或 ÷
    public static String createopr2() {
        return opr[(int) (Math.random()*2 + 2)];
    }
    // 只产生 + 或 -
    public static String createopr3() {
        return opr[(int) (Math.random()*2)];
    }
    // 处理括号无意义情况
    public static void checkbkt(int bkt_s, int bkt_e,List<String>exp) {
        String f;
        String s;
        String t;
        if (bkt_e - bkt_s == 1) {
            if (bkt_s == 1) {
                f = exp.get(2);
                s = exp.get(5);
                if (!(f.equals("+") || (f.equals("-"))) && !(s.equals("x") || s.equals("÷"))) {
                    exp.set(2, createopr3());
                    exp.set(5, createopr2());
                }
            } else if (bkt_s == 2) {
                f = exp.get(1);
                s = exp.get(4);
                if (exp.size()<8) {
                    if ((f.equals("+") || (f.equals("-"))) && (s.equals("x") || (s.equals("÷")))) { // 排除 a + ( b x c ) 此类括号无意义的情况
                        exp.set(1, createopr2());
                    }
                }
            } else if (bkt_s == 3) {
                f = exp.get(3);
                s = exp.get(6);
                if ((f.equals("+") || (f.equals("-"))) && (s.equals("x") || s.equals("÷"))) {
                    exp.set(3, createopr2());
                } else if (((f.equals("+") || f.equals("-"))) && (s.equals("+") || s.equals("-"))) {
                    exp.set(3, createopr2());
                }
            }
        } else {
            if (bkt_s == 1) {
                f = exp.get(2);
                s = exp.get(4);
                t = exp.get(7);
                if (!(t.equals("x") || t.equals("÷"))) {
                    exp.set(7, createopr2());
                    if (f.equals(s) && (f.equals("+") || f.equals("÷"))) {
                        exp.set(4, createopr2());
                    }
                }
            } else if (bkt_s == 2) {
                f = exp.get(1);
                s = exp.get(4);
                t = exp.get(6);
                if ((f.equals("+") || f.equals("-")) && (t.equals("x") || t.equals("÷"))) {
                    exp.set(1, createopr2());
                }
            }
        }
    }

计算表达式

 // 构建树计算表达式,并存入题目列表
    public static String count(List<String> list) {
        Stack<Node> a1 = new Stack<>();    // 数值栈
        Stack<String> b = new Stack<>();    // 未处理的运算符栈
//        Stack<Node> c = new Stack<>();    // 处理后的运算符栈
        for (int i=0; i<list.size(); i++) {
            String string = list.get(i);
            if (!isop(string)) {
          // 当前指针为数值
                a1.push(new Node(string, null, null, null));
            } else {
                //比较栈顶符号与当前符号的优先级
                while (!b.isEmpty() && !(string.equals("(") || (prefer(string)==2 && prefer(b.peek())==1) ||
                        (!string.equals(")") && b.peek().equals("(")))) {
                    String symbol = b.pop();
 
                    if (symbol.equals("(") && string.equals(")")) {
                        break;
                    }
                    push(symbol, a1);
 
                }
                //如果符号不是")"就进栈
                if (!string.equals(")")) {
                    b.push(string);
                }
            }
        }
 
        while (!b.isEmpty()) {
            push(b.pop(), a1);
        }
        negative(a1);
        return a1.peek().result;
    }
 
    // 处理负数
    public static void negative(Stack<Node> c) {
        if (!c.isEmpty()) {
            for (int i=0; i<c.size(); i++) {
                Node n = c.get(i);
                if (n.op.equals("-")) {
                    num l = new num(n.left.result);
                    num r = new num(n.right.result);
                    if (l.a*r.b < r.a*l.b) {
                        Node m = n.left;
                        n.left = n.right;
                        n.right = m;
                        n.setResult();
                    }
                }
            }
        }
    }
 
    public static void push(String op, Stack<Node> a) {
        if (!op.equals("(")) {
            Node r = a.pop();
            Node l = a.pop();
            Node o = new Node(null, r, l, op);
            o.result = count(r.result, l.result, op);
            a.push(o);
        }
    }
 
    public static String count(String r, String l, String op) {
        num left = new num(l);
        num right = new num(r);
        switch (op) {
            case "+":
                return left.add(right).tostring();
            case "-":
                return left.sub(right).tostring();
            case "x":
                return left.mul(right).tostring();
            case "÷":
                return left.div(right).tostring();
        }
        return null;
    }
 
    static class Node {
        String result;
        Node right;
        Node left;
        String op;
 
        public Node(String result, Node right, Node left, String op) {
            this.result = result;
            this.right = right;
            this.left = left;
            this.op = op;
        }
 
        public void setResult() {
            if (op!=null) {
                result = count(right.result, left.result, op);
            }
        }
 
        public void changelr() {
            Node m = left;
            right = left;
            left = m;
        }
 
    }
 
    public static int prefer(String op) {  // 判断运算符优先级
        if (op.equals("-") || op.equals("+")) {
            return 1;
        } else if (op.equals("x") || op.equals("÷")) {
            return 2;
        } else {
            return 3;
        }
    }
 
    public static boolean isop(String op) { // 判断是否为运算符
        if (op.equals("+") || op.equals("-")
                || op.equals("x") || op.equals("÷")
                || op.equals("(") || op.equals(")")) {
            return true;
        } else  {
            return false;
        }
    }
 
// 检查题目列表中是否有相同的题目,并处理
    static void ifExist(ArrayList<String> s) {
        for (int i=0; i<s.size(); i++) {
            for (int j=i+1; j<s.size();) {
                Stack<Node> f = e1.get(i);
                Stack<Node> se = e1.get(j);
                if (f.size() == se.size() && equals(f.pop(), se.pop())) {
                    s.remove(j);
                } else {
                    j++;
                }
            }
        }
    }
 
    static boolean equals(Node f, Node s) {
 
            if (fullequals(f, s)) {
                return true;
            } else if (f.op.equals(s.op) && f.result.equals(s.result)){
                if (change(f, s)) {
                    return true;
                } else {
                    return equals(f.left, s.left) && equals(f.right, s.right);
                }
            }
        return false;
    }
 
    static boolean change(Node f, Node s) {
        if (f.op.equals("+") || f.op.equals("x")) {
            f.changelr();
            f.setResult();
            if (nodeequal(f.left, s.left) && nodeequal(f.right, s.right)) {
                return true;
            }
        }
        return false;
    }
 
    static boolean nodeequal(Node f, Node s) {
        return f.op.equals(s.left.op) && f.result.equals(s.left.result);
    }
 
    static boolean fullequals(Node f, Node s) {
        if (f.op.equals(s.op) && f.result.equals(s.result)) {
            return fullequals(f.left, s.left) && fullequals(f.right, s.right);
        }
        return false;
    }

统计答案

static void check(File e, File a, File g) {
        // 用于对给定的题目文件和答案文件判断答案文件中的对错并统计
        File g1 = new File("./src/Grade.txt");
        if (!g1.exists()){
            try {
                g1.createNewFile();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
        try (BufferedReader exReader = new BufferedReader(new FileReader(e));
             BufferedReader anReader = new BufferedReader(new FileReader(a));
             BufferedWriter gradeWriter = new BufferedWriter(new FileWriter(g1))
        ) {
            String ex, an;
            int c = 0, w = 0;
            StringBuilder correct = new StringBuilder("Correct: %d (");
            StringBuilder wrong = new StringBuilder("Wrong: %d (");
            while ((ex = exReader.readLine()) != null && (an = anReader.readLine()) != null) {
                int exPoint = ex.indexOf(".");
                int anPoint = an.indexOf(".");
                if (exPoint != -1 && anPoint != -1) {
                    int i = Integer.valueOf(ex.substring(0,exPoint).trim());
                    String expression = ex.substring(exPoint + 2);
                    String[] exp = expression.split(" ");
                    List<String> al = new ArrayList<String>();
                    al = Arrays.asList(exp);
                    String realanswer = count(al);
                    String answer = an.substring(anPoint + 2);
                    if (realanswer.equals(answer.toString())) {
                        c++;
                        correct.append(" ").append(i);
                        if (c % 20 == 0) {
                            correct.append("\n");
                        }
                    } else {
                        w++;
                        wrong.append(" ").append(i);
                        if (w % 20 == 0) {
                            wrong.append("\n");
                        }
                    }
                }
            }
            gradeWriter.write(String.format(correct.append(" )\n").toString(),c));
            gradeWriter.write(String.format(wrong.append(" )\n").toString(),w));
            gradeWriter.flush();
        } catch (IOException e1) {
            e1.printStackTrace();
        }
    }

4. 测试

  • 单元测试
    image

  • 单元测试代码覆盖率
    image

  • 单元测试代码
    image

  • Windows下运行jar包测试
    image

  • 输出
    image
    image

  1. 效能分析
    image

5. 项目小结

这是我们双方第一次尝试二人项目,总体来说比较成功。我们先是对PSP表的预计时间进行讨论,同时确定项目流程,有不足的点在于分工不够明确,导致在编码过程出现重复编码的情况,最终采用了算法复杂度更低的算法。总体来说和古丽的合作十分愉快,她是一个很细心的合作伙伴,在许多细节处会给我意见和建议,我们在这次的二人项目中收获满满。

posted @ 2023-09-28 08:14  huangmengsha  阅读(41)  评论(0编辑  收藏  举报