结对项目:自动生成小学四则运算题目

所属课程 软件工程导论
作业要求 结对项目
作业目标 团队简介、分工合作、确定选题、团队计划安排

小组成员

姓名 班级 学号
林劲辰 计科2班 3121004707
许庆阳 计科2班 3121004931

Github链接: https://github.com/HsuQingYoung/PeerWork

项目要求

1、实现一个自动生成小学四则运算题目的命令行程序(也可以用图像界面,具有相似功能)
2、程序应能支持一万道题目的生成。
3、使用 n 参数控制生成题目的个数,使用 r 参数控制题目中数值(自然数、真分数和真分数分母)的范围
4、不能出现负数,假分数,每题运算符不能超过3个
5、生成的题目存入执行程序的当前目录下的Exercises.txt文件,在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件
6、程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计,统计结果输出到文件Grade.txt

1.PSP表格

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

2.模块接口设计

2.1流程图

2.2框架

2.3类

类名 作用
main 主函数
BuildFormula 随机生成式子
checkAnswer 对照答案
FileOperation 文件相关
Fraction 表示分数
GetResultFromArray 转换分数

2.4函数

函数名 功能 归属的类
generate 随机生成公式,如果有减法,则判定减数和被减数的大小,确保计算的子过程不出现负数 BuildFormula类
addBrackets 符合条件的话随机生成括号 BuildFormula类
check 讲用户输入的答案与正确答案比较,正确则在后面打勾,否则打叉 checkAnswer类
writeFormulaIntoTxt 讲生成的公式写入文件 FileOperation类
writeAnswerIntoTxt 讲每条公式对应的答案写入文件 FileOperation类
createFraction 根据分子分母构建分数 Fraction类
add 分数的加操作 Fraction类
sub 分数的减操作 Fraction类
mul 分数的乘操作 Fraction类
div 分数的除法操作 Fraction类
toString 分数转换为字符串 Fraction类
calculateStringArray 根据字符串数组中的公式将其转换为分数并计算其结果 GetResultFromArray类

函数之间的关系:BuildFormula类和GetResultFromArray类的函数分别根据所给的题目生成要求来生成题目和对应的答案,Fraction类的函数是为GetResultFromArray类的函数生产答案的过程提供服务,而checkAnswer类的函数则是为了对照答案是否正确。

2.5关键代码以及注释

式子生成:

点击查看代码
    public void generate(){//生成一条公式1 + 1 + 1
        Random random=new Random();
        StringBuilder sb=new StringBuilder();
        Fraction result=null;

        String[] formula=new String[count];
        String[] answer=new String[count];
        for(int j=0;j<count;j++){
            int numOfFraction=random.nextInt(3)+2;
            boolean bracketsGenerate=random.nextBoolean();//是否随机生成括号
            sb.setLength(0);
            result=null;
            int tag=0;
            int operator;
            for(int i=1;i<=numOfFraction;i++){//根据分数的个数生成公式和符号
                if(i!=numOfFraction){
                    int denominator=random.nextInt(10)+1;//分母
                    int numerator=random.nextInt(denominator*range)+1;//分子
                    Fraction f=new Fraction(numerator,denominator);
                    sb.append(f.toString()+" ");
                    if(tag==0){
                        operator=random.nextInt(4);
                    }else{
                        operator=random.nextInt(2)+2;
                    }

                    if(operator==0||operator==1){
                        tag=1;
                    }
                    switch (operator) {
                        case 0:
                            sb.append("÷ ");
                            break;
                        case 1:
                            sb.append("- ");
                            break;
                        case 2:
                            sb.append("* ");
                            break;
                        case 3:
                            sb.append("+ ");
                            break;
                    }
                }else{
                    int denominator=random.nextInt(10)+1;//分母
                    int numerator=random.nextInt(denominator*range)+1;//分子
                    Fraction f=new Fraction(numerator,denominator);
                    sb.append(f.toString());
                }

            }
            String[] s=sb.toString().split(" ");
            s=swapOrder(s);

            if(numOfFraction!=2&&bracketsGenerate){//符合生成括号的条件
                //String[] s=sb.toString().split(" ");
                int leftindex=2*(random.nextInt(numOfFraction-1));//4个操作时 0 1 2
                int rightindex=0;
                if(numOfFraction==3){
                    switch (leftindex){
                        case 0:
                            rightindex=2;
                            break;
                        case 2:
                            rightindex=4;
                            break;
                    }
                }else if(numOfFraction==4){
                    switch(leftindex){
                        case 0:
                            rightindex=2*(random.nextInt(2)+1);
                            break;
                        case 2:
                            rightindex=2*(random.nextInt(2)+2);
                            break;
                        case 4:
                            rightindex=6;
                            break;
                    }
                }
                GetResultFromArray g=new GetResultFromArray();
                String[] news=null;

                news=addBrackets(s,leftindex,rightindex);
                result=g.calculateStringArray(news);

                sb.setLength(0);
                for (String str : news) {
                    sb.append(str+" ");
                }
            }else{
                GetResultFromArray g=new GetResultFromArray();
                //s=sb.toString().split(" ");

                result=g.calculateStringArray(s);
            }
            sb.append("= ");
            formula[j]=sb.toString();
            if(result==null){
                answer[j]="不可计算";
            }else{
                answer[j]=result.toString();
            }

        }
        FileOperation fo=new FileOperation();
        fo.writeFormulaIntoTxt(formula);
        fo.writeAnswerIntoTxt(answer);

    }

计算答案:

点击查看代码
    public static Fraction calculateStringArray(String[] inputArray) {
        if (inputArray == null || inputArray.length == 0) {
            return new Fraction(0, 1); // 返回默认分数 0/1
        }

        Stack<Fraction> numStack = new Stack<>();
        Stack<Character> operatorStack = new Stack<>();

        for (String token : inputArray) {
            if (isFraction(token)) {
                numStack.push(new Fraction(token));
            } else if (token.equals("(")) {
                operatorStack.push('(');
            } else if (token.equals(")")) {
                while (!operatorStack.isEmpty() && operatorStack.peek() != '(') {
                    if (performOperation(numStack, operatorStack)) {
                        return null;
                    }
                }
                operatorStack.pop(); // Pop the opening parenthesis
            } else if (isOperator(token)) {
                while (!operatorStack.isEmpty() && hasPrecedence(token.charAt(0), operatorStack.peek())) {
                    if (performOperation(numStack, operatorStack)) {
                        return null;
                    }
                }
                operatorStack.push(token.charAt(0));
            }
        }

        while (!operatorStack.isEmpty()) {
            if (performOperation(numStack, operatorStack)) {
                return null;
            }
        }

        return numStack.pop();
    }

答案对照:

点击查看代码
    public void check() throws IOException {
        String filePath="D:\\IdeaProjects\\PeerWork\\src\\main\\resources\\Exercises.txt";
        String filePath1="D:\\IdeaProjects\\PeerWork\\src\\main\\resources\\Answer.txt";

        String[] useranswer=readLinesToArray(filePath);
        String[] realanswer=readLinesToArray(filePath1);
        String[] result=new String[useranswer.length];
        int i=0;
        for(String line:useranswer){
            String[] ss=line.split(" ");
            String answer=ss[ss.length-1];//用户写的
            int index=realanswer[i].indexOf("、");
            String realAnswer=realanswer[i].substring(index+1);
            if(realAnswer.equals(answer)){
                result[i]="✓";
            }else{
                result[i]="×";
            }
            i++;
        }
        List<String> lines = new ArrayList<>();
        BufferedReader reader = new BufferedReader(new FileReader(filePath));
        String line;
        i=0;
        while ((line = reader.readLine()) != null) {
            lines.add(line + result[i]);
            i++;
        }
        reader.close();

        BufferedWriter writer = new BufferedWriter(new FileWriter(filePath));
        for (String updatedLine : lines) {
            writer.write(updatedLine);
            writer.newLine();
        }
        writer.close();

    }

3代码性能分析

改善过程:首先,我们发现在式子生成的过程中由于查重、判断是否成立的代码部分存在冗余,所以我们优化了代码,使BuildFormula类的函数更加简洁,提高generate函数的运行效率。然后观察性能分析图后,我们发现GetResultFromArray类在程序运行过程中消耗较大,于是我们仔细查看了代码,减去了代码中不必要的循环,一定程度上减少了程序运行的消耗。

4单元测试展示

4.1测试代码

生成测试

点击查看代码
public class TestMain {
    public static void main(String[] args) {//测试生成公式和答案
//-n 10 -r 10
        int range=10;
        int count=10;
        BuildFormula bf=new BuildFormula(range,count);
        bf.generate();
    }
}

答案测试

点击查看代码
public class TestCheckAnswer {//测试校对答案
    public static void main(String[] args) {
        checkAnswer ca=new checkAnswer();
        try {
            ca.check();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

4.2测试结果

式子生成:

答案生成:

命令行测试

测试结果:成功生成式子,并且结果正确,没有出现问题。

4.3测试覆盖率

5.作业总结

团结协作是一切事业成功的基础,个人和集体只有依靠团结的力量才能把人人的愿望和团队的目标结合起来,超越人体的局限,发挥集体的协作作用,产生1+1>2的效果,在合作中,我们对出现的问题进行统一讨论,有时候我没能解决的问题,对方能解决。我们彼此都能想到对方想不到的点,这样互相完善,比起一个人来说,效率大大提升了。在这次代码中遇到最大的问题就是公式生成不合理的问题,因为之前没有学习过相关方面的问题,经过这次作业,也让我们学到了新的东西,取得了一定的进步。对于以后的结对编程,我们的建议是可以先了解彼此的长处,合理分配任务,是项目完成更加高效。

posted @ 2023-09-28 13:06  KinsonLin  阅读(40)  评论(0编辑  收藏  举报