首页 > 其他分享 >结对项目

结对项目

时间:2024-09-27 20:45:02浏览次数:1  
标签:结对 return String 项目 int denominator new public

结对项目

这个作业属于哪个课程 班级链接
这个作业要求在哪里 结对项目 - 作业 - 计科22级12班 - 班级博客 - 博客园 (cnblogs.com)
这个作业的目标 实现一个自动生成小学四则运算题目的命令行程序
姓名 学号
韩其锟 3122004348

GitHub

https://github.com/chocohQL/3122004348-02

PSP

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

运行结果

生成一万条题目:

生成10条题目,随机修改3个错误答案,进行判定统计:

系统设计

系统核心的设计思路: Application 类负责整体流程运行,下层抽象出一个 ProblemGenerator 负责具体题目和答案的生成,将题目表达式和答案封装到 Problem 实体类中。由于需要进行分数的计算,将每个数统一使用 Fraction 表示,实体类内部提供分数的加减乘除运算,使用构造函数创建分数自动进行化简,重写 toString 方法生成字符串。生成答案的思路是将表达式解析为操作数栈和数值栈,不断弹栈进行分数计算,并保证操作优先级。底层封装 FileUtil 工具类提供文件输入输出方法。

调用链:

  1. Main 主函数:启动程序。

  2. Application 程序:运行程序、解析参数、选择方法、调用 ProblemGenerator 生成题目、判定答案、调用 FileUtil 输入输出文件。

  3. ProblemGenerator 问题生成器:生成具体问题和答案、判定答案等。

  4. FileUtil 文件工具类:负责输入输出字符串行到指定文件中。

实体类:

  • Problem 问题:记录表达式 exercises 和答案 answers 。
  • Fraction 分数:进行分数的加减乘除计算,构造函数传入分子和分母自动进行简化。

具体实现

Application

public class Application {
    /**
     * 启动程序
     */
    public static void run(String[] args) {
        try {
            Map<String, String> params = parseParams(args);
            if (params.get("-r") != null && params.get("-n") != null) {
                generateProblems(params.get("-n"), params.get("-r"));
            } else if (params.get("-e") != null && params.get("-a") != null) {
                judgeProblems(params.get("-e"), params.get("-a"));
            } else {
                throw new RuntimeException("请检查参数 [-r][-n] | [-e][-a]");
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    /**
     * 解析参数
     */
    public static Map<String, String> parseParams(String[] args) {
        if (args.length != 4) {
            throw new RuntimeException("无法解析参数");
        }
        Map<String, String> params = new HashMap<>();
        for (int i = 0; i < args.length; i += 2) {
            params.put(args[i], args[i + 1]);
        }
        return params;
    }

    /**
     * 生成问题
     */
    public static void generateProblems(String n, String r) {
        int num = Integer.parseInt(n);
        int range = Integer.parseInt(r);
        if (num < 0 || range < 0) {
            throw new RuntimeException("参数必须为自然数");
        }
        num = Math.min(10000, num);
        List<Problem> problems = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            // 生成题目
            problems.add(ProblemGenerator.generateProblem(range));
        }
        // 输出结果
        List<String> exercises = new ArrayList<>();
        List<String> answers = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            exercises.add(i + 1 + ". " + problems.get(i).exercises);
            answers.add(i + 1 + ". " + problems.get(i).answers);
        }
        FileUtil.writeFile("Exercises.txt", exercises);
        FileUtil.writeFile("Answers.txt", answers);
    }

    /**
     * 判定答案
     */
    public static void judgeProblems(String e, String a) {
        List<String> exerciseFile = FileUtil.readFile(e);
        List<String> answerFile = FileUtil.readFile(a);
        int correct = 0;
        int wrong = 0;
        List<String> correctIndex = new ArrayList<>();
        List<String> gradeIndex = new ArrayList<>();
        for (int i = 0; i < exerciseFile.size(); i++) {
            try {
                String[] exercise = exerciseFile.get(i).split("\\. ");
                String[] answer = answerFile.get(i).split("\\. ");
                // 判定答案
                if (ProblemGenerator.judgeProblem(exercise[1], answer[1])) {
                    correctIndex.add(exercise[0]);
                    correct++;
                } else {
                    gradeIndex.add(exercise[0]);
                    wrong++;
                }
            } catch (Exception ex) {
                throw new RuntimeException("无法解析表达式");
            }
        }
        // 输出统计结果
        List<String> grade = new ArrayList<>();
        grade.add("Correct:" + correct + " (" + String.join(", ", correctIndex) + ")");
        grade.add("Wrong:" + wrong + " (" + String.join(", ", gradeIndex) + ")");
        FileUtil.writeFile("Grade.txt", grade);
    }
}

Problem

public class Problem {
    public String exercises;
    public String answers;

    public Problem(String exercises, String answers) {
        this.exercises = exercises;
        this.answers = answers;
    }
}

FileUtil

public class FileUtil {
    public static List<String> readFile(String filePath) {
        List<String> lines = new ArrayList<>();
        File file = new File(filePath);
        if (!file.exists()) {
            throw new RuntimeException("无法加载文件");
        }
        try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
            String line;
            while ((line = reader.readLine()) != null) {
                lines.add(line);
            }
        } catch (IOException e) {
            throw new RuntimeException("文件读取失败");
        }
        return lines;
    }

    public static void writeFile(String filePath, List<String> lines) {
        File file = new File(filePath);
        try (FileWriter writer = new FileWriter(file)) {
            for (String line : lines) {
                writer.write(line + "\n");
            }
        } catch (IOException e) {
            throw new RuntimeException("文件写入失败");
        }
    }
}

Fraction

public class Fraction {
    private int numerator;
    private int denominator;

    public Fraction(int numerator, int denominator) {
        this.numerator = numerator;
        this.denominator = denominator;
        simplify();
    }

    public int getNumerator() {
        return numerator;
    }

    public int getDenominator() {
        return denominator;
    }

    public Fraction add(Fraction other) {
        return new Fraction(this.numerator * other.denominator + other.numerator * this.denominator,
                this.denominator * other.denominator);
    }

    public Fraction subtract(Fraction other) {
        return new Fraction(this.numerator * other.denominator - other.numerator * this.denominator,
                this.denominator * other.denominator);
    }

    public Fraction multiply(Fraction other) {
        return new Fraction(this.numerator * other.numerator,
                this.denominator * other.denominator);
    }

    public Fraction divide(Fraction other) {
        return new Fraction(this.numerator * other.denominator,
                this.denominator * other.numerator);
    }

    private void simplify() {
        int gcd = gcd(numerator, denominator);
        numerator /= gcd;
        denominator /= gcd;
    }

    private int gcd(int a, int b) {
        return b == 0 ? a : gcd(b, a % b);
    }

    public int compareTo(Fraction other) {
        return Integer.compare(this.numerator * other.denominator, other.numerator * this.denominator);
    }

    @Override
    public String toString() {
        if (numerator == 0) {
            return "0";
        }
        if (Math.abs(numerator) < denominator) {
            return numerator + "/" + denominator;
        }
        int intPart = numerator / denominator;
        int numerator1 = Math.abs(numerator) % denominator;
        return numerator1 == 0 ? String.valueOf(intPart) : intPart + "'" + numerator1 + "/" + denominator;
    }
}

ProblemGenerator

public class ProblemGenerator {
    private static final char[] OPERATORS = {'+', '-', '×', '÷'};
    private static final Random RANDOM = new Random();

    /**
     * 生成题目
     */
    public static Problem generateProblem(int r) {
        String exercises = generateExercises(r);
        String answer = calculateAnswer(exercises);
        // 循环直到题目符合要求
        while (answer == null) {
            exercises = generateExercises(r);
            answer = calculateAnswer(exercises);
        }
        return new Problem(exercises, answer);
    }

    /**
     * 判定答案
     */
    public static boolean judgeProblem(String exercises, String answer) {
        return Objects.equals(calculateAnswer(exercises), answer);
    }

    /**
     * 生成表达式
     */
    public static String generateExercises(int r) {
        StringBuilder sb = new StringBuilder();
        sb.append(generateNumber(r));
        for (int i = 0; i < RANDOM.nextInt(3) + 1; i++) {
            sb.append(" ").append(generateOperator()).append(" ").append(generateNumber(r));
        }
        return sb.toString();
    }

    /**
     * 生成运算符
     */
    private static String generateOperator() {
        return String.valueOf(OPERATORS[new Random().nextInt(OPERATORS.length)]);
    }

    /**
     * 判断运算符
     */
    private static boolean isOperator(char c) {
        for (char operator : OPERATORS) {
            if (operator == c) {
                return true;
            }
        }
        return false;
    }

    /**
     * 生成数字
     */
    private static String generateNumber(int r) {
        return new Fraction(
                RANDOM.nextInt(r - 1) + 1,
                RANDOM.nextInt(r - 1) + 1
        ).toString();
    }

    /**
     * 计算答案
     */
    private static String calculateAnswer(String exercises) {
        Stack<Fraction> numStack = new Stack<>();
        Stack<Character> operator = new Stack<>();
        // 加入操作栈
        for (String str : exercises.split(" ")) {
            if (str.length() == 1 && isOperator(str.charAt(0))) {
                operator.push(str.charAt(0));
            } else {
                // 转为分数计算
                numStack.push(getFraction(str));
            }
        }
        while (!operator.isEmpty()) {
            char op = operator.pop();
            Fraction num2 = numStack.pop();
            Fraction num1 = numStack.pop();
            if (op == '+' || op == '-') {
                // 优先计算乘除
                if (!operator.isEmpty() && (operator.peek() == '×' || operator.peek() == '÷')) {
                    Fraction num3 = numStack.pop();
                    Character op1 = operator.pop();
                    if (op1 == '×') {
                        num1 = num1.multiply(num3);
                    } else if (op1 == '÷') {
                        if (num3.getNumerator() == 0) {
                            return null;
                        }
                        num1 = num1.divide(num3);
                    }
                }
                if (op == '+') {
                    numStack.push(num1.add(num2));
                } else {
                    // 如果存在形如e1− e2的子表达式,那么e1≥e2
                    if (num1.compareTo(num2) >= 0) {
                        numStack.push(num1.subtract(num2));
                    } else {
                        return null;
                    }
                }
            } else if (op == '×') {
                numStack.push(num1.multiply(num2));
            } else if (op == '÷') {
                if (num2.getNumerator() == 0) {
                    return null;
                }
                numStack.push(num1.divide(num2));
            }
        }
        return numStack.size() == 1 ? numStack.pop().toString() : null;
    }

    /**
     * 转换为分数
     */
    private static Fraction getFraction(String str) {
        if (str.contains("'")) {
            String[] parts = str.split("[/']");
            int intPart = Integer.parseInt(parts[0]);
            int numerator = Integer.parseInt(parts[1]);
            int denominator = Integer.parseInt(parts[2]);
            numerator += intPart * denominator;
            return new Fraction(numerator, denominator);
        }
        if (str.contains("/")) {
            String[] parts = str.split("/");
            return new Fraction(Integer.parseInt(parts[0]), Integer.parseInt(parts[1]));
        }
        return new Fraction(Integer.parseInt(str), 1);
    }
}

项目测试

测试用例

public class MainTest {
    @Test
    public void test1() {
        Main.main(new String[]{});
    }

    @Test
    public void test2() {
        Main.main(new String[]{"-n", "10", "-r", "10"});
    }

    @Test
    public void test3() {
        Main.main(new String[]{"-n", "-1", "-r", "10"});
    }

    @Test
    public void test4() {
        Main.main(new String[]{"-n", "10005", "-r", "10"});
    }

    @Test
    public void test5() {
        Main.main(new String[]{"-e", "e.txt", "-a", "a.txt"});
    }

    @Test
    public void test6() {
        Main.main(new String[]{"-e", "e", "-a", "a"});
    }

    @Test
    public void test7() {
        Main.main(new String[]{"-e", "Exercises.txt", "-a", "Answers.txt"});
    }

    @Test
    public void test8() {
        Main.main(new String[]{"-e", "Exercises.txt", "-a", "ErrorAnswers.txt"});
    }

    @Test
    public void test9() {
        Main.main(new String[]{"-e", "Exercises.txt", "-b", "ErrorAnswers.txt"});
    }

    @Test
    public void test10() {
        Main.main(new String[]{"-n", "10", "-f", "10"});
    }
}

覆盖率测试

除文件输入输出流异常外覆盖了项目所有分支。

性能测试

选择生成一万条题目进行性能测试,主要耗时在于文件写入、问题生成和答案生成。

项目小结

本次项目运用软件系统设计各方面知识,包括选择合理的算法、使用分治思想抽象系统模块、使用面向对象编程抽象题目和分数、将系统划分为多层进行解耦合、编写测试接口并进行性能分析等。此次任务能够增强我软件开发的能力并提高我系统设计的综合能力。

标签:结对,return,String,项目,int,denominator,new,public
From: https://www.cnblogs.com/chocohql/p/18432598

相关文章

  • 结对项目:四则运算自动生成程序
    [github地址]https://github.com/kkrInblU/3222004510.githttps://github.com/115any/3222004512.git这个作业属于哪个课程https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/这个作业要求在哪里https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/homework/13230......
  • 【鸟类识别系统】计算机毕设项目+卷积神经网络算法+人工智能+深度学习+模型训练+Pytho
    一、介绍鸟类识别系统。本系统采用Python作为主要开发语言,通过使用加利福利亚大学开源的200种鸟类图像作为数据集。使用TensorFlow搭建ResNet50卷积神经网络算法模型,然后进行模型的迭代训练,得到一个识别精度较高的模型,然后在保存为本地的H5格式文件。在使用Django开发Web网......
  • 结对项目
    一、作业信息这个作业属于哪个课程班级链接这个作业要求在哪里作业要求这个作业的目标组队设计实现一个生成小学四则运算题目的命令行程序二、小组成员姓名学号github陈大锴3122004816https://github.com/ez4-cdk/ez4-cdk/tree/master/3122004816......
  • 结对项目
    结对项目————四则运算的实现这个作业属于哪个课程https://edu.cnblogs.com/campus/gdgy/CSGrade22-34这个作业要求在哪https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/homework/13230这个作业的目标设计一个四则运算生成器项目成员一梁俊轩31220045......
  • 自然语言处理实战项目:从理论到实现
    一、引言自然语言处理(NLP)是计算机科学、人工智能和语言学交叉的领域,旨在让计算机能够理解、处理和生成人类语言。随着互联网的飞速发展,大量的文本数据被产生,这为自然语言处理技术的发展提供了丰富的素材,同时也对其性能提出了更高的要求。在本文中,我们将详细阐述一个自然语......
  • 结对项目
    这个作业属于哪个课程https://edu.cnblogs.com/campus/gdgy/CSGrade22-12这个作业要求在哪里https://edu.cnblogs.com/campus/gdgy/CSGrade22-12/homework/13221这个作业的目标结对合作完成项目两位同学的姓名许莹柔,学号:3222004684肖晓霞,学号:322200......
  • GitHub每日最火火火项目(9.27)
    项目名称:localsend/localsend项目介绍:“localsend/localsend”是一个极具价值的开源项目。它为用户提供了一种跨平台的文件传输替代方案,可媲美AirDrop。在当今数字化时代,人们常常需要在不同操作系统的设备之间传输文件,但并非所有设备都能使用AirDrop。这个项目的出......
  • Springboot大学生创新创业项目管理系统sg2u6(程序+源码+数据库+调试部署+开发环境)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表学生,教师,专家,项目类别,项目申报,中期检查,中期评价,项目结题,结题评价开题报告内容一、研究背景与意义在当前的知识经济时代,创新创业已成为推动社会发展和提......
  • 软件工程结队项目:基于C++实现的自动生成小学四则运算的命令行程序
    这个作业属于哪个课程https://edu.cnblogs.com/campus/gdgy/CSGrade22-34这个作业要求在哪里https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/homework/13230这个作业的目标<运用C++实现四则运算法则的命令行程序>团队成员1李梓灏3122004695团队成员2吴......
  • 快速创建SpringBoot项目
     1.使用SpringInitializr创建项目1.1.在线生成项目         访问SpringInitializr网站            选择项目的基本配置:Project:MavenProject或GradleProject(通常使用Maven)Language:JavaSpringBootVersion:......