GitHub項目地址:https://github.com/qq1040673290/untitled2/blob/master/myapp.py
1.功能要求
題目:實現一個自動生成小學四則運算題目的命令行程序
- 使用 -n 參數控制生成題目的個數
- 使用 -r 參數控制題目中數值(自然數、真分數和真分數分母)的范圍,該參數可以設置為1或其他自然數。該參數必須給定,否則程序報錯並給出幫助信息
- 生成的題目中計算過程不能產生負數,也就是說算術表達式中如果存在形如e1 − e2的子表達式,那么e1 ≥ e2
- 生成的題目中如果存在形如e1 ÷ e2的子表達式,那么其結果應是真分數
- 每道題目中出現的運算符個數不超過3個
- 程序一次運行生成的題目不能重復,即任何兩道題目不能通過有限次交換+和×左右的算術表達式變換為同一道題目。例如,23 + 45 = 和45 + 23 = 是重復的題目,6 × 8 = 和8 × 6 = 也是重復的題目。3+(2+1)和1+2+3這兩個題目是重復的,由於+是左結合的,1+2+3等價於(1+2)+3,也就是3+(1+2),也就是3+(2+1)。但是1+2+3和3+2+1是不重復的兩道題,因為1+2+3等價於(1+2)+3,而3+2+1等價於(3+2)+1,它們之間不能通過有限次交換變成同一個題目。生成的題目存入執行程序的當前目錄下的Exercises.txt文件
- 在生成題目的同時,計算出所有題目的答案,並存入執行程序的當前目錄下的Answers.txt文件
- 程序應能支持一萬道題目的生成
- 程序支持對給定的題目文件和答案文件,判定答案中的對錯並進行數量統計,統計結果輸出到文件Grade.txt (未實現)
2.PSP
PSP2.1 | Personal Software Process Stages | 預估耗時(分鍾) | 實際耗時(分鍾) |
---|---|---|---|
Planning | 計划 | 60 | 90 |
· Estimate | · 估計這個任務需要多少時間 | 60 | 90 |
Development | 開發 | 1720 | 2070 |
· Analysis | · 需求分析 (包括學習新技術) | 200 | 250 |
· Design Spec | · 生成設計文檔 | 50 | 60 |
· Design Review | · 設計復審 (和同事審核設計文檔) | 20 | 20 |
· Coding Standard | · 代碼規范 (為目前的開發制定合適的規范) | 10 | 10 |
· Design | · 具體設計 | 30 | 40 |
· Coding | · 具體編碼 | 1300 | 1600 |
· Code Review | · 代碼復審 | 50 | 30 |
· Test | · 測試(自我測試,修改代碼,提交修改) | 60 | 60 |
Reporting | 報告 | 100 | 100 |
· Test Report | · 測試報告 | 60 | 60 |
· Size Measurement | · 計算工作量 | 10 | 10 |
· Postmortem & Process Improvement Plan | · 事后總結, 並提出過程改進計划 | 30 | 30 |
合計 | 1880 | 2260 |
3.設計實現過程
首先,建立命令行控制模塊,然后建立一個com類來生成隨機數與隨機運算符,使用list表存放隨機數與隨機運算符,通過get_Calculate()函數判斷運算符,然后通過
get_Conversion()函數進行真分數的轉換,完成運算和化簡后,通過test_save()將算式寫入Exercise文檔中並把答案寫入Answers文檔中,將算式寫入文件時進行算式的查
重,通過重復答案的索引判斷算式是否重復來實現查重功能。
4.代碼說明
1.命令控制模塊
def get_Parameter():#命令行控制模塊 parser = argparse.ArgumentParser() parser.add_argument('-n', help='設定題目數量',type=int) parser.add_argument('-r', help='設定數值范圍',type=int) return parser.parse_args()
2.建立一個類用以生成隨機數與運算符
class com(object): def __init__(self, r):#初始化 self.r=r def get_Arithmeticl(self):#獲得隨機數字與符號 symbol=[] numerical=[] syb=0 n=1 m=0 i=random.randint(1, 3) for x in range(i): sy=random.choice(['+','-','×','÷']) if sy=='+'or sy=='-': syb +=10**(i-x-1) else : syb += 2 * (10 ** (i - x - 1)) symbol.append(sy) if self.r < 10: n = int(10 / self.r) if n==1: while m <= i: numerical.append(Fraction(random.randint(1, self.r), random.randint(1, self.r))) m+=1 else: while m <= i: nu = Fraction(random.randint(1, self.r * n), random.randint(1, self.r * n)) if nu<=self.r: numerical.append(nu) m += 1 return symbol,syb,numerical,i
3.識別運算符和分數的轉換
def get_Calculate(a,b,c):#四則運算 if c=='+': results=a+b elif c=='-': results=a-b elif c=='×': results=a*b else:results=a/b return results def get_Conversion(fraction):#假分數轉化真分數 if fraction.numerator%fraction.denominator==0: return '%d'%(fraction.numerator/fraction.denominator) elif fraction.numerator>fraction.denominator: a=int(fraction.numerator/fraction.denominator) b, c = fraction.numerator - a * fraction.denominator, fraction.denominator return '%d%s%d%s%d' % (a,'’',b,'/',c) else: b, c = fraction.numerator, fraction.denominator return '%d%s%d' % (b,'/',c)
4.生成算式列表和查重
ef get_Formula(n,r):#生成題目和答案列表 Exercises,Answers,Exercises1,Exercises2=[],[],[],[] x=1 while x<n+1: symbol, syb, numerical,i = com(r).get_Arithmeticl() results = numerical[0] judge = True for y in range(i): calculate=get_Calculate(results,numerical[y+1],symbol[y]) if calculate>=0:#判斷算式是否合法 answer=calculate else: judge=False break if judge:#查重 try: num=Answers.index(answer)#判斷重復答案的索引 if operator.eq(Exercises1[num],symbol) and operator.eq(Exercises2[num],numerical): pass except ValueError as e:#可以寫入 Answers.append(answer) Exercises1.append(symbol) Exercises2.append(numerical) Exercises.append('%d. %s'%(x,set_Formula(symbol,numerical,syb))) x+=1 else:pass return Exercises,Answers
5.寫入文件
def text_save(filename, data):#filename為寫入文件的路徑,data為要寫入數據列表. file = open(filename,'a') file.seek(0) file.truncate() # 清空文件 for x in data: x='%s\n'%(x) file.write(x) file.close() print('%s文件保存成功'%filename)
6.main函數
def main(): args = get_Parameter() if args.n: n = args.n if args.r: r = args.r Exercises, Answers = get_Formula(n, r) for x in range(n): Answers[x] = '%d. %s' % (x + 1, get_Conversion(Answers[x])) print('本次共生成題目%d道\n題目數值范圍為0-%d' % (n, r)) text_save('Exercises.txt', Exercises) text_save('Answers.txt', Answers)
5.測試結果分析:
程序運行:
生成文件:
生成10000道題目文件:
6.項目總結
本次項目為結對項目,這次題目比上次難了許多,一開始對項目框架的構建比較模糊,經過一段時間的查詢資料與討論后我們進行了項目分工,做項目時,一個人進行編寫另一個人在旁邊指導和構思,我們在設計功能時會提出各自的想法,經過討論選擇更合適的方法。其中在查重和統計答案對錯的功能實現遇到了困難,之后我們決定使用通過重復答案去查找相同的式子來完成查重,由於我們的編程基礎較為薄弱,未能實現對答案的統計對錯功能。結對編程之后,我感受到了結對編程的優點在於,在編寫代碼的過程中,結對伙伴會在旁邊找出編碼的錯誤,並能較快的找到BUG,讓我們能及時修改代碼,這樣提高了編程效率,節約時間。