2019软件工程结对项目-1120172176

1. 项目成员及Github项目地址

项目成员 博客地址 github地址
陆俊奇 https://blog.****.net/SaltyFishLu/article/details/104034857 https://github.com/SaltyFishL/AutoCal
吴大伟 https://me.****.net/qq_40026187 https://github.com/AmnesiaWu/AutoCal

2.预计时间表格

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

3. 解题思路描述

3.1 项目要求

3.1.1 第一阶段

  • 写一个能自动生成小学四则运算题目的命令行“软件”
  • 用-i num实现一次性生成的题目个数
  • 实现对一个最多10个运算符表达式的求值
  • 支持真分数的四则运算
  • 实现判定对错,并最后给出总共对/错数量。

3.1.2 第二阶段

  • 支持乘方运算,命令行参数-m 1为^表示乘方,命令行参数-m 2为**表示乘方。

3.1.3 第三阶段

  • 把程序编程一个Windows上的电脑图形界面程序
  • 增加倒计时功能,每道题必须要20s内完成,否则得0分并开始下一题
  • 增加历史记录功能,把用户做题的成绩记录下来并可以展现历史记录

3.2 思考过程

题目主要有几个难点:

  • 生成不同的表达式
  • 求解表达式
  • 命令行参数的设置
  • 图形界面,倒计时和历史记录

3.2.1 生成表达式

需要生成随机数,随机运算符,随机括号,还要保证表达式的正确性和唯一性。

生成表达式的时候,感觉还是中缀表达式最直观,最简单。而且不管怎样,最后呈现在用户面前的肯定也要是中缀表达式。当然,为了便于计算表达式,我们制定了了以下生成表达式时的规则:

  1. 一个表达式中最多只有一个乘方运算
  2. 除号和幂运算后不生成左括号,防止括号内的值为0
  3. 乘方幂的范围为1,2,3
  4. 生成左括号的概率为1/5
  5. 在有左括号的情况下,生成右括号的概率为1/3,且配对的右括号和左括号之间至少隔一个运算符

为了消除括号,也为了求解表达式方便,程序首先将中缀表达式转换成了后缀表达式。

最后就是要为表达式去重,所采用的数据结构是二叉树。每一个算式对应一个二叉树,所有的叶子节点为数值,所有的非叶节点为符号。有限次交换加号和乘号左右的算术表达式即所有二叉树的+和根节点的左右子节点任意交换次数不能得到相同的二叉树结构。

3.2.2 求解表达式

从二叉树底向上求解,体现在代码中就是从根节点递归求解。

3.2.3 图形界面,倒计时,历史记录

图形界面最终用的是tkinter库。倒计时和历史记录未实现。

4. 设计实现过程

4.1 类模块说明

4.1.1 Num类

不管用户选择的是什么模式,我们都用Num类来存放数字。因为即使是整数,也可以用分母为1的分数来表示。

  • int numerator //分子
  • int denominator //分母
  • int sign //符号,正数为1,负数为-1
  • int gcd //分子分母的最大公约数,在化简的时候可以用到

方法:

  • +, -, *, /, **, ==, <, str()运算符的重载
  • __gcd() //求解分子分母的最大公因数
  • __reduction() //化简操作,保证分子分母均为正数,符号由sign来定

4.1.2 ExpressionBuilder类

属性:

  • int[] exp_elements_infix //中缀表达式数组,每个符号数字都对应其中一项
  • int[] exp_elements_suffix //后缀表达式数组,去除了括号
  • BinaryTree tree //二叉树形式
  • Num ans //答案

方法:

  • __rand_op_num() //随机出1到10的随机数个数
  • __rand_op() //随机出一个运算符
  • __rand_num() //随机出一个0到100的数字
  • __rand_pow_num() //随机出一个1到3的数字作为幂
  • build_exp_infix() //生成中缀表达式
  • infix_to_sufix() //将中缀表达式转成后缀表达式
  • suffix_to_tree() //将后缀表达式转成树
  • get_ans() //求解表达式
  • build() //留给外部调用的函数,依次调用上述提到的函数

4.1.3 BinaryTree类

内部类:Node
python里没有内部类的概念,这里仅是这么叫而已。二叉树的节点,type代表节点是数字还是字符(是否为叶节点),如果是非叶节点,op为操作数;如果是叶节点,num为数字,left表示左孩子,right表示右孩子。

属性:

  • root //表达式树的根节点
  • op_num //表达式中运算符的个数

方法:

  • adjust_tree() //在计算完之后对数进行调整,以便后生成的表达式树预期对比看是否相同
  • is_same_tree() //判断两颗表达式树是否相同

4.1.4 Const

专门存放常数的类,增强代码的可读性。

4.1.5 Stack

python没有现成的stack,写了一个简易版的,基本功能都有。

4.1.6 Main

解析输入参数,调用其他类,实现与用户的交互

4.2 程序执行流程图

Created with Raphaël 2.2.0开始输入生成要求随机生成运算式是否无重复求解存储运算式和答案选取题目并显示判断答案输出结果并记分数结束yesno

5. 单元测试

  • 单元测试用例设计如下
    1.输入测试
    主要测试程序的合法输入以及不合法输入情况。
编号 输入格式 预期输出
1 简单模式 + max_num 整数运算式
2 中等模式 + max_num 分数、整数运算式
3 困难模式 + max_num 分数、整数乘方运算式

2.输入测试
检测四则运算器中每一种算符的运算正确性

编号 操作数1 操作数2 运算符 预测结果
1 2 1/2 + 5/2
2 2 1/2 - 3/2
3 2 3/2 * 3
4 2 1/2 / 4
5 3 3 ^ 27
6 3 0 ^ 1
7 1/2 1 ^ 1/2

3.题目查重测试

编号 算式1 算式2 预测结果
1 2+3+4 4+(2+3) 重复
2 1+2+3 3+2+1 不重复
3 2*3 3*2 重复
4 (1 + 2) * 3 3* (1 + 2) 不重复
5 (1+2)*(3+4) (3+4)*(1+2) 不重复
6 (2-1)/(5-3) (5-3)/(2-1) 不重复
7 (3+6)/(5-3) (6+3)/(5-3) 重复
8 (1/2+2/3)+3/4 1/2+(2/3+3/4) 重复
9 (1/2+2/3)* 3/4 3/4 *(1/2+2/3) 重复

6.性能分析

2019软件工程结对项目-1120172176
由分析报告可见,该项目的Gui.py里的main函数占用时间最多。build函数是生成运算表达式的函数,可从图看出调用了1000次(即生成了1000个算式),时间花了总时间的2.1%,可见主要时间花在与用户的交互上

7.程序扩展

我们用python做了个简单图形界面
主界面如下:
2019软件工程结对项目-1120172176
输入格式错误:
2019软件工程结对项目-1120172176
开始答题:
2019软件工程结对项目-1120172176
回答错误:
2019软件工程结对项目-1120172176
2019软件工程结对项目-1120172176
退出并显示分数界面:
2019软件工程结对项目-1120172176
点击确定后程序结束

8.PSP表格

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

9.总结

感觉部分需求有点挺没必要的,比如生成的表达式不重复。毕竟之前的数字是随机的,符号是随机的,括号是随机的,符号的数目也是随机的,这所有的随机下来,重复的可能性就非常非常低了。如果是真实的开发中,我觉得耗费大量的时间和精力在这个不影响结果正确性且概率极低的东西上是没有必要的,也不符合软件工程的目标。其他感觉还好,毕竟花的时间也不多,做的效果也基本满足需求了。