1.简单介绍
项目名称:中小学数学卷子自动生成程序
主要功能:a.登陆
通过命令行输入账号和密码进行登陆,成功后出现提示
否则需要重新输入
b.切换难度
可以输入“切换为XX”,修改生成题目的类型,如小学,初中,高中,不符合要求时提示重新输入
c.随机生成试卷
根据提示,输入数字,可以随机生成需要的数量的题目,题目难度默认为账户类型,亦可输入切换;
生成的试卷以txt格式和固定格式的文件名保存在特定的目录下;
新生成的题目不能与同文件夹下的题目重复。
D.附录
小学、初中、高中题目难度要求
|
小学 |
初中 |
高中 |
|
难度要求 |
+,-,*./ |
平方,开根号 |
sin,cos,tan |
|
备注 |
只能有+,-,*./和() |
题目中至少有一个平方或开根号的运算符 |
题目中至少有一个sin,cos或tan的运算符 |
|
2.开发环境
Windows10 python3.7
3.思路结构
由于老师提供的说明文档中已经对项目的要求介绍的非常详细。正常的一个思路就是将程序分为几个模块,包括:登陆,切换,生成等。
我的队友也不例外,他的python源代码中,除了主函数外,分为了Validlogin(), response_login(), paper_generating() 三个部分,从函数名就可以知道,我的队友想法相同。
那么我们就接下来就从这三个部分入手。
4.关键部分介绍
A.Validlogin() (登陆部分)
1 def Validlogin(): 2 global user_id,level 3 print('输入用户名和密码,两者之间用空格隔开') 4 try: 5 f=open("USER_IDlist.txt","r",encoding="utf-8") 6 userlist=f.read().split('\n') 7 login_flag=False 8 while True: 9 user_login=input().split(' ') 10 while len(user_login)!=2: 11 user_login=input("请输入正确的用户名、密码:").split(' ') 12 id=user_login[0] 13 psd=user_login[1] 14 for i in range(len(userlist)): 15 str=userlist[i].split() 16 if str[0].lstrip("username:")==id and str[1].lstrip("password:")== psd: 17 level=str[2].lstrip("level:") 18 user_id=id 19 login_flag=True 20 if login_flag: 21 print("登陆成功!\n当前选择为{}出题".format(level)) 22 break 23 else: print("请输入正确的用户名、密码! ") 24 except Exception as error: 25 print(error)
全局变量 user_id, level 分别代表登陆的账户的用户名和生成试卷难度
由于读取文件可能会产生异常,用try/except控制。
队友将文档提供的账户和密码保存为 文件USER_IDlist.txt中,每次登陆前先进行读取。
接下里是一个while循环配合flag标志判断输入的账号名和密码是否正确。
这一部分的逻辑比较简单,直接遍历预设的账户,判断是否符合。
B.reponse_login()
def response_login(): try: while True: global level,num str=input('准备生成{}数学题目,请输入生成题目数量,大小范围在(含)10-30以内:'.format(level)) result = re.match(r'切换为(.+)', str) if str.isdigit() : if int(str)<10 or int(str)>30: print("输入范围不符合要求!") continue else: num=int(str) break elif result: if(result.group(1)=='小学' or result.group(1)=='初中' or result.group(1)=='高中'): level=result.group(1) print("切换成功!") continue else: print("请输入小学,初中,高中三个选项中的一个!") continue elif not result: try: if int(str)==-1: print("即将重新登陆!") Validlogin() else:print("请输入正确的命令!") except: print("请输入正确的命令!") except Exception as error: print(error)
第二部分是选择部分 。这部分有两个功能:切换难度和输入题号,因此需要判断输入的字符串是题数或是切换难度的关键词。
输入后,使用match()判断是否匹配关键字,使用isdigit()判断是否是数字。
当输入为切换难度时,判断难度类型是否符合,若符合,用全局变量level提取。
当不是输入数字时,可以一直切换难度,所以整体是在while循环中。
使用全局变量num,将输入的题号提取。
c.paper_generating()
def paper_generating(): global level,num content = '' pre_time = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()) pre_path = os.getcwd() targetpath = pre_path + '/' + user_id+'/'+level ques_set = set() if not os.path.exists(targetpath): os.makedirs(targetpath) files = os.listdir(targetpath) for file in files: text_path = targetpath + '/' + file text = open(text_path, 'r',encoding='utf-8') content += text.read() for j in range(num): question=[] operater_num = random.randint(1, 5) k = operater_num - 2 if operater_num < 2: k = 0 bracket_num = random.randint(0, k) for i in range(operater_num+1): question.append(str(random.randint(MIN_N,MAX_N))) question.append(Arithmetic_operator[random.randint(0,3)]) question.append(str(random.randint(MIN_N,MAX_N))) ins=[2*i for i in range(operater_num+1)] if level=='初中': add_num=random.randint(1,2) for i in range(add_num): if(random.randint(0,1)==1): question[ins[random.randint(0,operater_num)]] = ps_operator[0] + question[ins[i]] else: question[ins[random.randint(0,operater_num)]] =question[ins[i]]+ps_operator[1] if level=='高中': add_num_1 = random.randint(0, 1) add_num_2=random.randint(1,2) for i in range(add_num_1): if(random.randint(0,1)==1): question[ins[random.randint(0,operater_num)]] = ps_operator[0] + question[ins[i]] else: question[ins[random.randint(0,operater_num)]] =question[ins[i]]+ps_operator[1] for i in range(add_num_2): k=random.randint(0,2) question[ins[random.randint(0,operater_num)]] =Trigonometric_operator[k] +"("+ question[ins[i]]+")" for i in range(bracket_num): question[ins[i]]='('+question[ins[i]] t=random.randint(1,2) question[ins[i+t]] = question[ins[i+t]]+')' for i in range(len(question)): if re.match(r'\([0-9]+\)', question[i]): if not (re.match(r'sin\([0-9]+\)', question[i]) or re.match(r'cos\([0-9]+\)', question[i]) or re.match( r'tan\([0-9]+\)', question[i])): question[i] = str(random.randint(1, 100)) ques = ''.join(question) ques_set.add(ques) if ques in content or len(ques_set) == j: j -= 1 continue f = open(targetpath + '/' + pre_time + '.txt', 'a',encoding='utf-8') f.write('(' + str(j + 1) + ') ' + ques + " = ?" + '\n'+'\n') print("出题成功!",end='')
第三部分是生成题目保存到文件。
生成文件部分比较常规,利用time的函数,直接生成以时间命名的文件,并根据当前路径进行存放。
读取旧文件,先将所有字符保存到一个字符串content中。
然后根据难度随机生成题目。
生成题目分为三步基本以random为核心。
先随机生成不定数量不定值的操作数;然后根据不同难度会用到不同的符号,采用全局变量的数组控制;在随机生成一些括号加入到式子中。
生成后的式子到content中进行比较,如果能在content找到则说明重复,则重新生成。
5.结果展示
总结:
队友采用python进行开发,而我采用了Java语音。两份项目很大的差异也是由开发环境不同导致的。自己完成工程后,再学习别人的代码,体验非常新鲜有趣。
优点:
与Java相比,python更加简单简洁,虽然Java也有很多好用的包、工具,但是使用起来也不方便,无论是配置环境的导入或是在代码上的实现,比起python还是麻烦太多。
并且Java类似c、c++的语法,加上面向对象的代码风格,在编写这种简单的项目代码量会增加很多。
缺点:
虽然队友的逻辑和实现都没有什么问题,但是由于空行分段比较少,看起来比较密集,寻找代码中的细节没有那么容易。