第四周-四则运算试题生成

作业具体要求链接: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

 

 

 

 

posted @ 2017-10-10 21:49  huyr000  阅读(248)  评论(0编辑  收藏  举报