Python(140行):第一次作業_中小學數學卷子自動生成程序
阿新 • • 發佈:2018-09-24
rpath set none 需求 小學 src temp {} 標記
項目需要簡單總結有以下幾點:
-
用戶登錄操作,命令行輸入用戶名和密碼,判斷是否有該賬戶;
-
登錄狀態下,可選擇生成題目的數量或者切換年級;
-
根據用戶對應的小學、初中、高中三個年級生成不同難度的算術題;
-
文件輸出打印
根據以上四點需求,我的程序設計也對應分為四個模塊對應。
- log_in() 用戶登錄
- number_chose() 選擇數量\切換年級
- arithmetic_production() 題目生成
- file_output() 打印
在登錄模塊中,把用戶數據按照如下格式保存在UserInfomation.txt文件中,並用open以只讀的方式打開。
f = open("UserInformation.txt", "r",encoding="utf-8")
這裏註意文件中包含有中文,需要用utf8的編碼打開。
username:張三1 password:123 grade:小學 username:張三2 password:123 grade:小學 username:張三3 password:123 grade:小學 username:李四1 password:123 grade:初中 username:李四2 password:123 grade:初中 username:李四3 password:123 grade:初中 username:王五1 password:UserInformation123 grade:高中 username:王五2 password:123 grade:高中 username:王五3 password:123 grade:高中
在等待用戶輸入打印題目數量或者切換學歷時,需要通過正則表達式進行匹配
import re in_str = input(‘準備生成{}數學題目,請輸入生成題目數量(10-30):‘.format(GRADED)) matchNub = re.match(r‘\d+‘,in_str) #判讀輸入為純數字 matchObj = re.match(r‘切換為(.*)‘,in_str) #判斷輸入為切換命令
在插入括號時,通過取隨機數確定要插入括號的個數,括號所以的組合情況與操作數個數有關,滿足組合關系,關系如下
brackt_Nub = C(2,operator_Nub)-1
減去一種情況是左右兩端數字組合的情況。
PS:這裏沒有考慮乘除法運算有時候加括號與不加括號運算順序一樣的問題
定義以下列表保存操作數為3-5時括號所有的位置組合情況
BRACKET_SIT = [[0,2],[2,4] ,[4,6],[0,4],[2,6] ,[0,6],[2,8],[4,8],[6,8]]
bracket_chose = [] #選擇加入括號的位置 for i in range(bracket_nub): temp_sit = BRACKET_SIT[random.randint(0,int(termNub*float((termNub-1)/2))-2)] #根據括號與操作數的組合關系確定選擇括號位置的區間 bracket_flag = 1 #標記括號是否交叉 for j in bracket_chose: #交叉判定,括號交叉時重新隨機 if j[1]>=temp_sit[0] and j[0]<temp_sit[0] and j[1]<temp_sit[1] or j[0]<=temp_sit[1] and j[1]>temp_sit[1] and j[0]>temp_sit[0] or j[0] == temp_sit[0] and j[1] ==temp_sit[1]: bracket_flag = 0 if bracket_flag: bracket_chose.append(temp_sit) else: i -= 1
為了不改變原來列表中操作數與操作符的位置,插入括號時只改變操作數字符串
for i in bracket_chose: outputDate[i[0]] = ‘(‘ + outputDate[i[0]] outputDate[i[1]] += ‘)‘
按照用戶名建立文件夾,按照當前時間新建txt文件,追加寫入。
def file_output(Equation,tName): #文件輸出 curPath = os.getcwd() #獲得當前文件目錄 targetPath = curPath+os.path.sep+USER #構建絕對地址 if not os.path.exists(targetPath): #如果不存在,則新建文件夾 os.makedirs(targetPath) f = open(targetPath + ‘/‘ + tName +‘.txt‘,‘a‘) #如果不存在,新建txt問題,且追加寫入 f.write(Equation+‘\n\n‘)
不會百度,反正我是記不住,每次都要問度娘QAQ
最後還有一個去重問題,其實按照程序的算法,隨機產生的題目相同的概率不到萬分之一 ,相當於我抽到SSR的概率,不過,萬一哪天我就抽到了不是嘛?
- 不能生成與用戶文件下所有txt文件重復相同的題目
- 不能生成本次產生題目中重復的題目(用集合)
q_set = set() #集合保存生成的問題,用於去重 history_data = ‘‘ #歷史題目 curPath = os.getcwd() #獲得當前文件目錄 targetPath = curPath+os.path.sep+USER #構建絕對地址 files = os.listdir(targetPath) #該文件夾下所有文件名 for f in files: txt_path = targetPath + ‘/‘ + f contents = open(txt_path,‘r‘) history_data +=contents.read() for i in range(QUESTION_NUB): q_Temp = ‘‘.join(arithmetic_production()) #將列表轉換為字符串 q_set.add(q_Temp) #加入集合 if len(q_set) == i or (q_Temp in history_data): #判定是否重復,重復則重新生成 i -= 1 continue file_output(‘[‘ + str(i+1)+‘] ‘ + q_Temp , time_name) #寫入文件
總結:度過了一個愉快的中秋假期:),今天最後一天爬下床來把作業寫了,一共130余行代碼(python真香,可惜還是超了100行……)。過了一個暑假後很多東西都忘記了,比如正則、文件流等等,還有加括號的算法也是想了好久(都是淚啊),就當做是復習了。當然,程序本身還存在很多不足,比如沒有判定括號加在乘除法上是無意義的問題。也沒有判定做除法和開根號和三角運算時是否能正確運算。繼續改進的話還可以每次打印題目後給出答案或者支持用戶自己輸入答案,答完題目後給出得分。最後歡迎評論給出優化意見或者有更簡短的代碼分享
附源碼:
1 # coding=utf-8 2 import random 3 import re 4 import os 5 import time 6 7 FOUR_OPERATOR = [‘ + ‘,‘ - ‘,‘ * ‘,‘ / ‘] #+-*x符號 8 POWER_OPERATOR = [‘√‘,‘^2‘] #初中運算的根號和平方 9 TRIGONOMETRIC = [‘sin‘,‘cos‘,‘tan‘] #高中運算的三角函數 10 BRACKET_SIT = [[0,2],[2,4] ,[4,6],[0,4],[2,6] ,[0,6],[2,8],[4,8],[6,8]] #操作數為3-5時括號的組合情況,操作數小於3括號無意義 11 MAXN = 100 #操作數的取值範圍最大值 12 MINN = 1 #操作數的取值範圍最小值 13 OPERATOR_MAX = 5 #操作符最大取值 14 USER = ‘‘ #用戶ID 15 GRADED = ‘‘ #用戶學歷 16 QUESTION_NUB = 0 #問題數目 17 targetPath = ‘‘ 18 19 def main(): 20 global targetPath 21 log_in() 22 number_chose() 23 time_name = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()) #格式化獲得當前時間 24 q_set = set() #集合保存生成的問題,用於去重 25 history_data = ‘‘ #歷史題目 26 curPath = os.getcwd() #獲得當前文件目錄 27 targetPath = curPath+os.path.sep+USER #構建絕對地址 28 if not os.path.exists(targetPath): #如果不存在,則新建文件夾 29 os.makedirs(targetPath) 30 files = os.listdir(targetPath) #該文件夾下所有文件名 31 for f in files: 32 txt_path = targetPath + ‘/‘ + f 33 contents = open(txt_path,‘r‘) 34 history_data +=contents.read() 35 for i in range(QUESTION_NUB): 36 q_Temp = ‘‘.join(arithmetic_production()) #將列表轉換為字符串 37 q_set.add(q_Temp) #加入集合 38 if len(q_set) == i or (q_Temp in history_data): #判定是否重復,重復則重新生成 39 i -= 1 40 continue 41 file_output(‘[‘ + str(i+1)+‘] ‘ + q_Temp , time_name) #寫入文件 42 43 def log_in(): 44 global USER,GRADED 45 print(‘輸入用戶名和密碼,兩者之間用空格隔開‘) 46 f = open("UserInformation.txt", "r",encoding="utf-8") #打開用戶數據庫 47 list = f.read().split(‘\n\n‘) 48 log_flag = 0 #用於標記是否在數據庫內 49 while 1: 50 str_user = input().split(‘ ‘) 51 while len(str_user) != 2: 52 str_user = input(‘請用正確的格式輸入用戶名和密碼:‘).split(‘ ‘) 53 in_name = str_user[0] #輸入ID 54 in_password = str_user[1] #輸入密碼 55 for i in range(len(list)): #遍歷用戶數據,查看是否存在用戶信息 56 temp_user = list[i].split(‘\n‘) 57 if temp_user[0].lstrip(‘username:‘) == in_name: 58 if temp_user[1].lstrip(‘password:‘) == in_password: 59 USER = in_name 60 GRADED = temp_user[2].lstrip(‘grade:‘) #獲得學歷信息 61 log_flag = 1 62 if log_flag == 1: 63 break 64 else: 65 print(‘無該用戶信息,請重新輸入:‘) 66 67 def number_chose(): #生成題目數目或切換學歷 68 while 1: 69 global GRADED,QUESTION_NUB 70 in_str = input(‘準備生成{}數學題目,請輸入生成題目數量(10-30):‘.format(GRADED)) 71 if re.match(r‘\d+‘,in_str) : #判斷輸入為數字 72 question_nub = int(in_str) 73 if question_nub<10 or question_nub>30: 74 print(‘題目數量範圍錯誤!‘) 75 continue 76 QUESTION_NUB = question_nub 77 break 78 matchObj = re.match(r‘切換為(.*)‘,in_str) #判斷輸入為切換命令 79 if matchObj and (matchObj.group(1) == ‘小學‘ or matchObj.group(1) == ‘初中‘ or matchObj.group(1) == ‘高中‘): 80 GRADED = matchObj.group(1) 81 continue 82 83 def arithmetic_production(): #產生數學題目 84 global GRADED 85 outputDate = [] #保存題目,做返回值 86 termNub = random.randint(2,OPERATOR_MAX) #操作數個數,2-5之間隨機 87 bracket_nub = random.randint(0,termNub-2) #括號個數,操作數個數-2 88 for i in range(termNub - 1): #將操作數和操作符隨機加入列表 89 outputDate.append(str(random.randint(MINN, MAXN))) 90 outputDate.append(FOUR_OPERATOR[random.randint(0,3)]) 91 outputDate.append(str(random.randint(MINN,MAXN))) 92 outputDate.append(‘ = ‘) 93 94 bracket_chose = [] #選擇加入括號的位置 95 for i in range(bracket_nub): 96 temp_sit = BRACKET_SIT[random.randint(0,int(termNub*float((termNub-1)/2))-2)] #括號選擇情況與操作數之間存在累加關系 97 bracket_flag = 1 #標記括號是否交叉 98 for j in bracket_chose: #交叉判定 99 if j[1]>=temp_sit[0] and j[0]<temp_sit[0] and j[1]<temp_sit[1] or 100 j[0]<=temp_sit[1] and j[1]>temp_sit[1] and j[0]>temp_sit[0] or101 j[0] == temp_sit[0] and j[1] ==temp_sit[1]: 102 bracket_flag = 0 103 if bracket_flag: 104 bracket_chose.append(temp_sit) 105 else: 106 i -= 1 107 for i in bracket_chose: 108 outputDate[i[0]] = ‘(‘ + outputDate[i[0]] 109 outputDate[i[1]] += ‘)‘ 110 111 if GRADED == ‘初中‘: 112 last_flag = 0 #標記是否已經加入根號和平方 113 for i in range(len(outputDate)): 114 if i%2==0 and random.randint(0,1)==1: 115 if random.randint(0,1) == 0: 116 outputDate[i] = POWER_OPERATOR[0] +outputDate[i] #加入根號 117 else: 118 outputDate[i] = outputDate[i] + POWER_OPERATOR[1] #加入平方 119 last_flag = 1 120 if last_flag ==0: 121 outputDate[-2] = outputDate[-2] + POWER_OPERATOR[1] 122 if GRADED == ‘高中‘: 123 last_flag = 0 #標記是否已經加入三角函數 124 T_chose = random.randint(0, 2) 125 for i in range(len(outputDate)): 126 if i%2==0 and random.randint(0,1)==1: 127 outputDate[i] = TRIGONOMETRIC[T_chose] + ‘(‘ +outputDate[i] + ‘)‘ #加入三角函數 128 last_flag = 1 129 if last_flag ==0: 130 outputDate[-2] = TRIGONOMETRIC[T_chose] + ‘(‘ + outputDate[-2] + ‘)‘ 131 132 return outputDate #返回字符串列表 133 134 def file_output(Equation,tName): #文件輸出 135 f = open(targetPath + ‘/‘ + tName +‘.txt‘,‘a‘) #如果不存在,新建txt問題,且追加寫入 136 f.write(Equation+‘\n\n‘) 137 138 if __name__=="__main__": 139 main()
Python(140行):第一次作業_中小學數學卷子自動生成程序