软工2017第四周作业--结对编程之四则运算

         作业要求:https://edu.cnblogs.com/campus/nenu/SWE2017FALL/homework/997

         这次和我结对的小伙伴时胡佑蓉同学,以下她的名字简称为H,H的博客地址是:https://home.cnblogs.com/u/huyourongmonkey

         这篇博客主要写以下几点:

           1、功能的重点难点

            2、如何解决重点难点以及收获

            3、运行截图

            4、结对编程环境

            5、较大收获的五大事件

            6、结对编程体会

            7、版本控制

一、功能的重点难点

      结对编程第一步我和H首先讨论了各种功能的技术难点:

    (1)功能一的重点难点

           功能一的要求:四个操作数做混合运算加减乘除,没有括号功能,首先输入式子,然后等待输入一个结果,判断输入的结果是不是正确答案,如果答错了,则显示“再想想吧,答案似乎是?喔!(?是算式的正确答案)”,答对了则显示“答对啦,你真是个天才!”,所有的题目答完之后显示“你一共答对n道题,共20道题。(一共20道题,n是答对的题目道数)”

           重点难点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;  
}  

三、运行截图

功能一、二运行截图,如下

    

  

功能三运行在answer.txt文件查看结果,如图:

四、结对编程环境

         地点:软件所220

         电脑:Windows8.1
         编程软件:eclipse Luna
         java单元测试工具:JUni4

工作照片:

五、收获最多的五大事件

1、在看到要求一的时候,H和我首先想到的是用随机操作数和随机运算符对着二十道题目进行生成,觉得可简单了,认为一个小时能写完,结果到了输出要求一的结果的时候卡了好久,然后转换字符串,判断等号获得结果,代码如下:

String expre;
        
        int right=0;
       //String result="";
        for (int i = 0; i < 3; i++)
        {
            expre=Generate();
            int k=0;
            for(int j=0;j<expre.length();j++)
            {
                
                if(expre.charAt(j)!=61)
                {   
                   System.out.print(expre.charAt(j));
                          
                }
                else
                {   
                    k=j+1;
                    System.out.print("=");
                    break;
                        
                }
            }
             System.out.println("");
             //System.out.println(k);
             System.out.print("?");
            @SuppressWarnings("resource")
                Scanner sc=new Scanner(System.in);
                double results=sc.nextDouble();
                String a=expre.substring(k);
                double result=Double.valueOf(a);
                if(Math.abs(result-results)<0.0001)
                {
                     right++;
                     System.out.println("答对啦,你真是个天才!");
                }
                else
                     System.out.println("再想想吧,答案似乎是"+result+"喔!");
             
                    
                    
         }
        System.out.println("你一共答对"+right+"道题,共3道题。");

         这段代码是随机生成的操作数和运算符然后产生的输出结果,随机生成的数只能是double数,不能输入带小数点的数,不符合输入表达式的要求,所以我们两个换了一种方式写输入,我们两废了好大的劲写完,然后全部推翻重来,没有提前考虑到实际结果与预期结果符不符合。

2、用输入字符串的方式写入表达式,要求一是不用输入括号,然后就是对输入的表达式做各种判断,操作数是不是数字,运算符是不是“+”、“-”、“*”、“/”,幸运的是我和H结对编程,两个人都会考虑到对方疏忽的问题。

3、要求二是支持括号,首先想到的是括号匹配,但是括号和运算符还有优先级的问题,然后我们用了map工具和栈,解决了这个问题,两个人查阅资料,两个人想解决办法,解决问题的速度比一个人快多了。

4、结对编程,H和我两个人互相检查各自的语法错误,互相指导和交流,比一个人冥思苦想的时候有趣多了,编程速度相对我一个人来说快了不少,写出来的代码质量更高了。

5、要求三的功能是将输入的表达式以及输出的结果打印到.txt文件中,运行输入表达式的时候,打开txt文件一看表达式及结果在文件里放着呢,然后一开心就多输入了几次,然后再打开文件一看,怎么那么多表达式,原始数据都没有清空,然后两个人就开始冥思苦想了,后来决定在输入题目个数语句后面将.txt文件赋空值。两个人发现问题--->解决问题的过程真的很愉快。

六、结对编程体会

1、刚开始听到结对编程要求是一电脑一显示屏一鼠标的时候,我都乐了,我觉得会是很好玩的一件事,结果真正编的时候有点不好意思,后来慢慢习惯了,学会互相体谅,考虑对方的想法。

2、互怼的时候也是挺有趣的,H和我互相讲明白某个争论的时候恍然大悟,有几次我和H交流的都想放弃交谈了(各自都有脑子短路的时候),结对编程真的让我变得更有耐心和小伙伴交流了,互怼才能进步。

七、四则运算代码地址,:https://git.coding.net/liusx0303/FourArithmetic.git

原文地址:https://www.cnblogs.com/liusx0303/p/7636140.html