20165214 結隊編程項目-四則運算(第二週)

20165214 第一次結隊編程項目——四則運算第二週

需求分析

本週的結隊編程想要實現一個四則運算系統,它能夠自動生成n個計算題(本週不包括分數),其中n由咱們輸入。每輸出一道題目,運行程序的人須要輸入相應的答案,直到最後一道題作完。最後,統計正確率。而後,在這個基礎上能夠進行相應的功能擴展,好比語言支持等。html

設計思路

我須要在上週的基礎上對程序進行補充。我以爲這個程序關鍵就分紅兩大部分,第一部分是題目的隨機生成,第二部分是算式的運算。其餘的各類擴展在這兩個步驟完成後再來添加便可。
因而咱們開始先着手於隨機生成,而後着手算式運算,接着把他們拼在一塊兒,而後再進行各類擴展項目的補充。這是咱們設計的總思路。
隨機生成題目時,咱們的想法是,利用隨機數random,根據隨機數生成的數來對應符號與數字,從而造成算式。
運算算式時,咱們參婁老師的博客2016-2017-2 《Java 程序設計》課堂實踐項目——數據結構應用中的棧的思想來解決,真分數的運算參考課本中第四章的例子22。git

本週達成:

①可以隨機生成n道題目,n由咱們輸入,最大長度可直接在程序裏面修改;
②支持真分數運算,支持多運算符;
③可以計算正確率而且按照百分比形式輸出,取到小數點後一位。
④支持簡體中文、繁體中文、英語;
⑤可以選擇參與運算的數字的最大值;
⑥可以查重到級別0(看兩個問題序列是否相等,因爲有的生產的算式很長,不知道怎麼查重比較好);
⑦將生成的算式都寫入文檔中。正則表達式

關鍵代碼解釋

因爲生成隨機算式的代碼是我我的的一些想法,,因此可能會比較很差理解,因而特別提出編程

File file=new File("Question.txt");
    GetNumber GN = new GetNumber();
    GetOperation GO = new GetOperation();
    GetBracket GB = new GetBracket();
    Random random = new Random();
    PraticeSystem ps=new PraticeSystem();
    int language;
    Scanner scanner=new Scanner(System.in);
    int range;
    GetQuestion(int language){
        switch (language) {
            case 0:
                System.out.println("選擇運算數最大爲:");
                range=scanner.nextInt();//得到四則運算中數字的上限。
                break;
            case 1:
                System.out.println("Choose The maximum number of operands is");
                range=scanner.nextInt();//得到四則運算中數字的上限。
                break;
            case 2:
                System.out.println("選擇運算數最大為");
                range=scanner.nextInt();//得到四則運算中數字的上限。
                break;
        }
    }
    public String get(){
        int flag=0,flag2=0;
        String Question="";
        for (int j = 0; j < (random.nextInt(7) + 2) * 2 - 1; j++) {  //這樣可以保證長度在必定範圍內隨機,而且長度>=3
            if (j % 2 == 0) {
                int choose=random.nextInt(2);//括號和整數只能在奇數位,除非是括號內的整數才能在偶數位
                if(choose==0){                          //這裏使得生成括號和整數都是隨機的
                    Question = Question + GN.A(range);  //生成整數鏈接在問題的後面
                }
                else{
                    if(flag==0){  //這裏flag做爲標記,由於括號要按順序來,一旦產生左括號,後面在產生括號時必定要產生右括號。
                        Question = Question + GB.A(flag); //左括號的右邊必定緊跟數字
                        Question = Question + GN.A(range);
                        flag=1; //以後再產生括號就產生右括號
                    }
                    else if(flag==1){
                        Question = Question + GN.A(range);//右括號的左邊必定緊跟數字
                        Question = Question + GB.A(flag);
                        flag=0;
                    }
                }
            }
            else if (j % 2 == 1){
                char c=GO.A(flag2);
                Question = Question + c;
                if(c=='/'){  //這裏是由於不產生歧義,由於在數學表達式中,若是有a/b/c,那麼到底是a除以b/c仍是a/b除以c?
                    //而÷不會產生這個問題。
                    flag2=1;
                }
                else{
                    flag2=0;
                }
            }
        }
        int len = Question.length();
        char a = Question.charAt(len - 1);
        if (a == '+' || a == '-' || a == '*'|| a == '/'|| a == '÷') { //若是最後一個字符是運算符,那麼捨棄這個運算符。
            Question = Question.substring(0, len - 1);
        }
        len = Question.length();
        a = Question.charAt(len - 1);
        if (flag==1) {
            Question = Question+')'; //若是到最後都沒有產生右括號,而在以前已經產生了左括號,那麼要補上右括號
            flag=0;
        }
        len = Question.length();
        a = Question.charAt(len - 1);
        char b=Question.charAt(0);
        int count=0;
        for(int h=0;h<len;h++){
            char c=Question.charAt(h);//若是一個算式只有一個左括號和一個右括號且這兩個括號分別在算式的兩邊,則捨棄。
            if(c=='('||c==')'){
                count++;
            }
        }
        if(count==2){
            if(a==')'&&b=='('){
                Question = Question.substring(1, len - 1);
            }
        }
        Question = Question.replaceAll("\\([0-9]+\\)",Integer.toString(random.nextInt(10)+1));
        //利用正則表達式替換在字符串中像(1)這樣的狀況。

        try{
            FileWriter tofile=new FileWriter(file,true);
            BufferedWriter out= new BufferedWriter(tofile);
            out.write(Question);
            out.newLine();
            out.close();
        }
        catch (IOException e){}
        return  Question;

真分數(題目生成/題目運算判題)

運行截圖:
數據結構

碼雲連接

其中關鍵代碼的解釋咱們註釋在代碼中,碼雲裏有體現~dom

JUnit測試

運算的測試:
學習

後綴表達式的測試:
測試

UML圖

PSP

PSP2.1 Personal Software Process Stages 預估耗時(分鐘) 實際耗時(分鐘)
Planning 計劃 120 100
· Estimate · 估計這個任務須要多少時間 600 580
Development 開發 60 60
· Analysis · 需求分析 (包括學習新技術) 5 5
· Design Spec · 生成設計文檔 30 30
· Design Review · 設計複審 (和同事審覈設計文檔) 30 40
· Coding Standard · 代碼規範 (爲目前的開發制定合適的規範) 30 60
· Design · 具體設計 30 35
· Coding · 具體編碼 120 120
· Code Review · 代碼複審 10 30
· Test · 測試(自我測試,修改代碼,提交修改) 120 100
Reporting 報告 30 40
· Test Report · 測試報告 10 5
· Size Measurement · 計算工做量 20 10
· Postmortem & Process Improvement Plan · 過後總結, 並提出過程改進計劃 20 10
合計 1235 1145

遇到的困難與解決方法

在編程時遇到的一些關於類的方法的問題我都用API解決了,這裏總結一下其餘的問題~編碼

  • 問題一:在隨機生成題目時,會出現單個數字字符可是有括號的現象,如"(1)",這時候我想用正則表達式,使用String類的repalceAll()方法來覆蓋這種狀況。可是,我發現要用正則表達式來匹配"([0-9]+)"總是失敗,程序直接把引號裏面的字符串做爲匹配的對象,而沒有發揮[]和+的做用。
  • 問題一解決方案:在不斷地摸索之下,我突然想到,會不會是由於在正則表達式內使用括號須要用轉義符號來表示呢?因而我嘗試着在括號的前面加上了\,如圖:

而後發現成功了。設計

  • 問題二:在測試運算的時候,若是有兩個等級相等的操做符連着使用的時候,會先算左邊的再算右邊的。這是不符合咱們平常生活中的計算的。
  • 問題二解決方案:仔細檢查了代碼事後發現是在壓棧這一步驟中,對運算符的優先級比較出現了錯誤。遇到運算符時,當比棧頂的運算符優先級小時,壓棧。我寫成了小於等於,出現了這個問題。

點評夥伴

本週的合做是基於上週的基礎上的。隨着合做的次數增長,我和隊友的配合也愈來愈好了,所以結隊編程的效率有了很多提高,關鍵的一點是如今兩我的若是意見上有什麼不統一也比較勇於發表出來,這樣頗有利於咱們的思考。
此次個人隊友表現也很好~能和我共同窗習一塊兒進步~但願從此可以一直合做下去。

結隊編程照片:

相關文章
相關標籤/搜索