小學生最害怕的計算題生成器


是一個標題

211614269 林凱 211601233 張康凌

一、預估與實際

PSP2.1 Personal Software Process Stages 預估耗時(分鍾) 實際耗時(分鍾)
Planning 計划
• Estimate • 估計這個任務需要多少時間 10 10
Development 開發
• Analysis • 需求分析 (包括學習新技術) 60 120
• Design Spec • 生成設計文檔 30 30
• Design Review • 設計復審 30 30
• Coding Standard • 代碼規范 (為目前的開發制定合適的規范) 10 10
• Design • 具體設計 60 60
• Coding • 具體編碼 240 400
• Test • 測試(自我測試,修改代碼,提交修改) 30 30
Reporting 報告
• Test Repor • 測試報告 30 30
• Size Measurement • 計算工作量 10 20
• Postmortem & Process Improvement Plan • 事后總結, 並提出過程改進計划 60 60
合計 570 800

二、需求分析

我通過查詢教學大綱及研究相關試卷的方式了解到,小學三級數學有如下的幾個特點:

  • 特點1
    • 減法的差應該大於0
  • 特點2
    • 除數要不等於0
  • 特點3
    • 除法結果不應該有余數
  • 特點4
    • 減法的差應該大於0
  • 特點5
    • 運算符2-4個
  • 特點6
    • 需要括號

經過分析,我認為,這個程序應當:

  • 要保證減法時的差不為負數
  • 除法時要保證被除數不為0且計算結果沒有余數
  • 隨機出現合適的括號(由於實在想不到很好的方式實現,出題模塊暫時沒有此功能,計算的模塊支持帶括號式子的計算)

三、設計

1. 設計思路


  • 這個程序有兩個類

    • MathExam負責生成題目
    • Calculate類專門用來計算表達式的結果
  • 算法的關鍵是什么?

    • 調度場算法
      • 定義兩個棧,一個棧叫做保存運算符記為op,另一個棧保存最終的表達式記為rpn。
      • 數字直接入op棧
      • op棧頂若是(則無條件入棧
      • 運算符要與op棧頂比較,優先級大則入棧,小於或等於則op出棧后再入棧
    • 逆波蘭式求值
      • 定義一個棧
      • 從左到右掃描逆波蘭式
      • 讀到一個數字時就將它壓入棧中
      • 讀到一個運算符時,就從棧中彈出兩個數字,並將該運算符作用於這兩個數字,然后將計算結果再壓入棧中
      • 逆波蘭式讀取完畢時,棧中剩下的就是最終結果
    • 生成合適的隨機數
      • (int) (min + Math.random() * (max - min + 1)) 可生成min-max范圍內的數;

2. 實現方案

  • 准備工作:先在Github上創建倉庫,克隆到本地
  • 技術關鍵點:梳理一下設計思路,可能遇到哪些技術關鍵點
    • 如何將調度場算法運用到該題中去
    • 隨機數的使用,本程序需要大量的使用Math.random()方法
    • 全局靜態變量的使用,本程序需要多個靜態函數共享數據
    • ArrayList數組的使用,用該數組存儲題目及答案的字符串,相比普通數組,該數組可以動態增加空間

四、編碼

請說明你如何按照設計思路進行編碼,並記錄你在開發中遇到的問題,與解決過程

1. 調試日志

  • 在代碼的什么位置,代碼出現了什么問題,問題會導致什么結果,怎么解決的
    • 在使用調度場算法將題目轉換成逆波蘭式時出現了問題,因為題目的數字可能是個位也可能是兩位,直接通過下標截取字符串的方法明顯不合適。最后我決定寫一個方法,將題目中的符號及數值按順序存放至字符串數組中,使用的時候遍歷數組取出即可。
    • 在出題時,有可能出現除法有余數的情況,導致題目不符合要求。我的做法是在生成除號時,將前一個被除數取出,同時隨機出被除數,若不能整除,則一直循環隨機出被除數,最后一定能保證不會有余數。

2. 關鍵代碼

請展示一段程序的關鍵代碼,並解釋代碼的作用

 //返回符號優先級
	public static int priority(String str) {
		switch (str) {
		case "(":
			return 0;
		case "+":
		case "-":
			return 1;
		case "*":
		case "/":
			return 2;
		default:
			return -1;
		}

	}

	// 轉換成逆波蘭式
	public static void reversePolishNotation() {

		for (int i = 0; i < slen; i++) {
			//scut字符串數組按順序存放了題目的數值及符號
			if (!(scut[i].equals("+") || scut[i].equals("-") || scut[i].equals("*") || scut[i].equals("/") || scut[i].equals("(") ||  scut[i].equals(")"))) {
				srpn.push(scut[i]);
			} else {
				if (soperators.isEmpty() || scut[i].equals("(")) {
					soperators.push(scut[i]);
				} else {
					if (priority(scut[i]) > priority(soperators.peek())) {
						soperators.push(scut[i]);
					} else {
						if(scut[i].equals(")")) {
							while (!soperators.peek().equals("(")) {
								srpn.push(soperators.pop());
							}
							soperators.pop();
						}else {
							while ((!soperators.isEmpty()) && (priority(soperators.peek()) >= priority(scut[i]))) {
								srpn.push(soperators.pop());
							}
							soperators.push(scut[i]);
						}
						
					}
				}
			}
		}
		//此時原表達式已掃描完畢,將符號棧里剩余的符號全部存至表達式棧
		while (!soperators.isEmpty()) {
			srpn.push(soperators.pop());
		}
	}
  • 該段代碼將原表達式通過調度場算法轉換成了逆波蘭式

3. 代碼規范

請給出本次實驗使用的代碼規范:

  • 第一條、代碼中的命名嚴禁使用拼音與英文混合的方式,更不允許直接使用中文的方式。
  • 第二條、類名使用UpperCamelCase風格
  • 第三條、方法名、參數名、成員變量、局部變量都統一使用 lowerCamelCase 風格,必須遵循駝峰形式。
  • 第四條、方法名、參數名、成員變量、局部變量都統一使用 lowerCamelCase 風格,必須遵循駝峰形式。
  • 第五條、靜態變量(static)前面加上小寫s。

4. 結對過程

  • 先互相溝通,對於要求進行分析,提出合適的解決思想
  • 我先設計出Calculate類專門負責計算傳入式子的結果,該類主要用到了調度場算法及逆波蘭式的計算
  • 張康凌同學則寫出了生成三年級題目的基本算法
  • 我則繼續在出題算法上進一步修改,使其更符合題目的要求
  • 實現基本功能后則一起進行相應的測試

五、測試

請思考並記錄你認為必要的測試點,並記錄測試用例與測試結果

測試項目 測試語句 預期結果 測試結果
不輸入任何參數 java MathExam4269 輸入錯誤 輸入錯誤
輸入一個參數 java MathExam4269 20 輸入錯誤 輸入錯誤
輸入二個參數 java MathExam4269 -n 20 輸入錯誤 輸入錯誤
輸入4個參數且題數在前 java MathExam4269 -n 20 -grade 2 出20道二年級題目 出20道二年級題目
輸入4個參數且年級在前 java MathExam4269 -grade 2 -n 20 出20道二年級題目 出20道二年級題目
輸入4個參數且題數過多 java MathExam4269 -grade 2 -n 1000 輸入錯誤 輸入錯誤

六、總結

  • 吸取上次個人作業的教訓,開始時要先設計好相應的框架,思路

  • 編程是一件非常需要細心的事情,不僅要實現好功能,后續也要考慮對代碼進行一些優化

  • 每次修改程序,都應該進行回滾測試,確保新增功能不會影響原功能的實現,調試程序時也要考慮到盡可能多的情況

  • 對於結對編程

    • 設計時應與隊友一起進行,自己和隊友都要理解相應的思路,這樣無論誰做駕駛員時都能理解代碼,避免因為沒有溝通充分導致后續編程出現問題

    • 結對編程時雙方都要輪流做駕駛員,另一方也需要做好領航者,沒有任何一方可以偷懶

    • 結對編程的好處很多,碰到問題時可以一起討論,觀察代碼的一方也容易發現編寫代碼者沒發現的錯誤


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM