结对编程之代码互评
作者:互联网
结对编程之代码互评
一、简介
这是我对我的队友姜涵的个人项目的评价
姜涵使用go语言实现中小学数学卷子自动生成程序的各种功能,满足了项目需求,代码结构清晰,分层明确。
二、项目需求
用户:小学、初中和高中数学老师。
功能:
- 用户通过账号密码登录。
- 登录之后,用户可以选择生成题目的类型并生成题目。
- 对题目数量有要求:10-30。
- 5、生成的题目将以“年-月-日-时-分-秒.txt”的形式保存,每个账号一个文件夹。
三、代码架构
Personal-Project
├── controllers
│ ├── Command.go # 控制命令读入,进入对应入口
│ ├── Generate.go # 控制生成题目的函数工作,检查生成结果
│ ├── Tree.go # 组织操作数与运算符,并生成题目
│ └── User.go # 控制用户输入账号密码登陆
├── go.mod
├── go.sum
├── main.go # 程序入口
├── models
│ └── base.go
├── out # 每个用户对应其中的一个文件夹
│ ├── 张三1
│ ├── 李四2
│ └── 王五3
└── sqlite
├── Question
└── Question.db # sqlite 数据库文件
1.自定义结构体
// User records information of current user
// These members initialize while input could be matched with users in database
type User struct {
Account string
Password string
Phase string
}
// TreeNode struct contains all operators and numbers
// leaf nodes stand for numbers, and other node stand for operators
// while generating the question, each un-leaf node become its Left value, its Val, its Right value
type TreeNode struct {
Left *TreeNode // Left node
Right *TreeNode // Right node
Val string // Val(value) of current node, operator or number
Level int //Level of current Val, number is -1, operator match its sequence in controller.Operator array
}
定义User结构体存储当前用户的信息,作为全局变量供所有函数使用
定义TreeNode结构体方便生成数学题
2.函数调用关系
3.函数具体实现
- main:程序的入口
- Login:得到命令行输入的账号密码,维持用户的登录状态
models.Teacher.Account = input[0]
models.Teacher.Password = input[1]
- LoginUser:
连接数据库
DB, _ = sql.Open("sqlite3", "sqlite/Question.db")
Sql := fmt.Sprintf("SELECT Account, Password, Phase FROM UserList WHERE Account = '%s' AND Password = '%s'", models.Teacher.Account, models.Teacher.Password)
rows, err := DB.Query(Sql)
验证输入的账号密码是否正确
for rows.Next() {
err = rows.Scan(&models.Teacher.Account, &models.Teacher.Password, &models.Teacher.Phase)
models.CheckError(err)
}
- GetCommand:调用
Generate
函数生成题目,更新用户信息 - Generate:
生成题目的函数为InitTree
和TransferTree
,函数中使用二叉树这个数据结构来组织题目的生成。将一个题目看做一棵满二叉树建树,然后通过中序遍历来遍历树生成题目
叶子结点中存放的为数字,其他节点存放的为操作符,TreeNode
中维护的Level
这个变量为运算符优先级,乘除的优先级高于加减法,所以当当前运算为3+2
而父节点的兄弟节点为乘法时就需要加上括号变为(3+2)* next number
func InitTree(node *models.TreeNode, cnt int) *models.TreeNode {
if cnt == 0 {
num := models.RandNumber(100) + 1
node.Val, node.Left, node.Right, node.Level = strconv.Itoa(num), nil, nil, -1
return node
}
num := models.RandNumber(limit)
node.Level = num
node.Val = Operator[num]
switch node.Level {
case 4:
num = 0
PhaseFlag = models.Max(PhaseFlag, 6)
case 5:
num = cnt - 1
PhaseFlag = models.Max(PhaseFlag, 6)
case 6, 7, 8:
num = 0
PhaseFlag = models.Max(PhaseFlag, 9)
default:
num = models.RandNumber(cnt)
}
node.Left, node.Right = new(models.TreeNode), new(models.TreeNode)
node.Left, node.Right = InitTree(node.Left, num), InitTree(node.Right, cnt-num-1)
return node
}
func TransferTree(node *models.TreeNode) (q string) {
if num, err := strconv.ParseInt(node.Val, 10, 32); err == nil {
q = strconv.Itoa(int(num))
return
}
LeftFormula := TransferTree(node.Left)
RightFormula := TransferTree(node.Right)
switch node.Level {
case 0, 1:
q = LeftFormula + " " + node.Val + " " + RightFormula
case 2, 3:
if node.Left.Level == 0 || node.Left.Level == 1 {
LeftFormula = "(" + LeftFormula + ")"
}
q = LeftFormula + " " + node.Val + " " + RightFormula
case 4:
q = node.Val + RightFormula + ")"
case 5:
if node.Left.Level != -1 {
LeftFormula = "(" + LeftFormula + ")"
}
q = LeftFormula + node.Val
default:
if node.Right.Level != -1 {
RightFormula = "(" + RightFormula + ")"
}
q = node.Val + RightFormula
}
return
}
这个算法非常优美非常巧妙,使用起来复杂度只有O(n)
而且在运算符优先级改变时能很容易的进行修改
- 错误处理函数
func CheckError(err error) {
if err != nil {
panic(err)
}
}
此项目的错误处理做的非常好
四、测试分析
测试登录函数
测试生成题目
在文件中查看生成的题目
在数据库中查看生成的题目
测试切换生成题目类型
测试退出登录
经过测试,发现此项目的所有功能均实现并且无任何bug
五、总结
优点
- 代码命名规范,可读性很高,符合Google编码规范。
- 代码结构层次清晰,功能分块,设计优雅。
- 每个函数前都有注释,能了解每个函数的功能,全局变量前也有非常详细的注释,能迅速读懂每行代码。
- 生成数学题目的算法运用到了二叉树这个数据结构,非常巧妙。
- 错误处理逻辑严谨,有专门的错误处理函数。
- 使用数据库存储题目和用户信息,非常高效。
缺点
- 连接数据库时没有考虑数据库中存储的题目信息与文件中存储的题目信息不一致这个问题。
- 运行时需要保证系统变量对于
gcc
的配置,在部分电脑中可能会出现无法运行的情况。
标签:node,结对,题目,Val,Level,models,编程,互评,num 来源: https://www.cnblogs.com/redwine/p/16691394.html