小学生的随机四则运算
GitHub项目地址:https://github.com/Juneflyfire/jisuan
一、需求分析
- 为了让小学生得到充分锻炼,每个练习题至少要包含2种运算符。同时,由于小学生没有分数与负数的概念,你所出的练习题在运算过程中不得出现负数与非整数,比如不能出 3/5+2=2.6,2-5+10=7等算式。
- 练习题生成好后,将你的学号
- 当程序接收的参数为4时,以下为输出文件示例。
二、功能分析
根据需求分析,可以得出该项目所需的功能:
- 随机产生自定义的n道二位数的四则运算题,运算题的运算符号不少于2。
- 学生可以输入做题的答案
- 将随机产生的题目以及正确答案保存在一个包含自己学号的TXT文件中,
三、设计实现
四、测试运行
如下图所示,当n=50时,循环产生50个算式,学生可输入答案,与result文件中的正确答案对比是否正确。
五、核心代码
/** * 提前将 符号的优先级定义好 */ private static final Map<Character, Integer> basic = new HashMap<Character, Integer>(); static { basic.put('-', 1); basic.put('+', 1); basic.put('*', 2); basic.put('/', 2); basic.put('(', 0); }
/** * 得到计算式的字符串 */ public String getString() { String[] operate = new String[] { "+", "-", "*", "/" }; int[] number = new int[101]; for (int i = 0; i <= 100; i++) number[i] = i; int[] type = new int[3]; for (int i = 0; i < 3; i++) type[i] = i; Random r = new Random(); int t = type[r.nextInt(3)]; if (t == 0){ String str1 = operate[r.nextInt(4)]; String str2 = operate[r.nextInt(4)]; if (str1.equals(str2)) return null; else return number[r.nextInt(101)] + str1 + number[r.nextInt(101)] + str2 + number[r.nextInt(101)]; } else if (t == 1){ String str1 = operate[r.nextInt(4)]; String str2 = operate[r.nextInt(4)]; String str3 = operate[r.nextInt(4)]; if(str1.equals(str2)&&str1.equals(str3)) return null; else return number[r.nextInt(101)] + str1 + number[r.nextInt(101)] + str2 + number[r.nextInt(101)] + str3 + number[r.nextInt(101)]; } else{ String str1 = operate[r.nextInt(4)]; String str2 = operate[r.nextInt(4)]; String str3 = operate[r.nextInt(4)]; String str4 = operate[r.nextInt(4)]; if(str1.equals(str2)&&str1.equals(str3)&&str1.equals(str4)) return null; else return number[r.nextInt(101)] + str1 + number[r.nextInt(101)] + str2 + number[r.nextInt(101)] + str3 + number[r.nextInt(101)] + str4 + number[r.nextInt(101)]; } }
/** * 将 中缀表达式 转化为 后缀表达式 */ public String toSuffix(String infix) { if(infix==null) return null; List<String> queue = new ArrayList<String>();// 定义队列 用于存储 数字 以及最后的 后缀表达式 List<Character> stack = new ArrayList<Character>();// 定义栈 用于存储 运算符,最后stack中会被 弹空 char[] charArr = infix.trim().toCharArray();// 字符数组 用于拆分数字或符号 String standard = "*/+-()"; // 判定标准 将表达式中会出现的运算符写出来 char ch = '&';// 在循环中用来保存 字符数组的当前循环变量的 这里仅仅是初始化一个值 没有意义 int len = 0;// 用于记录字符长度 【例如100*2,则记录的len为3 到时候截取字符串的前三位就是数字 for (int i = 0; i < charArr.length; i++) {// 开始迭代 ch = charArr[i]; // 保存当前迭代变量 if (Character.isDigit(ch)) { // 如果当前变量为 数字 len++; } else if (Character.isLetter(ch)) {// 如果当前变量为 字母 len++; } else if (ch == '.') {// 如果当前变量为 . 会出现在小数里面 len++; } else if (Character.isSpaceChar(ch)) {// 如果当前变量为 空格 支持表达式中有空格出现 if (len > 0) {// 若为空格 代表 一段结束 ,就可以往队列中 存入了 【例如100 * 2 100后面有空格 // 就可以将空格之前的存入队列了】 queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len, i)));// 往队列存入截取的字符串 len = 0;// 长度置空 } continue;// 如果空格出现,则一段结束 跳出本次循环 } else if (standard.indexOf(ch) != -1) { // 如果是上面标准中的 任意一个符号 if (len > 0) { // 长度也有 queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len, i)));// 说明符号之前的可以截取下来做数字 len = 0;// 长度置空 } if (ch == '(') {// 如果是左括号 stack.add(ch);// 将左括号 放入栈中 continue; // 跳出本次循环 继续找下一个位置 } if (!stack.isEmpty()) {// 如果栈不为empty int size = stack.size() - 1;// 获取栈的大小-1 即代表栈最后一个元素的下标 boolean flag = false; while (size >= 0 && ch == ')' && stack.get(size) != '(') { queue.add(String.valueOf(stack.remove(size))); size--; } while (size >= 0 && !flag && basic.get(stack.get(size)) >= basic.get(ch)) { queue.add(String.valueOf(stack.remove(size))); size--; } } if (ch != ')') { stack.add(ch); } else { stack.remove(stack.size() - 1); } } if (i == charArr.length - 1) { if (len > 0) { queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len + 1, i + 1))); } int size = stack.size() - 1; while (size >= 0) { queue.add(String.valueOf(stack.remove(size))); size--; } } } return queue.stream().collect(Collectors.joining(",")); }
六、总结
本次项目花了很长的时间,首先是代码的完成部分,由于自己很久没有使用过Java语言,所以一直都觉得这个代码很难,写不出来。渐渐有同学提交了,deadline将至,便硬着头皮上,先是百度看别人的,然后自己尝试着写,从产生随机数开始,一点一点的积少成多,也突然觉得其实Java也并没有自己想象中的那么难,把它和C语言一样当成一个工具就好了。还有就是刚开始写这个项目的时候,由于自己没有真正的理清头绪,为了实现老师要求的三到五个运算符,在随机产生两个数字的计算题的前提下,投机取巧将加减乘除运算符定死。如下
int a=(int)(Math.random()*100);//随机生成一个1-100的整数 int b=(int)(Math.random()*100);//随机生成一个1-100的整数 int c=(int)(Math.random()*100);//随机生成一个1-100的整数 int d=(int)(Math.random()*4);//随机生成一个1-4的整数,0表示加法,1表示减法,2表示乘法,3表示除法 String temp; switch((int)(Math.random()*3)) { case 0: if(d==0) System.out.println(a+"+"+b+"+"+c+"="); temp=Integer.toString(a)+"+"+Integer.toString(b)+"+"+Integer.toString(c)+"="+Integer.toString(a+b+c); fos.write(temp.getBytes()); if(d==1) System.out.println(a+"+"+b+"-"+c+"="); temp=Integer.toString(a)+"+"+Integer.toString(b)+"-"+Integer.toString(c)+"="+Integer.toString(a+b-c); fos.write(temp.getBytes()); if(d==2) System.out.println(a+"+"+b+"*"+c+"="); temp=Integer.toString(a)+"+"+Integer.toString(b)+"*"+Integer.toString(c)+"="+Integer.toString(a+b*c); fos.write(temp.getBytes()); if(d==3) System.out.println(a+"+"+b+"/"+c+"="); temp=Integer.toString(a)+"+"+Integer.toString(b)+"/"+Integer.toString(c)+"="+Integer.toString(a+b/c); fos.write(temp.getBytes()); int sum = in.nextInt(); count++; break; case 1: if(d==0) System.out.println(a+"-"+b+"+"+c+"="); temp=Integer.toString(a)+"-"+Integer.toString(b)+"+"+Integer.toString(c)+"="+Integer.toString(a-b+c); fos.write(temp.getBytes()); if(d==1) System.out.println(a+"-"+b+"-"+c+"="); temp=Integer.toString(a)+"-"+Integer.toString(b)+"-"+Integer.toString(c)+"="+Integer.toString(a-b-c); fos.write(temp.getBytes()); if(d==2) System.out.println(a+"-"+b+"*"+c+"=");
运行结果表面上符合老师的部分要求,然而在数据流的写入却是乱的。我从中也学会了要提前设计好程序流程,着眼全局。
代码部分还有一个问题就是功能没有完全是实现,代码中虽然涉及到了括号的优先级,并且也用逆波兰式模拟了括号的出栈入栈情况,但是在随机产生运算符的时候依旧不知道该如何处理。这个问题希望可以得到解决。
其次就是将项目在上传GitHub时花费了很长的时间,看视频看了一半就开始在GitHub上建立仓库,开始新建文件,殊不知这是一知半解。在求助他人的时候,知道了可以本地上传,就开始百度各种资料,依旧遇到很多的问题。比如本地git访问到gihub账号等等。好在都解决了,也让我在此学会了静心尽力去主动解决问题,而不是去恐惧它。
总之呢,这个作业很磨人,尤其是对于我这种基础不好的同学,但是当看着这个项目聚沙成塔的时候,也算痛并快乐着。
七、生成PSP
PSP2.1 |
任务内容 |
计划完成需要的时间(min) |
实际完成需要的时间(min) |
Planning |
计划 |
8 |
15 |
· Estimate |
· 估计这个任务需要多少时间,并规划大致工作步骤 |
8 |
15 |
Development |
开发 |
120 |
201 |
·· Analysis |
需求分析 (包括学习新技术) |
6 |
10 |
· Design Spec |
· 生成设计文档 |
5 |
6 |
· Design Review |
· 设计复审 (和同事审核设计文档) |
4 |
6 |
· Coding Standard |
代码规范 (为目前的开发制定合适的规范) |
3 |
25 |
· Design |
具体设计 |
10 |
18 |
· Coding |
具体编码 |
36 |
100 |
· Code Review |
· 代码复审 |
7 |
15 |
· Test |
· 测试(自我测试,修改代码,提交修改) |
13 |
21 |
Reporting |
报告 |
9 |
10 |
·· Test Report |
· 测试报告 |
3 |
5 |
· Size Measurement |
计算工作量 |
2 |
2 |
· Postmortem & Process Improvement Plan |
· 事后总结 ,并提出过程改进计划 |
3 |
3
|