作业具体要求链接:https://edu.cnblogs.com/campus/nenu/SWE2017FALL/homework/997
具体实现功能如下:
功能1:支持出题4个数的四则运算题目,所有题目要求作者有能力正确回答。(+10)
功能2:在功能1的基础上,支持括号。(+15)
功能3:限定题目数量,“精美”打印输出,且要避免重复,最好能输出到.txt文件中。且对输入题目数进行限定,题目数量必须是正整数。(+10)
功能4:支持分数出题和运算。(不完成此题不倒扣分数)
功能5:可把程序改成GUI版/web版/移植为android,ios版。
此次作业完成是以“结对编程”的形式完成,我的伙伴是刘淑霞,她的博客地址为:http://www.cnblogs.com/liusx0303/
这篇博客主要由如下几个方面讲述:
1.每个功能的重点,难点。
2.如何解决重点难点以及收获
3.运行截图
4.结对编程体会。
5.合作过程。
6.版本控制。
一,每个功能的重点,难点
(1)功能一的重点难点
重点难点1:应该选择什么样的输入,操作数和运算符随机产生还是用户自己输入,如果随机产生要如何操作,如果用户自己输入要以什么样的形式输入
重点难点2:如何处理四则运算算式。
重点难点3:将输入的结果与正确结果比较,然后按照要求输出。
(2)功能二的重点难点
功能二的要求:在功能一要求的基础上加上有括号的运算。
重点难点:加上有括号的运算,我们当初分析的时候是用括号匹配的方法,括号优先级最高,优先算括号里面的算式。
(3)功能三的重点难点
功能三的要求:输入题目道数,然后输出四则运算算式以及结果到.txt文件中,注意输出结果右对齐,与算式有一定的距离。
重点难点:将输出放到.txt文件中。
(4) 功能四的重点难点
功能四的要求:支持分数运算,不加括号,输出也是用分数的形式输出,例如1/2 + 2/3 +1+1=3 1/6。
重点难点:支持分数运算,通过通分来进行运算,结果是最简分数(几又几分之几)。
二,合作中如何解决重点难点以及收获
(1)功能一:
因为要支持出题4个数的四则运算题目,针对的用户是初中生,所以题目难度不能太过于简单,也不能过于困难。如果题目随机生成,有太大的随机性,且容易产生重复,用随机数自动生成四个数的四则运算也会比较麻烦,考虑的情况会比较繁多。开始,我们用random生成两个数加减乘除的运算,运行成功,实现支持4个数的四则运算的时候,因为要考虑的情况太过于复杂,写完就400多行代码了,且题目易重复。想想功能一实现就这样艰难。于是想通过自己输入出题,然后让人做的形式实现,且自己出题可以避免重复。题以字符串的出现,然后对字符串进行处理,然后对题进行计算。
对字符串进行处理,判断表达式格式是否正确的代码实现如下:
//检查表达式格式是否正确 public static boolean checkFormat(String str) { // 校验是否以“=”结尾 if ('=' != str.charAt(str.length() - 1)) { return false; } // 校验开头是否为数字或者“(” if (!(isCharNum(str.charAt(0)) || str.charAt(0) == '(')) { return false; } char c; // 校验 for (int i = 1; i < str.length() - 1; i++) { c = str.charAt(i); if (!isCorrectChar(c)) {// 字符不合法 return false; } if (!(isCharNum(c))) { if (c == '-' || c == '+' || c == '*' || c == '/') { if (c == '-' && str.charAt(i - 1) == '(') {// 1*(-2+3)的情况 continue; } if (!(isCharNum(str.charAt(i - 1)) || str.charAt(i - 1) == ')')) {// 若符号前一个不是数字或者“)”时 return false; } } if (c == '.') { if (!isCharNum(str.charAt(i - 1)) || !isCharNum(str.charAt(i + 1))) {// 校验“.”的前后是否位数字 return false; } } } } return isBracketCouple(str);// 校验括号是否配对 }
(2)功能二:
对于在功能一的基础上,实现括号。我们是利用栈实现括号匹配算法。并且使用了map对运算符进行了优先级处理。
符号的优先级处理代码如下:
public static final Map<Character, Integer> symLvMap = new HashMap<Character, Integer>();// 符号优先级map static { symLvMap.put('=', 0); symLvMap.put('-', 1); symLvMap.put('+', 1); symLvMap.put('*', 2); symLvMap.put('/', 2); symLvMap.put('(', 3); symLvMap.put(')', 1); }
括号匹配的代码如下:
//校验括号是否配对 public static boolean isBracketCouple(String str) { LinkedList<Character> stack = new LinkedList<Character>(); for (char c : str.toCharArray()) { if (c == '(') { stack.add(c); } else if (c == ')') { if (stack.isEmpty()) { return false; } stack.removeLast(); } } if (stack.isEmpty()) { return true; } else { return false; } }
(3)功能三:
1.对于输入题目道数是正整数的判断,不能是英文(test),负数(-100),浮点数(3.5)。开始是定义了一个int型的变量,然后对变量进行正整数判断,把负整数去掉。
但是当输入英文,负数和浮点数的时候,运行的时候报错了。后来采用字符串的格式进行输入,然后对字符串的进行在数值范围的判断。
判断输入题目道数是正整数的代码如下:
//判断输入的题目数是否为正整数 public boolean judgeInput(String str) { boolean flag=true; for(int j=0;j<str.length();j++) { if(!(str.charAt(j)>=48&&str.charAt(j)<=57)) { System.out.println("题目数量必须是 正整数。"); flag=true; break; } else { flag=false; } } return flag; }
2.将题目和答案输出到.txt文件中
实现代码如下:
//将表达式写入文件answer.txt try { if (!file.exists()) { file.createNewFile(); } FileWriter writer = new FileWriter(file,true); if(true) { results = System.getProperty("line.separator")+results; } writer.write(results); writer.flush(); writer.close(); } catch (IOException ex) { ex.printStackTrace(); }
(4)功能四:
方法是先求出两个分数分母的最小公倍数,通分后,再对两个分子的加减乘除,最后约简结果分数的分子和分母,即用分子分母的最大公约数分别除分子和分母。再按顺序输入分子和分母,在控制台上输出其运算结果。
求最大公约数的代码如下:
static int gcd(int m,int n)
{ int t,r;//辗转相除法 if(m < n) { t = m; m = n; n = t; } while(n != 0) { r = m%n; m = n; n = r; } return m; }
求最小公倍数代码如下:
static int lcm(int m,int n)
{ int i = gcd( m,n); int j = (m/i)*(n/i)*i; return j; }
收获:
1.在制定代码规范的时候,因为我们都有自己的习惯,所以在制定规则时讨论了较长时间,但是彼此为对方考虑,都各自让步,最终制定了两个人都能接受的代码风格规范。这告诉我们,要多为对方考虑一点,这样才能使合作更愉快,后面实现的过程中也证明了这一点。
2.在考虑实现出题的时候,我和霞都不约而同的用随机数生成出题。觉得可简单了,认为一两个小时就能完成功能一,开始实现起来两个数的加减乘除很快就完成了,然后按照老师要求要完成四个数的加减乘除,实现起来情况就很复杂了,我们完成一个demo的时候就差不多500行代码了,花费了3个多小时,并且有出题重复的情况。后来就一起讨论用自己出题的方式解决,可以避免重复,并且可以控制难度。实现的过程,我们让结果返回double,因为除法肯定会有小数的出现。在一起讨论实现的过程中,知道了不要把一个问题看得太简单,不然容易眼高手低,要明白需求,再开始做事。
3.在对输入题目以字符串的形式写表达式时,要对输入的表达式做各种判断,不然表达式会出错,操作数是不是数字,操作数是不是“+,-,*,/”,最后是不是以等号结尾。一个人总是会疏忽很多小细节,幸运的是,我和霞结对编程,总能考虑到对方疏忽的一些小问题。
4.在结对编程的过程中,一个人在编,另外一个人在旁边盯着,总是能够及时提醒对方触犯的代码规范和犯的语法错误,相互批评,指导,和交流,比一个人编程好玩多了,编程速度虽然没有一个人快,但是两个人编程的质量更高,错误更少。
5.功能3将结果输出到.txt文件中,运行输入表达式的时候,打开.txt文件一看结果都在,以为自己成功了,但是可开心了,然后霞察觉文件的表达式很多,且有重复,我们恍然大悟,知道自己原始数据没有清空,然后两个人寻找解决对策,后来决定在输入题目语句后面将.txt赋空值,两个人一起发现和解决问题的过程真是很nice。
三,运行截图
功能1,2截图
功能3截图:
四,结对编程体会
结对编程之前,我并没有发现结对编程的好处,但在共同完成作业的时候,切身感受到结对编程的好处。两人合作的过程,是一段“美好且痛苦又幸福”的体验。
在四个功能的实现过程中,我们遇见了很多没有想到的困难。在遇见一个难点的时候,或者运行时出错的时候,两个人一起想办法解决,两个人虽然都有不一样的想法,但是都是为了解决同一个问题,当谁的办法能够解决问题的时候,我们都特别开心。完成作业的同时,我获得了知识,也从对方的身上学到了很多,学习能力和思维方式都得到了进步,发现结对编程会使两个人加在一起,会达到1+1>2的效果。
五,合作过程
我们结对编程是在软件所220完成,附上我们两人结对编程的照片。
六,版本控制
git地址:https://coding.net/u/huyr000/p/FourArithmetic/git