个人项目队友代码分析
个人项目队友崔光博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; } } } }
缺点
- 终端提示信息少,有时候不知道当前需要输入什么
总结
队友在题目设计方面比较巧妙,项目设计结构清晰。好!