软件工程(2019)结对编程第二次作业 (小霸王出题器)
题目要求
我们在刚开始上课的时候介绍过一个小学四则运算自动生成程序的例子,请实现它,要求:
能够自动生成四则运算练习题
可以定制题目数量
用户可以选择运算符
用户设置最大数(如十以内、百以内等)
用户选择是否有括号、是否有小数
用户选择输出方式(如输出到文件、打印机等)
最好能提供图形用户界面(根据自己能力选做,以完成上述功能为主)
角色分配
结对伙伴:苗齐
这个项目进行过程中,我们经常交换角色。
我编写了大部分的算式生成程序,苗齐写了乘法部分的质因数分解与随机组合以及GUI窗体。
项目地址
写在前面
这次的需求是要做一个小学算数题生成程序,我们两个讨论这个的时候各种发挥,最后这个项目的工作量大大超出了预期。
设计
设计过程经历了几个阶段:
符号插入?
本来的思路是随机生成一个数字串,然后往里面插运算符与括号。但是看看需求:嗯?包含除法,那如果不支持小数的话,肯定也不能告诉小学生们 8/3 =2
啊。
逆波兰?
那么最好要边生成边有中间结果,嗯,逆波兰式不错,这样随机起来也方便(不用考虑括号插在哪了)。这样只要构造一棵树,然后中序遍历,就可以回到中缀式。而且还能知道结果。很完美!
倒推算式?
队友:“那你的结果怎么控制最小值啊?”
对啊,如果小学生的题是10以内加减法,那结果应该也不会超过10吧...
队友:“我们来从结果拆成一棵二叉树,倒推算式吧!”
我:“好呀好呀!”
这就是噩梦的开始。
树的结构
队友出完馊主意去写界面了,我们来看看这棵树是什么样子的。
诺,大概这样。
这棵树是 2*15+23-17
。
中序遍历就是算式,叶子结点要数,有符号的结点要符号。
加括号
括号也很好办,我们在每个结点上存一个bool变量表示这个算符对应的子式有没有括号。在每个节点生成两个叶子结点的时候,根据规则判断子节点是否需要挂括号,若需要,将这个bool变量设为true。
加括号的规则还挺多的,除考虑算符的优先级,同优先级的算符也有减号/除号后面变号的规则。
但是这样加括号有个特点,就是不会加“无意义”的括号(就是只有对运算顺序有影响的时候才会加括号)。
树形随机
这个,维护一个当前树的叶子的队列,然后每次“发芽”的时候随机取其中的一个 pop 出来,把它的两个儿子 push 进去。
加减乘除
其实比较难办的只有乘法的情况,这部分是队友写的,大致做法是质因数分解,然后随机各个质因子的次数。
具体见队友博客:传送门
各种功能
至此,其实就有个基本的原型了,不过还有很多功能要加:
-
不包含括号
不包含括号,那么就控制算式的生成规则。要子树的优先级大于等于父节点,如果生成同优先级且父节点是减或者除,那么子节点只能是相应的不产生括号的符号。 -
任意选择运算符集
维护可选的运算符集合,选的时候随机一下。 -
最大数字
由于有中间结果,这个随机的时候直接解决 -
包含小数
没啥好的办法,建一棵double的树。 -
GUI以及试卷输出
队友搞的。传送门
运行效果
对队友的评价
苗齐同学的编码能力一如既往的稳定,算法能力就不用说了,合作起来很愉快。就是脑壳有点疼。
总结
这个故事告诉我们,我们做项目不要过早扩大化,过早优化(小学生可以先用个烂一点的试卷),或者就多留点时间,不然脑壳就比较疼。
项目开始前的评估,其实还包括真正的需求(说不定人家没想那么多),很重要。要清楚这个项目大概要花多长时间,然后区分主次地解决各个问题。
先不说了,脑壳疼。