欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Python(140行):第一次作业_中小学数学卷子自动生成程序

程序员文章站 2022-04-18 23:09:21
项目需要简单总结有以下几点: 用户登录操作,命令行输入用户名和密码,判断是否有该账户; 登录状态下,可选择生成题目的数量或者切换年级; 根据用户对应的小学、初中、高中三个年级生成不同难度的算术题; 文件输出打印 根据以上四点需求,我的程序设计也对应分为四个模块对应。 log_in() 用户登录 nu ......

项目需要简单总结有以下几点:

  1. 用户登录操作,命令行输入用户名和密码,判断是否有该账户;

  2. 登录状态下,可选择生成题目的数量或者切换年级;

  3. 根据用户对应的小学、初中、高中三个年级生成不同难度的算术题;

  4. 文件输出打印

根据以上四点需求,我的程序设计也对应分为四个模块对应。

  • log_in()  用户登录
  • number_chose() 选择数量\切换年级
  • arithmetic_production() 题目生成
  • file_output() 打印

在登录模块中,把用户数据按照如下格式保存在userinfomation.txt文件中,并用open以只读的方式打开。

f = open("userinformation.txt", "r",encoding="utf-8")    

这里注意文件中包含有中文,需要用utf8的编码打开。

Python(140行):第一次作业_中小学数学卷子自动生成程序
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:123
grade:高中

username:王五2
password:123
grade:高中

username:王五3
password:123
grade:高中
userinformation

 

在等待用户输入打印题目数量或者切换学历时,需要通过正则表达式进行匹配

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] or\
101                     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()