小学生最害怕的计算题生成器

是一个标题

211614269 林凯 211601233 张康凌

一、预估与实际

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

二、需求分析

我通过查询教学大纲及研究相关试卷的方式了解到,小学三级数学有如下的几个特点:

  • 特点1
    • 减法的差应该大于0
  • 特点2
    • 除数要不等于0
  • 特点3
    • 除法结果不应该有余数
  • 特点4
    • 减法的差应该大于0
  • 特点5
    • 运算符2-4个
  • 特点6
    • 需要括号

经过分析,我认为,这个程序应当:

  • 要保证减法时的差不为负数
  • 除法时要保证被除数不为0且计算结果没有余数
  • 随机出现合适的括号(由于实在想不到很好的方式实现,出题模块暂时没有此功能,计算的模块支持带括号式子的计算)

三、设计

1. 设计思路


  • 这个程序有两个类

    • MathExam负责生成题目
    • Calculate类专门用来计算表达式的结果
  • 算法的关键是什么?

    • 调度场算法
      • 定义两个栈,一个栈叫做保存运算符记为op,另一个栈保存最终的表达式记为rpn。
      • 数字直接入op栈
      • op栈顶若是(则无条件入栈
      • 运算符要与op栈顶比较,优先级大则入栈,小于或等于则op出栈后再入栈
    • 逆波兰式求值
      • 定义一个栈
      • 从左到右扫描逆波兰式
      • 读到一个数字时就将它压入栈中
      • 读到一个运算符时,就从栈中弹出两个数字,并将该运算符作用于这两个数字,然后将计算结果再压入栈中
      • 逆波兰式读取完毕时,栈中剩下的就是最终结果
    • 生成合适的随机数
      • (int) (min + Math.random() * (max - min + 1)) 可生成min-max范围内的数;

2. 实现方案

  • 准备工作:先在Github上创建仓库,克隆到本地
  • 技术关键点:梳理一下设计思路,可能遇到哪些技术关键点
    • 如何将调度场算法运用到该题中去
    • 随机数的使用,本程序需要大量的使用Math.random()方法
    • 全局静态变量的使用,本程序需要多个静态函数共享数据
    • ArrayList数组的使用,用该数组存储题目及答案的字符串,相比普通数组,该数组可以动态增加空间

四、编码

请说明你如何按照设计思路进行编码,并记录你在开发中遇到的问题,与解决过程

1. 调试日志

  • 在代码的什么位置,代码出现了什么问题,问题会导致什么结果,怎么解决的
    • 在使用调度场算法将题目转换成逆波兰式时出现了问题,因为题目的数字可能是个位也可能是两位,直接通过下标截取字符串的方法明显不合适。最后我决定写一个方法,将题目中的符号及数值按顺序存放至字符串数组中,使用的时候遍历数组取出即可。
    • 在出题时,有可能出现除法有余数的情况,导致题目不符合要求。我的做法是在生成除号时,将前一个被除数取出,同时随机出被除数,若不能整除,则一直循环随机出被除数,最后一定能保证不会有余数。

2. 关键代码

请展示一段程序的关键代码,并解释代码的作用

 //返回符号优先级
	public static int priority(String str) {
		switch (str) {
		case "(":
			return 0;
		case "+":
		case "-":
			return 1;
		case "*":
		case "/":
			return 2;
		default:
			return -1;
		}

	}

	// 转换成逆波兰式
	public static void reversePolishNotation() {

		for (int i = 0; i < slen; i++) {
			//scut字符串数组按顺序存放了题目的数值及符号
			if (!(scut[i].equals("+") || scut[i].equals("-") || scut[i].equals("*") || scut[i].equals("/") || scut[i].equals("(") ||  scut[i].equals(")"))) {
				srpn.push(scut[i]);
			} else {
				if (soperators.isEmpty() || scut[i].equals("(")) {
					soperators.push(scut[i]);
				} else {
					if (priority(scut[i]) > priority(soperators.peek())) {
						soperators.push(scut[i]);
					} else {
						if(scut[i].equals(")")) {
							while (!soperators.peek().equals("(")) {
								srpn.push(soperators.pop());
							}
							soperators.pop();
						}else {
							while ((!soperators.isEmpty()) && (priority(soperators.peek()) >= priority(scut[i]))) {
								srpn.push(soperators.pop());
							}
							soperators.push(scut[i]);
						}
						
					}
				}
			}
		}
		//此时原表达式已扫描完毕,将符号栈里剩余的符号全部存至表达式栈
		while (!soperators.isEmpty()) {
			srpn.push(soperators.pop());
		}
	}
  • 该段代码将原表达式通过调度场算法转换成了逆波兰式

3. 代码规范

请给出本次实验使用的代码规范:

  • 第一条、代码中的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。
  • 第二条、类名使用UpperCamelCase风格
  • 第三条、方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格,必须遵循驼峰形式。
  • 第四条、方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格,必须遵循驼峰形式。
  • 第五条、静态变量(static)前面加上小写s。

4. 结对过程

  • 先互相沟通,对于要求进行分析,提出合适的解决思想
  • 我先设计出Calculate类专门负责计算传入式子的结果,该类主要用到了调度场算法及逆波兰式的计算
  • 张康凌同学则写出了生成三年级题目的基本算法
  • 我则继续在出题算法上进一步修改,使其更符合题目的要求
  • 实现基本功能后则一起进行相应的测试

五、测试

请思考并记录你认为必要的测试点,并记录测试用例与测试结果

测试项目 测试语句 预期结果 测试结果
不输入任何参数 java MathExam4269 输入错误 输入错误
输入一个参数 java MathExam4269 20 输入错误 输入错误
输入二个参数 java MathExam4269 -n 20 输入错误 输入错误
输入4个参数且题数在前 java MathExam4269 -n 20 -grade 2 出20道二年级题目 出20道二年级题目
输入4个参数且年级在前 java MathExam4269 -grade 2 -n 20 出20道二年级题目 出20道二年级题目
输入4个参数且题数过多 java MathExam4269 -grade 2 -n 1000 输入错误 输入错误

六、总结

  • 吸取上次个人作业的教训,开始时要先设计好相应的框架,思路

  • 编程是一件非常需要细心的事情,不仅要实现好功能,后续也要考虑对代码进行一些优化

  • 每次修改程序,都应该进行回滚测试,确保新增功能不会影响原功能的实现,调试程序时也要考虑到尽可能多的情况

  • 对于结对编程

    • 设计时应与队友一起进行,自己和队友都要理解相应的思路,这样无论谁做驾驶员时都能理解代码,避免因为没有沟通充分导致后续编程出现问题

    • 结对编程时双方都要轮流做驾驶员,另一方也需要做好领航者,没有任何一方可以偷懒

    • 结对编程的好处很多,碰到问题时可以一起讨论,观察代码的一方也容易发现编写代码者没发现的错误

posted @ 2018-09-19 02:10  lk12345  阅读(1636)  评论(5编辑  收藏  举报