一、需求分析
- 根据用户的需求,生成不同难度的题目。包括:题目生成数量,取值范围和运算符数量
- 题目包含四则运算和括号,其中操作数数包括自然数、真分数,结果要用分数表示。
- 每次同时生成的题目不能重复。
- 生成题目和大难的文件。
- 统计错题数量。
二、功能设计
基本功能:根据用户输入生成运算式的条件,生成相应数量要求的题目,并给出正确答案。
扩展功能:对生成的题目进行判重。
高级功能:设置积分榜,可以进行实时双人甚至多人pk,限时答题等等。。。
三、设计实现
一共有七个类,主要实现就是生成表达式,计算表达式和最后的输出判题。判重我没有实施,因为感觉用处不是很大,而且实现起来稍显复杂,即使题目相同也可以锻炼用户的计算能力。此次暂时没有判重,之后再跟进。
- Calculate类:用于计算后缀表达式。
- Control类:程序的起点控制。
- Fraction类:控制操作数,包括整数和分数。
- Question类:按要求随机生成题目
- Showgrade类:生成grade文件,展示相关内容
- Stack类:进行栈的基本操作
- ToRPN: 将中缀表达式变为后缀表达式
四、代码说明
1.生成表达式:主要是括号的处理,想到了根据运算符的数量来增加括号,首先生成两个数字和一个运算符,随机判断是否加括号,之后在生成一个运算符和一个数字,将之前的表达式作为一个操作数,继续随机判断是否加括号,直到最后一个操作符,不加括号,避免首尾出现括号的情况。
1 public ArrayList<Object> createQuestion() { //随机生成表达式 2 ArrayList<Object> arr_q = new ArrayList<Object>(); 3 Random rand = new Random(); 4 Fraction num1; 5 Fraction num2; 6 String oper; 7 int bracket; //判断是否要括号 8 for (int i = 0; i < o_num; i++) { //根据操作符数量 9 num1 = createNum(); 10 num2 = createNum(); 11 oper = createOperator(); 12 13 if (oper == "÷" && num2.toString() == "0") { //除法 除数不能为0 14 num2.setNumerator(rand.nextInt(maxvalue - 1) + 1); 15 } 16 17 if (i == o_num - 1) { //若是最后一个操作符时不加括号,避免首尾括号 18 bracket = 0; 19 } else { 20 bracket = rand.nextInt(2); //括号是在将所有的内容都加上括号,随机生成 21 } 22 if (i == 0) { //首先生成两个操作数 23 if (bracket == 0) { 24 arr_q.add(num1); 25 arr_q.add(oper); 26 arr_q.add(num2); 27 } else { //之后在原基础上只需要再多一个操作数 28 arr_q.add("("); 29 arr_q.add(num1); 30 arr_q.add(oper); 31 arr_q.add(num2); 32 arr_q.add(")"); 33 } 34 } else { 35 if (bracket == 0) { 36 arr_q.add(oper); 37 arr_q.add(num2); 38 } else { 39 arr_q.add(0, "("); //括号要加到首位 40 arr_q.add(oper); 41 arr_q.add(num2); 42 arr_q.add(")"); 43 } 44 } 45 } 46 return arr_q; 47 }
2.表达式的计算:将中缀转换为后缀表达式,在进行计算。主要是把所有的数都看成分数,结果也为分数,所以写一个分数的四则运算配合栈即可
1 public ArrayList<Object> GetAnswer(ArrayList<Object> rpn) { 2 ArrayList<Object> answer = new ArrayList<Object>(); 3 Stack sk = new Stack(); //初始化一个栈 4 Object data; 5 Fraction num1, num2; //操作数 6 Fraction sk_temp; 7 for (int i = 0; i < rpn.size(); i++) { 8 data = rpn.get(i); 9 if (isOperator(data.toString())) { //是否为操作符 10 num2 = (Fraction) sk.pop(); 11 num1 = (Fraction) sk.pop(); 12 sk_temp = count(data.toString(), num1, num2); 13 sk.push(sk_temp); 14 } else 15 sk.push(data); 16 } 17 18 Fraction result = (Fraction) sk.pop(); 19 answer.add(result); 20 return answer; 21 }
五、测试运行
1.程序开始运行:
2.输入要生成表达式的数量:
3.输入操作数的范围:
4.输入操作符数量
5.生成的题目和答案:
6.我的答案:
7.输入1判题:
六、PSP
PSP2.1 | Personal Software Process Stages | Time Senior Student | Time | |
Planning | 计划 | 10 | 7 | |
· Estimate | 估计这个任务需要多少时间 | 10 | 8 | |
Development | 开发 | 600 | 450 | |
· Analysis | 需求分析 (包括学习新技术) | 10 | 8 | |
· Design Spec | 生成设计文档 | 10 | 10 | |
· Design Review | 设计复审 | 20 | 15 | |
· Coding Standard | 代码规范 | 5 | 7 | |
· Design | 具体设计 | 10 | 12 | |
· Coding | 具体编码 | 300 | 400 | |
· Code Review | 代码复审 | 20 | 15 | |
· Test | 测试(自我测试,修改代码,提交修改) | 15 | 30 | |
Reporting | 报告 | 15 | 12 | |
· | 测试报告 | 12 | 10 | |
· | 计算工作量 | 4 | 3 | |
· | 并提出过程改进计划 | 10 | 5 |
七、个人小结
面向对象的第一次作业,同时也是第一次写博客,感觉有点拖沓,写的也不是特别规范,功能也并没有完全实现,之后还要继续进行完善,同时这个题目也比较老,相对思路网上的也比较多,对于后缀表达式的生成都是直接拿来用的,判重也没有什么好的思路,就只能使用二叉树,实现还需要进一步完成。
八、附录
此次实验参考代码: