v0x  

摘要:

本篇内容是基于上一次个人项目,两人共同完成的结对项目,关于项目要求详见结对项目需求文档。

 

总体分析:

本出题软件项目基于python,采用Tkinter模块实现GUI框架,每一个界面都采用一个Class实现(具体界面见代码注释);切换界面时,摧毁当前界面画布,并调用其它Class生成新的界面;该项目中的验证码采用榛子云实现,仅供测试;用户信息的保存采用了pickle模块读取或保存;函数answer_item_get(item_product)用于题目选项的生成,正确答案随机分配选项。

 

具体分析:

首先从出题功能开始分析,由于个人项目笔者与同伴都采用的是c++实现,故本项目对于个人项目的复用主要是对于思路的复用。

answer_item_get()函数是用于生成题目选项的函数,首先他会计算该题目的答案然后随机的将其分配到A,B,C,D内的某个选项中,剩下的三个选项也会被分配与答案不相同的值其输入为生成的题目,输出的是一个选项的列表。

  1 def answer_item_get(item_product):  # item_product为生成的题目
  2     l = len(item_product)  # 题目的长度
  3     z = 0  # z和i都是在生成题目时用到的下标
  4     i = 0
  5     ans_str1 = ""  # 生成的答案运算表达式
  6     # 答案运算的逻辑就是整体先将三角函数,根号,平方先进行运算,运算完后得到的一个表达式,可以直接用python的eval函数算出值
  7     while i < l:
  8         r = 0  # 用于计算三角函数时,指向三角符号的第一个字符的下标,如sin的s
  9         if item_product[i] == '':
 10             z = i + 1  # z和i都为根号后第一个数字的位置
 11             i = i + 1
 12             # 对根号后的字符进行遍历,直到访问的字符不是数字,然后对前面的数字形成的数进行开根号运算
 13             # 随后将其保存到ans_str1中
 14             while i < l:
 15                 if item_product[i] >= '0' and item_product[i] <= '9':
 16                     i = i + 1  # 这里不是数字时,循环结束,此时i的位置指向一个非数字字符
 17                     # item_product[z:i]的切片正好为根号后的整个数,接下来的三角函数和平方运算也是如此
 18                 else:
 19                     break
 20             num = int(item_product[z:i])
 21             one_ans = str(num ** 0.5)
 22             ans_str1 += one_ans
 23             # 对于平方的运算,由于一个数最大为100,故每次访问一个字符时,先判断其
 24             # 是否为数字,然后判断其后1,2,3个位置是否有平方(注意数组的长度,防止其溢出)
 25             # 随后和根号一样,对其进行运算,将结果保存到ans_str1中
 26         elif (item_product[i] >= '0' and item_product[i] <= '9') and (
 27                 (i + 1 < l and item_product[i + 1] == '^') or (i + 2 < l and item_product[i + 2] == '^') or
 28                 (i + 3 < l and item_product[i + 3] == '^')):
 29             z = i
 30             while i < l:
 31                 if item_product[i] >= '0' and item_product[i] <= '9':
 32                     i = i + 1
 33                 else:
 34                     break
 35             num = int(item_product[z:i])
 36             one_ans = str(num ** 2)
 37             ans_str1 += one_ans
 38             i = i + 1
 39             # 计算三角函数和计算根号类似,这里用到了一个sy模块,其可以计算三角函数
 40         elif item_product[i:i + 3] == "sin" or item_product[i:i + 3] == "cos" or item_product[i:i + 3] == "tan":
 41             r = i
 42             z = i + 3  # z和i此时都为三角符号后第一个数字的位置
 43             i = i + 3
 44             while i < l:
 45                 if item_product[i] >= '0' and item_product[i] <= '9':
 46                     i = i + 1
 47                 else:
 48                     break
 49             angle_str = item_product[r:z]  # angle_str保存的是三角符号,sin,cos,tan
 50             one_ans = ""  # 计算后的答案
 51             num_str = int(item_product[z:i])
 52             if angle_str == "sin":
 53                 one_ans = sy.sin(num_str / 180 * np.pi)
 54             elif angle_str == "cos":
 55                 one_ans = sy.cos(num_str / 180 * np.pi)
 56             elif angle_str == "tan":
 57                 one_ans = sy.tan(num_str / 180 * np.pi)
 58             one_ans_str = str(one_ans)
 59             ans_str1 += one_ans_str
 60         else:
 61             ##若符号非三角函数,平方,根号,如*,+,-或不带需要计算符号的数字,就将其直接添加到字符串内
 62             ans_str1 += item_product[i]
 63             i = i + 1
 64     ans_position = random.randint(0, 3)  # 正确答案的位置
 65     ans_product = []
 66     answer_str = ""
 67     # 将选项添加到列表内,函数返回该列表。
 68     if ans_position == 0:
 69         answer_str = 'A.'  # mystr保存着某选项
 70         answer_str += str(eval(ans_str1))
 71         # 当ans_position=0时,正确答案就为A,将A和正确答案构成的字符串
 72         # 添加到列表里面,随后在将其他选项和错误答案也添加进列表,
 73         # 这里的错误答案选择的是正确答案+1,+2,+3
 74         ans_product.append(answer_str)
 75         answer_str = 'B.'
 76         answer_str += str(eval(ans_str1) + 1)
 77         ans_product.append(answer_str)
 78         answer_str = 'C.'
 79         answer_str += str(eval(ans_str1) + 2)
 80         ans_product.append(answer_str)
 81         answer_str = 'D.'
 82         answer_str += str(eval(ans_str1) + 3)
 83         ans_product.append(answer_str)
 84     if ans_position == 1:
 85         answer_str = 'A.'
 86         answer_str += str(eval(ans_str1) + 1)
 87         ans_product.append(answer_str)
 88         answer_str = 'B.'
 89         answer_str += str(eval(ans_str1))
 90         ans_product.append(answer_str)
 91         answer_str = 'C.'
 92         answer_str += str(eval(ans_str1) + 2)
 93         ans_product.append(answer_str)
 94         answer_str = 'D.'
 95         answer_str += str(eval(ans_str1) + 3)
 96         ans_product.append(answer_str)
 97     if ans_position == 2:
 98         answer_str = 'A.'
 99         answer_str += str(eval(ans_str1) + 1)
100         ans_product.append(answer_str)
101         answer_str = 'B.'
102         answer_str += str(eval(ans_str1) + 2)
103         ans_product.append(answer_str)
104         answer_str = 'C.'
105         answer_str += str(eval(ans_str1))
106         ans_product.append(answer_str)
107         answer_str = 'D.'
108         answer_str += str(eval(ans_str1) + 3)
109         ans_product.append(answer_str)
110     if ans_position == 3:
111         answer_str = 'A.'
112         answer_str += str(eval(ans_str1) + 1)
113         ans_product.append(answer_str)
114         answer_str = 'B.'
115         answer_str += str(eval(ans_str1) + 2)
116         ans_product.append(answer_str)
117         answer_str = 'C.'
118         answer_str += str(eval(ans_str1) + 3)
119         ans_product.append(answer_str)
120         answer_str = 'D.'
121         answer_str += str(eval(ans_str1))
122         ans_product.append(answer_str)
123     return ans_product
answer_item_get

answer_get函数是用于生成答案的函数,输入题目,返回其答案逻辑与生成选项的函数的生成答案部分完全相同,只是返回的是一个正确答案的字符串。

 1 def answer_get(s):
 2     l = len(s)
 3     z = 0
 4     i = 0
 5     ans_str1 = ""
 6     while i < l:
 7         r = 0
 8         if s[i] == '':
 9             z = i + 1
10             i = i + 1
11             while i < l:
12                 if s[i] >= '0' and s[i] <= '9':
13                     i = i + 1
14                 else:
15                     break
16             num = int(s[z:i])
17             one_ans = str(num ** 0.5)
18             ans_str1 += one_ans
19         elif (s[i] >= '0' and s[i] <= '9') and (
20                 (i + 1 < l and s[i + 1] == '^') or (i + 2 < l and s[i + 2] == '^') or
21                 (i + 3 < l and s[i + 3] == '^')):
22             z = i
23             while i < l:
24                 if s[i] >= '0' and s[i] <= '9':
25                     i = i + 1
26                 else:
27                     break
28             num = int(s[z:i])
29             one_ans = str(num ** 2)
30             ans_str1 += one_ans
31             i = i + 1
32         elif s[i:i + 3] == "sin" or s[i:i + 3] == "cos" or s[i:i + 3] == "tan":
33             r = i
34             z = i + 3
35             i = i + 3
36             while i < l:
37                 if s[i] >= '0' and s[i] <= '9':
38                     i = i + 1
39                 else:
40                     break
41             angle_str = s[r:z]
42             one_ans = ""
43             num_str = int(s[z:i])
44             if angle_str == "sin":
45                 one_ans = sy.sin(num_str / 180 * np.pi)
46             elif angle_str == "cos":
47                 one_ans = sy.cos(num_str / 180 * np.pi)
48             elif angle_str == "tan":
49                 one_ans = sy.tan(num_str / 180 * np.pi)
50             one_ans_str = str(one_ans)
51             ans_str1 += one_ans_str
52         else:
53             ans_str1 += s[i]
54             i = i + 1
55     return str(eval(ans_str1))
answer_get

关于其他功能,验证码采用了榛子云服务,在网上找到对应的实现代码和下载了相应的jdk后实现。对于用户信息的保存,则是采用python的pickle模块来进行保存,将用户名和密码,电话号码和密码作为组合保存在两个文件中,需要修改密码时,找到该匹配,修改键值即用户名即可。其余入总体分析所述,总体框架采用的是tkinter模块。

# 获取验证码
            global code
            code = ''
            # 判断电话号码的格式
            if tel == '' or len_tel != 11 or is_number(tel) == False:
                tkinter.messagebox.showerror('Error', '请输入正确的电话号码')
            # 判断该电话号码是否注册过
            elif tel in exist_usr_info2:
                tkinter.messagebox.showerror('Error', '改电话已被注册')
            else:
                tkinter.messagebox.showinfo('tip', '验证码已发送')
                for num in range(1, 5):
                    code = code + str(random.randint(0, 9))
                print(code)
                # 将AppId和AppSecret复制粘贴过来
                client = smsclient.ZhenziSmsClient('https://sms_developer.zhenzikj.com', '参数1',
                                                   '参数2')
                # 第一个参数为发送号码,第二个参数为发送的验证码内容
                params = {}
                params['number'] = tel
                params['templateId'] = '6944'
                params['templateParams'] = [code, '15分钟']
                print(client.send(params))
验证码

给出榛子云Python的JDK下载地址:http://smsow.zhenzikj.com/doc/sdk.html

 

总结:

       本次项目笔者主要是负责出题外功能的设计,在一开始单单通过调用函数去实现,发现实现困难后采用类来进行实现,设定一个界面写在一个类中,登录界面,出题界面,修改密码界面等等。切换界是通过摧毁当前的界面的画布,并调用其它类形成一个新的画布来实现,而关于用户信息的储存,上述分析中已经提到是采用pickle模块来实现的,当pickle文件被删除其中的信息也一并被删除,并且创建该文件时必须预先写入一条信息,否则当文件是空时,读取会报错。一开始考虑过采用数据库实现,但是当时对于数据库的使用还并不熟悉。本次项目花费时间最多的还是Bug的查找与改进,这个过程是痛苦的,每次编写完部分功能的代码都会出现一堆bug,试错,修改,试错,修改,中后期基本就是这两步的循环,然后就是寻找他人来使用,再一步步修改界面,做到简洁实用的样子,能让人一目了然。本次项目不仅学会了许多新鲜的内容,同时也初步体会到了软件开发的过程。

 

posted on 2021-10-09 15:28  v0x  阅读(56)  评论(0)    收藏  举报