小學生噩夢——四則運算題庫(python 全功能實現)


Github: https://github.com/holidaysss

小組:龍天堯(代碼實現),林毓植(浮點轉分數函數,代碼審查)

PSP2.1

Personal Software Process Stages

預估耗時(分鍾)

實際耗時(分鍾)

Planning

計划

 30  30

· Estimate

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

 30  30

Development

開發

 540  540

· Analysis

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

 60  60

· Design Spec

· 生成設計文檔

 30  30

· Design Review

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

 60  60

· Coding Standard

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

 30  30

· Design

· 具體設計

 120  120

· Coding

· 具體編碼

240 240

· Code Review

· 代碼復審

 60  60

· Test

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

 60  60

Reporting

報告

 90  90

· Test Report

· 測試報告

 30  30

· Size Measurement

· 計算工作量

 30  30

· Postmortem & Process Improvement Plan

· 事后總結, 並提出過程改進計划

 30  30

合計

  780  780

設計實現過程:思路:四則運算題庫的功能應該包括 出題,計算答案, 對比答案 這三個主要功能。

 

 

 

代碼說明

題目生成函數:problem()  ,調用natural(),fraction()

 

def problem(area=10):  # 隨機生成一道題目(自然數四則運算或分數運算),運算符不超過3個
    try:
        if random.choice([1, 2]) == 1:  # 隨機生成 自然數或分數 的四則運算
            expression, print_expression = natural(area)  # 生成一個自然數運算
            results = demical_to_fraction(eval(expression))  # 運算結果通過demical_to_fraction()轉成分數
        else:  # 分數四則運算 和上面流程大致相同
            expression, print_expression = fraction(area)  # 生成一個分數運算
            results = demical_to_fraction(eval(expression))
        if not results:  # 無法轉分數
            problem(area)
            return 0
        # print_expression_nums = list(filter(str.isdigit, print_expression))  # ['2','+',1']
        print_expression_nums = print_expression.replace('(', '').replace(')', '').split()  # 將輸出表達式拆解
        print_expression_nums.sort()  # ['+', 1', '2']
        if results < 0 or ((str(results)in answers) and (print_expression_nums in str_num)):  # 去負答案,去重復
            problem(area)
        else:
            results = turn_fracrtion(results)  # 轉化
            prints.append(print_expression)
            answers.append(results)  # 答案列表
            str_num.append(print_expression_nums)
    except Exception:  # 過濾分母為0的題目
        problem(area)

 

 

自然數運算生成 natural():

def natural(area):  # 生成一個自然數運算
    operator_num = random.randint(1, 3)  # 隨機運算符
    expression = print_expression = num = str(random.randint(1, area))  # 第一個數
    bracket = (random.choice(['(', '']) if not operator_num == 1 else '')  # 非單運算符 可加括號
    for i in range(operator_num):  # 隨機個運算符
        op = str(random.choice(operators))  # 隨機選擇運算符 (+ - * /)
        if op == '-':  # 若為'-',生成數字小於前一個數字
            num = str(random.randint(1, int(num)))
        else:
            num = str(random.randint(1, area))  # 隨機數值,不超過area
        if bracket == ')':  # 右括號在數字右邊
            print_expression += ' ' + change(op) + ' ' + num + bracket  # 用於輸出的表達式  例:1×2
            expression += op + num + bracket  # 用於eval()計算的表達式 例:1*2
        else:  # 左括號在數字左邊
            print_expression += ' ' + change(op) + ' ' + bracket + num
            expression += op + bracket + num
        bracket = (')' if bracket == '(' else '')  # 左括號配右括號, 空配空
    return expression, print_expression

 

 

分數運算生成 fraction(), gen_fraction():

def gen_fraciton(area):  # 生成一個規范分數
    while True:
        a = random.randint(1, area)
        b = random.randint(1, area)
        if '/' in str(Fraction(a, b)):
            return Fraction(a, b)


def fraction(area):  # 生成一個分數運算
    operator_num = random.randint(1, 3)  # 隨機運算符
    num = gen_fraciton(area)
    expression = print_expression = str(num)  # 第一個分數
    bracket = (random.choice(['(', '']) if operator_num != 1 else '')  # 超過一個運算符才需要加括號
    for i in range(operator_num):
        op = str(random.choice(operators))
        if op == '-':  # 若為'-',生成分數小於等於前一個分數
            while True:
                next_num = gen_fraciton(area)
                if next_num <= num:
                    break
            num = next_num
        else:
            num = gen_fraciton(area)
        if bracket == ')':
            if float(num) > 1:  # 假分數轉帶分數 例:8/3 -> 2'2/3
                print_expression += ' ' + change(op) + ' ' + turn_fracrtion(num) + bracket
            else:
                print_expression += ' ' + change(op) + ' ' + str(num) + bracket
            expression += op + str(num) + bracket
        else:
            if float(num) >= 1:
                print_expression += ' ' + change(op) + ' ' + bracket + turn_fracrtion(num)
            else:
                print_expression += ' ' + change(op) + ' ' + bracket + str(num)
            expression += op + bracket + str(num)
        bracket = (')' if bracket == '(' else '')  # 左括號配右括號
    return expression, print_expression

 

 

 假分數轉化函數 turn_fraction():

def turn_fracrtion(results):  # 假分數轉帶分數
    if isinstance(eval(str(results)), int) or (eval(str(results)) < 1):  # 整數和真分數
        return str(results)
    else:
        return str(int(results)) + "'" + str(results - int(results))  # 假分數

 

 

符號轉化函數 change():

def change(a):   # *,/ 轉成 ×,÷
    if a == '*':
        a = '×'
    elif a == '/':
        a = '÷'
    return a

eval函數處理的結果出來是浮點數,不符合要求,苦想不解,讓毓植寫了個浮點轉化分數的函數:

def find_cycle(demical):  # 找小數的循環體(參數為小數部分)
    for i in range(1, 17):
        cycle_part = demical[:i]  # 截取小數部分的前i位,假設為循環體
        if len(cycle_part) < 4:  # 如果循環體較短
            if (cycle_part*3) == demical[:3*i]:  # 需要滿足4次重復
                return cycle_part  # 滿足才認定為循環體
        else:  # 如果循環體較長
            if (cycle_part*2) == demical[:2*i]:  # 滿足2次重復
                return cycle_part
    return 0  # 找不到循環體,返回0


def demical_to_fraction(n, zero_num=0):  # 小數轉化分數
    n = str(n)  # 規范輸入為字符串形式
    if len(n) < 16:  # 如果是有限小數,直接返回
        return Fraction(n)
    real_num, dot_area = n.split('.')  # 獲取整數 和 小數
    float_num = float(n)  # 轉化一個浮點數用於計算
    for i in range(len(n)):
        cycle_start = dot_area[i:]  # 從第i位開始,開始截取字符串
        result = find_cycle(cycle_start)  # 從截取的字符串中找到循環體
        length = len(str(result))  # 判斷循環體的長度
        if result:   # 如果存在循環體
            if i != 0:  # 如果循環體的開始不是小數點后第一位 eg 0.13888888
                new_number = float_num*(10**i)  # 移位數使循環體是小數點后的開始 eg 13.8888
                demical_to_fraction(new_number, i)  # 將新生成的數遞歸使用
                break
            else:  # 如果循環體直接在小數點后的第一位
                fraction = Fraction(int(result), int('9'*length))  # 小數部分轉化為分數 /數學知識需要了解
                final_num = int(real_num) + fraction  # 小數點前的部分需要從重新加上
                return final_num/(10**zero_num)  # 回退移的位數

 

 

以上是主要函數

具體源碼后面會上傳到github

 

運行結果

生成一萬道題:

 

 

 

 

 

 

 

 

 

 

 

小學生就可以在記事本上做題啦

 

一年后。。

 

 感覺良好

開始對答案

 還行

 

 

 

 

 為了方便家長了解學生的成績,  在  答案對比 處增加了水型球比例圖。(具體代碼Github已更新,這里就不修改了)

 

 

 

好了。。。

 問題記錄:1.出現了溢出錯誤,發現是條件判斷的問題,已修改。  2.優化邏輯,分解problem()函數。 3.修改去重邏輯,優化程序運行速度. 4.拓展對比答案功能,增加水型球比例圖。 5.需求看錯了,過程不能出現負數看出結果不出現負數, 已修改。

      6. 忘記吧結果的假分數轉化了。。已補上。 7.日常優化。。。。。。。。 8.優化答案對比  ( 最后一次改了,再改我

項目小結:這個項目挺有意思的,主要運用到”隨機性“,小邏輯特別多,主要思路還是有跡可循的,繼續努力,加油。

 


免責聲明!

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



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