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

结对项目

时间:2024-03-26 13:00:12浏览次数:29  
标签:index 结对 num1 num2 项目 else let calculate

这个作业属于哪个课程 软件工程
这个作业要求在哪里 结对项目

一、合作者

姓名 学号
张楠 3222004599
周广 3122004418
github 链接

二、PSP表格

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

三、设计实现过程

1.代码组织

  • 引入依赖库

  • main.rs

use std::error::Error;
fn main() -> Result<(), Box<dyn Error>>{
    let matches = miniopgenerator::get_args();

    miniopgenerator::run_args(matches)
}
  • get_args
// 获取命令行指令
pub fn get_args() -> ArgMatches {
    let matches = Command::new("MyApp")
        .version("1.0.0")
        .author("zg")
        .about("A mini quadratic operator generator")
        .arg(
            Arg::new("num")
                .short('n')
                .long("num")
                .value_parser(value_parser!(usize))
                .help("Use this parameter to control the number of generated topics"),
        )
        .arg(
            Arg::new("realm")
                .short('r')
                .long("realm")
                .value_parser(value_parser!(i32))
                .help("Use this parameter to control the range of values in the title"),
        )
        .arg(
            Arg::new("exercisefile")
                .short('e')
                .long("exercisefile")
                .value_parser(value_parser!(String))
                .help("Exercisefile name")
                .group("input")
                .requires("answerfile"),
        )
        .arg(
            Arg::new("answerfile")
                .short('a')
                .long("answerfile")
                .value_parser(value_parser!(String))
                .help("Answerfile name")
                .requires("input"),
        )
        .get_matches();

    matches
}
  • run_arg
// 执行命令
pub fn run_args(matches: ArgMatches) -> Result<(), Box<dyn Error>> {
    if let (Some(num), Some(realm)) = (
        matches.get_one::<usize>("num"),
        matches.get_one::<i32>("realm"),
    ) {
        generate_expression(num, realm);
    }
    if let (Some(exercisefile), Some(answerfile)) = (
        matches.get_one::<String>("exercisefile"),
        matches.get_one::<String>("answerfile"),
    ) {
        check_answer(exercisefile, answerfile)?;
    }

    Ok(())
}
  • write_to_file
// 写入文件
fn write_to_file(filename: &str, content: Vec<String>) -> std::io::Result<()> {
    let mut file = File::create(filename).expect("创建文件失败!");
    let mut ansfile = File::create("Answers.txt").expect("创建文件失败!");
    for (index, exp) in content.iter().enumerate() {
        write!(file, "{}. {} = \n", index + 1, exp)?;
        write!(
            ansfile,
            "{}. {} = {}\n",
            index + 1,
            exp,
            calculate_fraction(exp)
        )?;
    }
    Ok(())
}
  • check_answer
// 检查答案
fn check_answer(exercisefile: &String, answerfile: &String) -> io::Result<()> {
    let exercises = fs::read_to_string(exercisefile)?;
    let answers = fs::read_to_string(answerfile)?;

    // 使用正则表达式来消去题目前面的序号
    let re = Regex::new(r"\d+\. ").unwrap();

    let mut correct_count = 0;
    let mut incorrect_count = 0;
    let mut correct_indices = Vec::new();
    let mut incorrect_indices = Vec::new();

    for (index, (question, answer)) in exercises.lines().zip(answers.lines()).enumerate() {
        let tokens: Vec<_> = answer.split(' ').collect();
        let question = &question[0..question.trim().len() - 1];
        if let Some(captures) = re.captures(question) {
            let calculate_ans = calculate_fraction(
                &question[captures.get(0).unwrap().end()..]
                    .trim()
                    .to_string(),
            );
            if let Some(ans) = tokens.last() {
                if ans.to_string() == calculate_ans {
                    correct_count += 1;
                    correct_indices.push(index + 1);
                } else {
                    incorrect_count += 1;
                    incorrect_indices.push(index + 1);
                }
            }
        }
    }

    let grade_result = format!(
        "Correct: {} ({:?})\nWrong: {} ({:?})",
        correct_count, correct_indices, incorrect_count, incorrect_indices
    );

    fs::write("Grade.txt", grade_result)?;

    Ok(())
}
  • Operator
// 定义一个枚举来表示四则运算符
enum Operator {
    Add,
    Subtract,
    Multiply,
    Divide,
}

// 为Operator实现一个方法,用于将其转换为字符串表示
impl Operator {
    fn to_string(&self) -> &str {
        match self {
            Operator::Add => "+",
            Operator::Subtract => "-",
            Operator::Multiply => "*",
            Operator::Divide => "/",
        }
    }
}

// 实现Distribution trait,以便我们可以使用rand::random()来生成Operator
impl Distribution<Operator> for Standard {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Operator {
        match rng.gen_range(0..4) {
            0 => Operator::Add,
            1 => Operator::Subtract,
            2 => Operator::Multiply,
            _ => Operator::Divide,
        }
    }
}
  • ExpressionNode
enum ExpressionNode {
    Number(i32),
    Operation(Box<ExpressionNode>, Operator, Box<ExpressionNode>),
}

// 实现一个方法来将表达式节点转换为字符串
impl ExpressionNode {
    fn to_string(&self) -> String {
        match self {
            ExpressionNode::Number(num) => num.to_string(),
            ExpressionNode::Operation(left, op, right) => {
                let left_str = left.to_string();
                let right_str = right.to_string();
                match right.as_ref() {
                    ExpressionNode::Number(_) => {
                        return format!("{} {} {}", left_str, op.to_string(), right_str)
                    }
                    _ => (),
                }
                if rand::thread_rng().gen_bool(0.5) {
                    format!("{} {} ({})", left_str, op.to_string(), right_str)
                } else {
                    format!("{} {} {}", left_str, op.to_string(), right_str)
                }
            }
        }
    }
}
  • build_expression_tree
// 递归函数来构建表达式树
fn build_expression_tree(rng: &mut impl Rng, depth: usize, realm: i32) -> ExpressionNode {
    let node = ExpressionNode::Number(rng.gen_range(1..realm));
    let operator = rng.sample(Standard);

    if depth > 1 {
        // 随机决定是否继续添加运算符
        if rng.gen_bool(0.5) {
            let right = match operator {
                Operator::Divide => {
                    // 确保除法结果为真分数
                    let numerator = match node {
                        ExpressionNode::Number(value) => value,
                        _ => panic!("获取随机值失败!"),
                    };
                    let denominator = rng.gen_range(1..realm) + numerator;
                    Box::new(ExpressionNode::Number(denominator))
                }
                Operator::Subtract => {
                    // 确保减法结果为正数
                    let numerator = match node {
                        ExpressionNode::Number(value) => value,
                        _ => panic!("获取随机值失败!"),
                    };
                    if numerator == 1 {
                        Box::new(ExpressionNode::Number(numerator))
                    } else {
                        Box::new(ExpressionNode::Number(
                            numerator - (rng.gen_range(1..numerator)),
                        ))
                    }
                }
                _ => Box::new(build_expression_tree(rng, depth - 1, realm)),
            };
            ExpressionNode::Operation(Box::new(node), operator, right)
        } else {
            // 如果不添加运算符,直接返回
            let right = generate_right(rng, &node, &operator, realm);
            ExpressionNode::Operation(Box::new(node), operator, right)
        }
    } else {
        // 如果达到最大深度,直接返回
        let right = generate_right(rng, &node, &operator, realm);
        ExpressionNode::Operation(Box::new(node), operator, right)
    }
}
  • generate_right
fn generate_right(
    rng: &mut impl Rng,
    node: &ExpressionNode,
    operator: &Operator,
    realm: i32,
) -> Box<ExpressionNode> {
    match operator {
        Operator::Divide => {
            // 确保除法结果为真分数
            let numerator = match *node {
                ExpressionNode::Number(value) => value,
                _ => panic!("获取随机值失败!"),
            };
            let denominator = rng.gen_range(1..realm) + numerator;
            Box::new(ExpressionNode::Number(denominator))
        }
        Operator::Subtract => {
            // 确保减法结果为正数
            let numerator = match *node {
                ExpressionNode::Number(value) => value,
                _ => panic!("获取随机值失败!"),
            };
            if numerator == 1 {
                Box::new(ExpressionNode::Number(numerator))
            } else {
                Box::new(ExpressionNode::Number(
                    numerator - (rng.gen_range(1..numerator)),
                ))
            }
        }
        _ => Box::new(ExpressionNode::Number(rng.gen_range(1..realm))),
    }
}
  • add_brace
// 添加左括号
fn add_braces(exp: &str) -> String {
    let operators = vec!['+', '-', '*', '/'];
    let pos1 = exp.chars().position(|c| operators.contains(&c));
    let pos2 = exp[pos1.unwrap() + 1..]
        .chars()
        .position(|c| operators.contains(&c));

    match (pos1, pos2) {
        (Some(index1), Some(index2)) => format!(
            "({}){}",
            &exp[0..(index1 + index2)],
            &exp[(index1 + index2)..]
        ),
        _ => exp.to_string(),
    }
}
  • generate_expression
fn generate_expression(num: &usize, realm: &i32) {
    let mut rng = rand::thread_rng();
    let mut vecexp: Vec<_> = Vec::new();
    for _ in 0..*num {
        // 构建一个包含最多三个运算符的表达式树
        let expression_tree = build_expression_tree(&mut rng, 2, *realm);

        // 将表达式树转换为字符串
        let mut expression_str = expression_tree.to_string();

        if expression_str.chars().last().unwrap() != ')' {
            if rand::thread_rng().gen_bool(0.5) {
                expression_str = add_braces(&expression_str);
            }
        }
        vecexp.push(expression_str);
    }
    write_to_file("Exercises.txt", vecexp).expect("写入文件失败!");
}
  • calculate_fraction
// 四则计算
fn calculate_fraction(exp: &String) -> String {
    let tokens: Vec<&str> = exp.split(&[' ', '(', ')']).collect();
    let (opening_index, closing_index) = find_parentheses_indices(&tokens);
    match (opening_index, closing_index) {
        (Some(op_index), Some(close_index)) => {
            let num1 = tokens[op_index + 1].parse::<i32>().unwrap();
            let num2 = tokens[close_index - 1].parse::<i32>().unwrap();
            let op1 = tokens[op_index + 2];
            let (op2, num3) = if op_index == 0 {
                (
                    tokens[close_index + 1],
                    tokens[close_index + 2].parse::<i32>().unwrap(),
                )
            } else {
                (tokens[op_index - 1], tokens[0].parse::<i32>().unwrap())
            };
            let ans = calculate(num1, num2, op1);
            if op1 == "/" {
                if op2 == "+" {
                    return format!("{}'{}", num3, ans);
                } else if op2 == "*" {
                    return calculate(num1 * num3, num2, op1);
                } else if op2 == "/" {
                    return calculate(num1, num2 * num3, op1);
                } else {
                    return calculate(num1 - (num2 * num3), num2, op1);
                }
            } else {
                let ans = ans.parse::<i32>().unwrap();
                return calculate(ans, num3, op2);
            }
        }
        _ => {
            let num1 = tokens[0].parse::<i32>().unwrap();
            let num2 = tokens[2].parse::<i32>().unwrap();
            let op1 = tokens[1];
            if tokens.len() < 5 {
                calculate(num1, num2, op1)
            } else {
                let num3 = tokens[4].parse::<i32>().unwrap();
                let op2 = tokens[3];
                if op1 == "/" {
                    let ans = calculate(num1, num2, op1);
                    if op2 == "+" {
                        return format!("{}'{}", num3, ans);
                    } else if op2 == "*" {
                        return calculate(num1 * num3, num2, op1);
                    } else if op2 == "/" {
                        return calculate(num1, num2 * num3, op1);
                    } else {
                        return calculate(num1 - (num2 * num3), num2, op1);
                    }
                } else if op1 == "*" {
                    return calculate(num1 * num2, num3, op2);
                } else if op2 == "/" {
                    if op1 == "-" {
                        return calculate((num1 * num3) - num2, num3, op2);
                    } else {
                        return format!("{}'{}", num1, calculate(num2, num3, op2));
                    }
                } else if op2 == "*" {
                    return calculate(num1, num2 * num3, op1);
                } else {
                    let ans = calculate(num1, num2, op1).parse::<i32>().unwrap();
                    calculate(ans, num3, op2)
                }
            }
        }
    }
}
  • calculate
fn calculate(num1: i32, num2: i32, op: &str) -> String {
    if op == "+" {
        (num1 + num2).to_string()
    } else if op == "-" {
        (num1 - num2).to_string()
    } else if op == "*" {
        (num1 * num2).to_string()
    } else {
        if num2 == 0 {
            panic!("除数不能为0");
        }
        let common_divisor = gcd(num1, num2);
        let num1 = num1 / common_divisor;
        let num2 = num2 / common_divisor;
        if num1 > num2 {
            format!("{}'{}/{}", num1 / num2, num1 % num2, num2)
        } else {
            format!("{}/{}", num1, num2)
        }
    }
}
  • gcd
fn gcd(a: i32, b: i32) -> i32 {
    let mut a = a;
    let mut b = b;
    while b != 0 {
        let temp = b;
        b = a % b;
        a = temp;
    }
    a
}
  • find_parentheses_indice
fn find_parentheses_indices(vec: &Vec<&str>) -> (Option<usize>, Option<usize>) {
    let opening_parenthesis_index = vec.iter().position(|&item| item == "");
    let closing_parenthesis_index = vec.iter().rposition(|&item| item == "");

    (opening_parenthesis_index, closing_parenthesis_index)
}

四、代码说明

1、关键代码

(1)get_args
使用 Rust 中的 clap 库来定义命令行参数,并解析用户提供的命令行参数

(2)run_args
根据命令行参数执行一些操作,包括生成四则运算表达式并写入文件,以及输出指定的文件名。

(3)build_expression_tree
根据给定的深度和数值范围生成一个四则运算表达式的表达式树。

(4)generate_right
根据当前节点的运算符生成一个合适的右子树节点,用于构建四则运算表达式的表达式树。

(5)calculate_fraction
计算这个数学表达式的结果,并返回结果的字符串形式。

(6)check_answer
计算出给的exercisefile的答案,与answerfile进行对比,将所得结果输出到Grade.txt中。

2、思路说明

(1)get_args
这个函数定义了一个名为 get_args 的公共函数(即 pub 关键字修饰的),其返回类型为 ArgMatches。ArgMatches 是 clap 库中的一个结构体,用于存储解析后的命令行参数信息。最后,通过调用 get_matches() 方法,对用户提供的命令行参数进行解析,并将解析结果存储在 matches 变量中,然后将 matches 变量作为函数的返回值返回。
(2)run_args
run_args函数根据命令行参数执行操作。首先,根据提供的参数生成四则运算表达式,确保数值范围符合要求,并将表达式写入文件。然后,检查是否指定了文件名参数,如果有,则输出相应的文件名。最后,返回执行成功的结果。
(3)build_expression_tree
build_expression_tree 函数用于构建四则运算表达式的表达式树。通过递归地生成表达式节点,首先生成根节点,然后根据给定的深度逐层生成子节点,直到达到最大深度。在生成节点过程中,根据随机选择的运算符,确保除法结果为真分数,减法结果为正数,保证生成的表达式符合规则。最后返回构建好的表达式树的根节点。
(4)enerate_right
generate_right 函数用于生成四则运算表达式的右子树节点。根据当前节点的运算符,确保生成的右子树节点满足特定条件,如除法结果为真分数,减法结果为正数。通过模式匹配和随机数生成来实现不同运算符下的条件判断和节点生成。最后返回生成的右子树节点。
(5)calculate_fraction
calculate_fraction接受一个数学表达式的字符串,计算其结果并返回。它首先将表达式拆分成片段,然后根据运算符的顺序和括号的位置进行递归计算。根据运算符的不同,采取不同的计算策略,最终得出表达式的结果。
(6)test_get_args_exercis
模拟了用户在命令行中输入参数的情况,然后创建了一个命令行应用程序,并定义了两个参数:exercisefile 和 answerfile,分别表示练习文件和答案文件的名称。接着,通过解析命令行参数,并使用断言来验证解析结果是否符合预期。如果测试通过,表示命令行参数解析功能正常运作。

五、测试运行

(1)生成100个算式

(2)下载算式

(3)统计结果输入到grade.txt

(4)下载答案与题目

六、项目小结

小结1:

周广
虽然最初对项目的整体思路有所了解,但具体实现过程花费了更多时间。发现问题和解决方案之间的鸿沟可能比预期更大,特别是在处理重复表达式和添加多个小括号时遇到困难。即使有结对编程的支持,合作伙伴提供了一些帮助和思路,但整体而言,还是花费了相当多的时间在讨论和熟悉工具上。这表明了即使有初步的想法,实际的实现仍然可能面临各种挑战和耗时的任务。

小结2:

张楠
刚刚开始接到项目时,我感到有些迷茫,不知道从哪里下手。但随着查阅资料和与搭档的交流,我逐渐理解了项目的大致思路。完成这个作业,很大程度上得益于有一个优秀的搭档。他在编程方面的能力远超过我,能够快速构思整个项目的框架,确定所需的主要函数,甚至提供了这些函数的实现思路。在短短的一个下午,他向我解释了他的构想,解答了我的疑问,并帮助我建立了项目的框架。有了他的帮助,我才得以顺利完成这个任务。

标签:index,结对,num1,num2,项目,else,let,calculate
From: https://www.cnblogs.com/Guan9Z/p/18096440

相关文章

  • 结对项目
    杨宇航3122004498赵军3122004501这个作业属于哪个课程https://edu.cnblogs.com/campus/gdgy/SoftwareEngineering2024这个作业要求在哪里结对项目-作业-软件工程2024-班级博客-博客园(cnblogs.com)这个作业的目标1.能够生成包含自然数和真分数的四......
  • 信息系统项目管理师——第7章项目立项管理
    本章考选择题2-3分,案例和论文均有可能作为领域考试。项目建议与立项申请♥♥♥♥♥立项申请的概念立项申请又称为项目建议书,是项目建设单位向上级主管部门提交项目申请时所必须的文件,是该项目建设筹建单位根据国民经济的发展、国家和地方中长期规划、产业政策、生产力......
  • 海量数据处理项目-账号微服务和流量包数据库表+索引规范(下)
    海量数据处理项目-账号微服务和流量包数据库表+索引规范(下)第2集账号微服务和流量包数据库表+索引规范讲解《下》简介:账号微服务和流量包数据库表+索引规范讲解账号和流量包的关系:一对多traffic流量包表思考点海量数据下每天免费次数怎么更新?海量数据付费流量套餐包每天......
  • 使用Go语言开发一个短链接服务:三、项目目录结构设计
    章节 使用Go语言开发一个短链接服务:一、基本原理 使用Go语言开发一个短链接服务:二、架构设计 使用Go语言开发一个短链接服务:三、项目目录结构设计 使用Go语言开发一个短链接服务:四、生成code算法 使用Go语言开发一个短链接服务:五、添加和获取短链接 使用Go语言开......
  • 智慧工地解决方案,智慧工地项目管理系统源码,支持大屏端、PC端、手机端、平板端
    智慧工地解决方案依托计算机技术、物联网、云计算、大数据、人工智能、VR&AR等技术相结合,为工程项目管理提供先进技术手段,构建工地现场智能监控和控制体系,弥补传统方法在监管中的缺陷,最线实现项目对人、机、料、法、环的全方位实时监控。支持多端展示(大屏、PC端、手机端、平板......
  • vue3+ts项目引入富文本编辑器wangeditor
    说明项目开发中,做到媒体说、资讯等模块时,会需要引入富文本编辑器,对比发现wangeditor使用群众多,并且很多问题也已经有解答。界面展示实现要点引入wangeditor配置导航栏代码<template><divstyle="border:1pxsolid#EEEFF0;border-radius:5px;overflow:hidden;wid......
  • Springboot项目的main函数入口,如何像jar包一样接受参数
    一般来说,springboot项目是提供服务的,但是也可以用到导出jar来启动,那么如何介绍参数呢:packagecom.example.TestDemo;importcom.example.jmeter.bean.TestCaseResult;importcom.example.jmeter.controller.JmeterController;importlombok.extern.slf4j.Slf4j;importorg.......
  • 使用Github托管Unity项目
    ​准备工作在本机生成ssh密钥ssh-keygen-trsa-C"你的邮箱地址"点击回车后会出现生成的密钥路径,我们直接打开密钥复制下来。github官网添加我们的本机密钥进入Github官网,点击设置,选择SSHandGPGkeys点击newSSHkey,将我们刚才在本机生成的ssh密钥放入key中,并起......
  • EECS 183项目分析
    EECS183项目4:酷派图片p4酷图片EECS183项目4:CoolPics项目截止时间:2024年3月22日星期五晚上11:59直接自动标记链接在这个项目中,您将创建一个程序,读取形状的描述,绘制形状,并将结果保存到文件中。您将使用表示不同的形状。在这里以下是学生在上学期创作的一些图像示例:EECS183项目4......
  • 结对项目
    这个作业属于哪个课程<软件工程2024(广东工业大学)>这个作业要求在哪里<结对项目>这个作业的目标<团队互相合作完成一个随机生成四则运算题目的项目>Gitee链接:https://github.com/messagelost/Arithmetic-Operations一、团队介绍项目合作者学号陈......