github地址

这个作业属于哪个课程 计科22级12班
这个作业要求在哪里 作业要求链接
这个作业的目标 结对实现一个自动生成小学四则运算题目的命令行程序
姓名 任务
郑铠洋 程序实现
彭培炎 测试

一、PSP表格

阶段 描述 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 5 5
· Estimate · 估计这个任务需要多少时间 5 5
Development 开发 160 180
· Analysis · 需求分析 (包括学习新技术) 10 10
· Design Spec · 生成设计文档 10 10
· Design Review · 设计复审 10 10
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 20 20
· Design · 具体设计 10 10
· Coding · 具体编码 60 90
· Code Review · 代码复审 10 10
· Test · 测试(自我测试,修改代码,提交修改) 30 30
Reporting 报告 60 60
· Test Report · 测试报告 40 40
· Size Measurement · 计算工作量 10 10
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 10 10
合计 225 245

二、效能分析

覆盖率:

大约85%

时间:

150ms左右可生成一次

空间:

因为要存储之前的题目以判断题目的唯一性,所以这里空间开的比较多

三、设计思路

文件结构:

程序流程:

实现逻辑:

  • 写一个Fraction类将数字转为分数结构,分母为1时为整数
  • 在createQuestion类随机分子分母,符号,并且根据符号随即添加括号
  • answerChecker用于比对答案

四、代码说明

主要的create函数

用random()随机生成

    ppublic static void create(int number, int range, List<String> exercises, List<String> answers) {

        Random rand = new Random();
        while (exercises.size() < number) {
            try{
                // 生成分子和分母,控制整数和分数的出现概率
                int[] fraction1 = generateNumberOrFraction(rand, range);
                int[] fraction2 = generateNumberOrFraction(rand, range);
                int[] fraction3 = generateNumberOrFraction(rand, range);

                // 获取分数或整数
                Fraction num1=new Fraction (fraction1[0],fraction1[1]);
                Fraction num2=new Fraction (fraction2[0],fraction2[1]);
                Fraction num3=new Fraction (fraction3[0],fraction3[1]);

                // 生成两个运算符
                char operator1 = createOperator();
                char operator2 = createOperator();

                // 随机决定是否添加括号
                boolean addBracket = rand.nextBoolean();
                boolean[] bracket1Ref = {false};
                boolean[] bracket2Ref = {false};

                // 生成题目
                String question = createBracket(addBracket, fraction1, fraction2, fraction3, operator1, operator2, bracket1Ref, bracket2Ref);
                if (!generatedQuestions.contains(question)) {
                    boolean bracket1 = bracket1Ref[0];
                    boolean bracket2 = bracket2Ref[0];
                    String answer = calculateAnswer(num1, num2, num3, operator1, operator2,bracket1, bracket2);
                    exercises.add(question);
                    answers.add(answer);
                    generatedQuestions.add(question);// 记录生成的题目
                }
            }catch (ArithmeticException e) {
                continue;
            }
        }
    }

    /*
     * 生成整数或分数,根据随机数控制出现概率
     */
    private static int[] generateNumberOrFraction(Random rand, int range) {
        // 50% 概率生成整数,50% 概率生成分数
        if (rand.nextBoolean()) {
            int numerator = rand.nextInt(range); // 生成整数
            return new int[]{numerator, 1};      // 分母为1,表示整数
        } else {
            int numerator = rand.nextInt(range);
            int denominator = rand.nextInt(range - 1) + 1; // 确保分母不为0
            return new int[]{numerator, denominator};
        }
    }

添加括号

将加入括号的频率设置成50%,对每个符号都有几率添加括号

private static String createBracket(boolean addParentheses, int[] fraction1, int[] fraction2,
                                        int[] fraction3, char operator1, char operator2, boolean[] bracket1, boolean[] bracket2) {
        String question;
        // 获取分数或整数
        double num1 = (double) fraction1[0] / fraction1[1];
        double num2 = (double) fraction2[0] / fraction2[1];
        double num3 = (double) fraction3[0] / fraction3[1];
        // 随机添加括号
        if (addParentheses && ((operator1 == '+' || operator1 == '-') && (operator2 == '*' || operator2 == '/'))
                || ((operator2 == '+' || operator2 == '-') && (operator1 == '*' || operator1 == '/')))
        {
            if(operator1 == '+' || operator1 == '-')
            {
                bracket1[0]=true;
                if(operator1 == '-' && num1<num2)swap(fraction1,fraction2);
                question = "(" + formatFraction(fraction1[0], fraction1[1]) + " " + operator1 + " " +
                        formatFraction(fraction2[0], fraction2[1]) + ") " + operator2 + " " +
                        formatFraction(fraction3[0], fraction3[1]) + " = ";
            }
            else
            {
                bracket2[0]=true;
                if(operator2 == '-' && num2<num3)swap(fraction2,fraction3);
                question =  formatFraction(fraction1[0], fraction1[1]) + " " + operator1 + " (" +
                        formatFraction(fraction2[0], fraction2[1]) + " " + operator2 + " " +
                        formatFraction(fraction3[0], fraction3[1]) + " )= ";
            }
        } else if (addParentheses) {
            bracket2[0]=true;
            if(operator2 == '-' && num2<num3)swap(fraction2,fraction3);
            question =  formatFraction(fraction1[0], fraction1[1]) + " " + operator1 + " (" +
                    formatFraction(fraction2[0], fraction2[1]) + " " + operator2 + " " +
                    formatFraction(fraction3[0], fraction3[1]) + " )= ";
        } else {
            question = formatFraction(fraction1[0], fraction1[1]) + " " + operator1 + " " +
                    formatFraction(fraction2[0], fraction2[1]) + " " + operator2 + " " +
                    formatFraction(fraction3[0], fraction3[1]) + " = ";
        }


        return question;
    }

计算答案

对加入括号的优先计算,再计算剩下的

public static String calculateAnswer(Fraction num1, Fraction num2, Fraction num3,
                                          char operator1, char operator2, boolean bracket1, boolean bracket2) {
        Fraction finalResult = new Fraction(1,1);

        if (bracket1) {
            // 先计算括号内的操作
            Fraction middleResult = applyOperator(num1, num2, operator1);
            finalResult = applyOperator(middleResult, num3, operator2);
        } else if (bracket2) {
            Fraction middleResult = applyOperator(num2, num3, operator2);
            finalResult = applyOperator(num1, middleResult, operator1);
        } else {
            // 正常顺序运算
            if((operator1 == '+' || operator1 == '-') && (operator2 == '*' || operator2 == '/')) {
                Fraction middleResult = applyOperator(num2, num3, operator2);
                finalResult = applyOperator(num1, middleResult, operator1);
            }
            else
            {
                Fraction middleResult = applyOperator(num1, num2, operator1);
                finalResult = applyOperator(middleResult, num3, operator2);
            }
        }

        return finalResult.toString();
    }

五、测试运行

题目

答案

其余测试用例

针对各个函数正确和错误以及空的测试

六、记录小结

我们第一次尝试结对任务,认为结对任务可以有效节省时间,减少差错,且对项目拥有更清楚的思路和理解。但是,在工作效率上仍有欠缺,主要涉及沟通交流

posted on 2024-09-26 17:26  ez4bridge  阅读(31)  评论(0编辑  收藏  举报