个人项目队友代码分析

个人项目队友崔光博Cui_GOD_Bo代码分析

队友:崔光博
语言:Rust

代码结构

运行截图

优点

  • 生成题目除了生成文件还直接打印在控制台,方便迅速查看题目质量

  • 结构层次清晰,便于后续开发

  • 各类函数封装良好

  • 注释详细易于理解

  • 题目查重使用redis,键值数据库效率高

  • 程序运行时未检测出bug

  • 生成题目方法巧妙,在生成的过程中即可计算答案

    队友的项目比较巧妙的地方即是生成题目并计算答案的方法。以二叉树为载体,保存符号节点的两个子数字节点的运算结果,逐层往上生成题目,期间计算两个子节点运算答案时根据运算符号优先级加括号。

    /// # OperationTreeNode
    /// * op: 节点值
    /// * left: 左子树
    /// * right: 右子树
    #[derive(Debug, PartialEq, Eq)]
    pub struct OperationTreeNode<'a> {
        op: OperationVal<'a>,
        left: Option<Rc<RefCell<OperationTreeNode<'a>>>>,
        right: Option<Rc<RefCell<OperationTreeNode<'a>>>>,
    }
    /// # OpearionTree
    /// * size: 仅表示操作符个数
    /// * root: 根节点
    #[derive(Debug, PartialEq, Eq)]
    pub struct OperationTree<'a> {
        size: u32,
        root: Option<Rc<RefCell<OperationTreeNode<'a>>>>,
    }
    impl<'a> OperationTreeNode<'a> {
        pub fn new(oper: OperationVal<'a>) -> Self {
            OperationTreeNode {
                op: oper,
                left: None,
                right: None,
            }
        }
    }
    
    impl<'a> OperationTree<'a> {
        /// 构造一棵指定难度系数的表达式数(即一道数学题)
        ///
        /// <em>@para t: 题目难度</em>
        ///
        /// # Examples
        ///
        /// ```
        /// use self_project::model::{OperationTree, Type};
        ///
        /// let tree: OperationTree = OperationTree::build(Type::High);
        /// println!("{:?}", tree);
        /// ```
        pub fn build(t: Type, limit: u32) -> Self {
            let mut tree = OperationTree {
                size: 0,
                root: Some(Rc::new(RefCell::new(OperationTreeNode::new(
                    OperationVal::Empty,
                )))),
            };
            let max_size: u32 = rand::random();
            Self::build_helper(&mut tree.root, &t, (max_size % limit) + 1, &mut tree.size);
            tree
        }
    
        /// private不提供文档
        fn build_helper(
            root: &mut Option<Rc<RefCell<OperationTreeNode>>>,
            t: &Type,
            max_size: u32,
            size: &mut u32,
        ) {
            if root.is_none() {
                *root = Some(Rc::new(RefCell::new(OperationTreeNode::new(
                    OperationVal::Empty,
                ))));
            }
            let node = Rc::clone(root.as_ref().unwrap());
            if *size == max_size {
                let n: u32 = rand::random();
                node.borrow_mut().op = OperationVal::Val((n % 100) + 1);
                return;
            }
    
            let tmp: u32 = rand::random();
            let op = Question::next_operation(t);
            let op_val = if *size == 0 || (tmp & 0x3) <= 2 {
                *size += 1;
                OperationVal::Op(op)
            } else {
                OperationVal::Val((tmp % 100) + 1)
            };
            node.borrow_mut().op = op_val;
    
            if let OperationVal::Op(x) = op_val {
                match OPERATIONS_TYPES.get(x).unwrap() {
                    OperationType::TwoParaOp => {
                        if tmp & 0x1 == 0x0 {
                            Self::build_helper(&mut node.borrow_mut().left, t, max_size, size);
                            Self::build_helper(&mut node.borrow_mut().right, t, max_size, size);
                        } else {
                            Self::build_helper(&mut node.borrow_mut().right, t, max_size, size);
                            Self::build_helper(&mut node.borrow_mut().left, t, max_size, size);
                        }
                    }
                    OperationType::LeftOp => {
                        Self::build_helper(&mut node.borrow_mut().right, t, max_size, size);
                    }
                    OperationType::RightOp => {
                        Self::build_helper(&mut node.borrow_mut().left, t, max_size, size)
                    }
                    OperationType::FunctionOp => {
                        Self::build_helper(&mut node.borrow_mut().left, t, max_size, size)
                    }
                }
            }
        }
    
        /// 将表达式树转换为字符串
        pub fn to_string(&self) -> String {
            if self.root.is_none() {
                return String::new();
            }
            Self::to_string_helper(self.root.as_ref(), OperationVal::Empty)
        }
    
        /// private函数不提供文档
        fn to_string_helper(
            root: Option<&Rc<RefCell<OperationTreeNode>>>,
            up_op: OperationVal,
        ) -> String {
            let node = Rc::clone(root.unwrap());
            let op_val = node.borrow().op;
            match op_val {
                OperationVal::Op(s) => match OPERATIONS_TYPES.get(s).unwrap() {
                    OperationType::TwoParaOp => {
                        if let OperationVal::Op(up) = up_op {
                            if (up.eq("*") || up.eq("/") || up.eq("_/") || up.eq("^2"))
                                && (s.eq("+") || s.eq("-"))
                                || (up.eq("^2"))
                                    && !(s.eq("sin") && s.eq("cos") && s.eq("tan")
                                        || up.eq("-") && (s.eq("-") || s.eq("+")))
                            {
                                return format!(
                                    "({} {} {})",
                                    Self::to_string_helper(
                                        node.borrow().left.as_ref(),
                                        OperationVal::Op(s)
                                    ),
                                    s,
                                    Self::to_string_helper(
                                        node.borrow().right.as_ref(),
                                        OperationVal::Op(s)
                                    )
                                );
                            }
                        }
                        return format!(
                            "{} {} {}",
                            Self::to_string_helper(node.borrow().left.as_ref(), OperationVal::Op(s)),
                            s,
                            Self::to_string_helper(node.borrow().right.as_ref(), OperationVal::Op(s))
                        );
                    }
                    OperationType::LeftOp => {
                        return format!(
                            "{}({})",
                            s,
                            Self::to_string_helper(node.borrow().right.as_ref(), OperationVal::Op(s))
                        );
                    }
                    OperationType::RightOp => {
                        return format!(
                            "{}{}",
                            Self::to_string_helper(node.borrow().left.as_ref(), OperationVal::Op(s)),
                            s
                        );
                    }
                    OperationType::FunctionOp => {
                        return format!(
                            "{}({})",
                            s,
                            Self::to_string_helper(node.borrow().left.as_ref(), OperationVal::Op(s))
                        );
                    }
                },
                OperationVal::Val(n) => {
                    return format!("{}", n);
                }
                OperationVal::Empty => String::new(),
            }
        }
    
        /// 计算表达式数的值
        pub fn calculate(&self) -> f64 {
            if self.root.is_none() {
                return 0_f64;
            }
            Self::calculate_helper(self.root.as_ref())
        }
    
        /// private函数不提供文档
        fn calculate_helper(root: Option<&Rc<RefCell<OperationTreeNode>>>) -> f64 {
            let node = Rc::clone(root.unwrap());
            let op_val = node.borrow().op.clone();
    
            match op_val {
                OperationVal::Op(op) => {
                    if let OperationType::TwoParaOp = OPERATIONS_TYPES.get(op).unwrap() {
                        let a = Self::calculate_helper(node.borrow().left.as_ref());
                        let b = Self::calculate_helper(node.borrow().right.as_ref());
                        if op.eq("+") {
                            return a + b;
                        } else if op.eq("-") {
                            return a - b;
                        } else if op.eq("*") {
                            return a * b;
                        } else {
                            return a / b;
                        }
                    } else if op.eq("_/") {
                        let a = Self::calculate_helper(node.borrow().right.as_ref());
                        return a.powf(0.5);
                    } else if op.eq("^2") {
                        let a = Self::calculate_helper(node.borrow().left.as_ref());
                        return a.powi(2);
                    } else {
                        let a = Self::calculate_helper(node.borrow().left.as_ref());
                        if op.eq("sin") {
                            return a.sin();
                        } else if op.eq("cos") {
                            return a.cos();
                        } else {
                            return a.tan();
                        }
                    }
                }
                OperationVal::Val(x) => {
                    return x as f64;
                }
                OperationVal::Empty => {
                    return 0_f64;
                }
            }
        }
    }
    

缺点

  • 终端提示信息少,有时候不知道当前需要输入什么

总结

队友在题目设计方面比较巧妙,项目设计结构清晰。好!

posted @ 2022-09-13 20:00  lIlINC  阅读(268)  评论(1编辑  收藏  举报