使用java實現四則運算的生成 (羅彬 梁漢烽)

来源:https://www.cnblogs.com/Roo-2196576426/archive/2018/09/29/9727046.html
-Advertisement-
Play Games

本項目Github地址:https://github.com/Rollsom/MyApp 項目簡介: 實現一個自動生成小學四則運算題目的命令行程式。 項目相關要求: 使用 -n 參數控制生成題目的個數 使用 -r 參數控制題目中數值(自然數、真分數和真分數分母)的範圍,例如:Myapp.exe -r ...


 

本項目Github地址:https://github.com/Rollsom/MyApp

項目簡介:

實現一個自動生成小學四則運算題目的命令行程式。

項目相關要求:

 

使用 -n 參數控制生成題目的個數

 

使用 -r 參數控制題目中數值(自然數、真分數和真分數分母)的範圍,例如:Myapp.exe -r 10

將生成10以內(不包括10)的四則運算題目。該參數可以設置為1或其他自然數。該參數必須給定,否則程式報錯並給出幫助信息。

3. 生成的題目中計算過程不能產生負數,也就是說算術表達式中如果存在形如e1 − e2的子表達式,那麼e1 ≥ e2

4. 生成的題目中如果存在形如e1 ÷ e2的子表達式,那麼其結果應是真分數。

5. 每道題目中出現的運算符個數不超過3個。

6. 程式一次運行生成的題目不能重覆,即任何兩道題目不能通過有限次交換+和×左右的算術表達式變換為同一道題目。

生成的題目存入執行程式的當前目錄下的Exercises.txt文件,格式如下: 

1. 四則運算題目1

2. 四則運算題目2

……

其中真分數在輸入輸出時採用如下格式,真分數五分之三表示為3/5,真分數二又八分之三表示為2’3/8。

7. 在生成題目的同時,計算出所有題目的答案,並存入執行程式的當前目錄下的Answers.txt文件,格式如下:

1. 答案1

2. 答案2

8. 程式應能支持一萬道題目的生成。

9. 程式支持對給定的題目文件和答案文件,判定答案中的對錯併進行數量統計,輸入參數如下:

Myapp.exe -e <exercisefile>.txt -a <answerfile>.txt

統計結果輸出到文件Grade.txt,格式如下:

Correct: 5 (1, 3, 5, 7, 9)

Wrong: 5 (2, 4, 6, 8, 10)

解題思路:

  大致思路為:先隨機生成若幹個子表達式(表達式內操作數不超過2個,若操作數為2個則加上括弧),根據數字特征生成合適的操作符,隨後根據子表達式的總值來生成表達式之間的運算符號,期間去除多餘的括弧,並且將小數換成真分數。從而生成一個符合要求的表達式。

  查重則使用二叉樹,在生成子表達式的過程中構建二叉樹,查重就變成了兩個二叉樹是否相等的問題。

  最後輸出文件以及正誤判斷只需要用到文件的輸入輸出流以及簡單的字元串判斷方法即可。

代碼結構:

Expression類:當做數據結構來用,裡面主要設置一些表達式裡面的一些參數方便編程。

Data類:數據的屬性,主要用來處理真分數的轉換,整數及真分數的運算,生成符合輸入輸出的數字表達。

CQ類:生成子表達式及組合表達式,生成結果。

ExpressionArray類:用來處理生成的表達式數組,主要用來查重以及存儲生成的每一個表達式。

Tree類:子表達式附加的類,用來輔助查重。

Saveanswer類:將生成的表達式輸出到文件中,以及統計正誤數量。

關鍵代碼說明:

生成子表達式:

public void CQQ(Expression e,int Range) {//創造表達式
        e.flag1 = true;
    Random r = new Random();
    if(this.CurrentOperateNum==3||this.CurrentOperateNum==0)
      {     
        e.Operate1.CreatNumble(Range);        
         this.CurrentOperateNum += 1;
         e.value = e.Operate1.ExpressionValue;         
         e.Result = e.Operate1;
         this.ExpressionNum += 1;
         e.flag1=true;
         e.Node.value = e.Operate1.ExpressionValue;
         }
    else if(this.CurrentOperateNum==4) return ;
    else {
        e.Operate1.CreatNumble(Range);
            this.ExpressionNum += 1;
            e.flag1 = true;
        if(r.nextInt(2)==1) //生成兩個操作數
        {            
               e.flag = true;                   
               e.Operate2.CreatNumble(Range);                   
           this.CurrentOperateNum += 2;
           switch(r.nextInt(4)) 
           {
           case 0 : e.value = e.Operate1.ExpressionValue + e.Operate2.ExpressionValue; e.Operator = '+';                         
                 break;
           case 1 : while(e.Operate1.ExpressionValue < e.Operate2.ExpressionValue) 
                       {
                       e.Operate1.CreatNumble(Range); 
                       e.Operate2.CreatNumble(Range); 
                       }
                     e.value = e.Operate1.ExpressionValue - e.Operate2.ExpressionValue; e.Operator = '-';                
                 break;
           case 2 : e.value = e.Operate1.ExpressionValue * e.Operate2.ExpressionValue; e.Operator = '*';
                 break;
           case 3 : 
                     e.value = e.Operate1.ExpressionValue / e.Operate2.ExpressionValue; e.Operator = '÷';
                     break;         
           }
           e.Result = e.Result.Carculate(e, e.Operate1, e.Operate2, e.Operator);
           e.Node.e1.value = e.Operate1.ExpressionValue;
           e.Node.e2.value = e.Operate2.ExpressionValue;
           e.Node.value = e.value;
           
            }
            else {                        
                this.CurrentOperateNum += 1; 
                e.value = e.Operate1.ExpressionValue;
                e.Result = e.Operate1;
                e.Node.value = e.Operate1.ExpressionValue;
             }                
             }

 

組建已經生成的表達式:

public String GroupSonExpression(Expression e1,Expression e2,Expression father)
    {
        int Operate;
        Random r = new Random();
        Operate = r.nextInt(4);
        while((e1.value<e2.value&&Operate==1)||(e2.value==0&&Operate==3))
            Operate = r.nextInt(3);
        if(e1.flag1==true&&e2.flag1==true)
        {
            switch(Operate)
            {
            case 0 :     father.Operator = '+';father.value = e1.value + e2.value;
                        if(e1.flag==true)
                            {
                                e1.flag = false;
                                e1.GetExpression();                       
                            }                   
                        if(e2.Operator=='*'||e2.Operator=='÷')
                            {
                            e2.flag = false;
                            e2.GetExpression();
                            }            
                        break;
            case 1 :    father.Operator = '-';father.value = e1.value - e2.value;
                        if(e1.flag==true)
                        {
                            e1.flag = false;                   
                            e1.GetExpression();                    
                        }
                        if(e2.Operator=='*'||e2.Operator=='÷')
                        {
                            e2.flag = false;
                            e2.GetExpression();                    
                        }
                        break;
            case 2 :    father.Operator = '*';father.value = e1.value * e2.value;
                        if(e1.Operator=='*'||e1.Operator=='÷')
                            {e1.flag = false;
                            e1.GetExpression();}
                            break;
            case 3 :father.Operator = '÷';father.value = e1.value / e2.value;
                    if(e1.Operator=='*'||e1.Operator=='÷')
                            {e1.flag = false;
                            e1.GetExpression();}
                    break;        
            }
            father.Result = father.Result.Carculate(father, e1.Result, e2.Result, father.Operator);            
            father.SonExpression = e1.Expression + father.Operator + e2.Expression;
            father.Expression =  "("+ father.SonExpression +")";
            father.flag1 = true;
            father.Node.value = father.value;
            father.Node.e1 = e1.Node;
            father.Node.e2 = e2.Node;
        }    
        else if(e2.flag1==false&&e1.flag1==true)        
            {
            father.value = e1.value;
              father.Operate1 = e1.Operate1;
              father.Operate2 = e1.Operate2;          
              father.Expression = e1.Operate1.Fraction;
              father.Operator = e1.Operator;
              father.Result = e1.Result;
              father.flag = e1.flag;
              father.Result.ExpressionValue = e1.Result.ExpressionValue;
              father.flag1 = true;
              if(e1.Operator==' ')
              father.SonExpression = e1.Expression;
              else 
                  father.SonExpression = e1.Operate1.Fraction+ father.Operator + e1.Operate2.Fraction;              
               father.Node = e1.Node;
            }
            else  father = e2;        
        return father.Expression;
            }

 

 真分數的各種運算:

public Data Carculate(Expression e,Data d1,Data d2,char Operator) {
    Data d = new Data();
    switch(Operator)
    {
    case '+':d.Molecule = d1.Molecule * d2.Deno + d2.Molecule * d1.Deno;
             d.Deno = d1.Deno * d2.Deno;
             d.integer = d1.integer + d2.integer;             
             d.Simplication();
             d.ExpressionValue = (double)d.integer+(double)(d.Molecule)/(double)d.Deno;
             d.CreatFractor();
             e.valueExpression = d.Fraction;
             break;
    case '-':
            d.Molecule = d2.Deno * (d1.integer * d1.Deno+d1.Molecule) - d1.Deno * (d2.integer * d2.Deno + d2.Molecule);
            //d1.Molecule * d2.Deno - d2.Molecule * d1.Deno;
              d.Deno = d1.Deno * d2.Deno;
              d.integer = 0;              
              d.Simplication();
              d.ExpressionValue = (double)d.integer+(double)(d.Molecule)/(double)d.Deno;
              d.CreatFractor();
              e.valueExpression = d.Fraction;
              break;
    case '*':
             d.Molecule = (d1.Molecule+d1.integer * d1.Deno) * (d2.Molecule + d2.integer * d2.Deno);
             d.Deno = d1.Deno * d2.Deno;
             d.integer = 0;
             d.Simplication();
             d.ExpressionValue = (double)d.integer+(double)(d.Molecule)/(double)d.Deno;
             d.CreatFractor();
             e.valueExpression = d.Fraction;
             break;
    case '÷':d.Molecule = (d1.Molecule+d1.integer * d1.Deno) * d2.Deno;
             d.Deno = d1.Deno * (d2.Molecule + d2.integer * d2.Deno);    
             d.integer = 0;
             d.Simplication();
             d.ExpressionValue = (double)d.integer+(double)(d.Molecule)/(double)d.Deno;
             d.CreatFractor();
             e.valueExpression = d.Fraction;
             break;
             default : System.out.println("計算出錯");break;
    }    
    return d;
}

查重:

boolean IFequal(Tree T1,Tree T2) {
          if(T1==null&&T2==null) return true;
          else if(T1==null||T2==null) return false;
     else if(T1.value!=T2.value||T1.Operator!=T2.Operator) 
              return false;
     else  if((IFequal(T1.e1,T2.e1)&&IFequal(T1.e2,T2.e2))||(IFequal(T1.e2,T2.e1)&&IFequal(T1.e1,T2.e2)))
     return true;
     return false;
 }

運行測試舉例:

生成10000條表達式並且操作數範圍為20,輸出到.txt文件上面。

測試比較答案對錯:

 

psp:

 

PSP2.1

Personal Software Process Stages

預估耗時(分鐘)

實際耗時(分鐘)

Planning

計劃

 60

 120

· Estimate

· 估計這個任務需要多少時間

 60

 120

Development

開發

 1800

 2140

· Analysis

· 需求分析 (包括學習新技術)

 60

 60

· Design Spec

· 生成設計文檔

 60

 90

· Design Review

· 設計覆審 (和同事審核設計文檔)

 20

 30

· Coding Standard

· 代碼規範 (為目前的開發制定合適的規範)

 40

 40

· Design

· 具體設計

 120

 180

· Coding

· 具體編碼

 720

 960

· Code Review

· 代碼覆審

 60

 60

· Test

· 測試(自我測試,修改代碼,提交修改)

 720

 720

Reporting

報告

 40

 40

· Test Report

· 測試報告

 15

 15

· Size Measurement

· 計算工作量

 0

 0

· Postmortem & Process Improvement Plan

· 事後總結, 並提出過程改進計劃

 25

 25

合計

 

 1900

 2300

代碼覆蓋率:

執行-n 與 -r 時:

執行-e 與 -a 時:

項目總結:

  本次項目比上一次的項目的難度要高許多,製作時間比較緊張。在這一次編程中,我實現功能需要用到的類比較多,類比較簡單所以多而且繁瑣,相互又有聯繫,所以出bug的時候總是會卡很久。而且這次隨我個人而言也是一次很大的挑戰,我平時沒有學習技術,只有要做項目的時候才去學,是非常痛苦的事情,這痛苦的經歷也告訴了我平時練習的重要性。。最主要的是,這一次是結對編程,兩個人在一起編寫程式,相互提出想法,輕鬆解決小錯誤,有小的問題與失誤常常能夠及時發現,避免了到時候重新觀看代碼耗費大量時間,是一次非常好的體驗。兩人相互督促,效率比較高,雖然沒有一個人打碼那麼自在,但是確實感受到了結對編程的好處。

評價:

  我的隊友梁漢烽在我打碼的時候給了我很多的幫助,他常常坐在我旁邊看我打碼,在旁邊給出他的思路,人也很幽默,沒有頭緒的時候也會說一些騷話活躍氣氛。我從他那裡學到了不少東西,他指導我代碼的規範性,讓我對設計程式時的結構性有了進一步的瞭解,而且經常提醒我犯得一些小錯誤。   

  羅彬進行了對功能的基本架構,並且提供了基本思路,在此過程中我為他提供意見,儘可能的求同存異,改善基本情況,兩個人同時進行編碼可以在編碼過程中看出錯誤,避免BUG的過多產生,導致任務進度的減慢。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 環境 一、websocket協議 1. 先建立連接 wss://broadcastlv.chat.bilibili.com/sub 2. 發送登錄包 { "uid": 0表示未登錄,否則為用戶ID, "roomid": 房間ID, "protover": 1, "platform": "web", ...
  • 下麵的程式會發生崩潰: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 include <stdio.h> include <iostream> using namespace std; int main(void) { int p; int i = ...
  • 單變數:表達式、方程式、函數或者一元多項式等 數據:http://www.presidency.ucsb.edu/data/sourequests.php美國總統歷年在國情咨文中對國會提起的訴求數量 一、獲取數據 本次使用到的數據量並不多,不過還是按照常規思路,通過爬蟲獲取。 得到的數據: 二、繪製 ...
  • n1、下載windows版本的nginx安裝包 nginx官網,我使用的是穩定版的1.8.1 2、下載好的安裝包,找一個路徑進行解壓(註意:不要使用中文路徑);解壓之後nginx就安裝好了,嘻嘻window下安裝特別簡單,比linux簡單多了 3、然後就需要配置tomcat伺服器了,因為要模擬集群的 ...
  • 1. weak_ptr 介紹 std::weak_ptr 是一種智能指針,它對被 std::shared_ptr 管理的對象存在非擁有性("弱")引用。在訪問所引用的對象指針前必須先轉換為 std::shared_ptr。 主要用來表示臨時所有權,當某個對象存在時才需要被訪問。轉換為shared_p ...
  • jQuery runnoob網址: http://www.runoob.com/jquery/jquery-tutorial.html jQuery API手冊: http://www.runoob.com/manual/jquery/ jQuery筆記 筆記來源於: 傳智播客的黑馬程式員視頻筆記.... ...
  • 內容 ​ 網上很多資料都詳細地講解了HashMap底層的實現,但是講到HashMap的併發操作不是線性安全時,往往一筆帶過:在多個線程併發擴容時,會在執行transfer()方法轉移鍵值對時,造成鏈表成環,導致程式在執行get操作時形成死迴圈。 ​ 對於沒有研究過該過程的童鞋,很難費解這句話的含義。 ...
  • 內容 ​ 網上很多資料都詳細地講解了HashMap底層的實現,但是講到HashMap的併發操作不是線性安全時,往往一筆帶過:在多個線程併發擴容時,會在執行transfer()方法轉移鍵值對時,造成鏈表成環,導致程式在執行get操作時形成死迴圈。 ​ 對於沒有研究過該過程的童鞋,很難費解這句話的含義。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...