关键词:
前言:
在个人项目中,实现小初高数学出题程序只需要命令行,但在结对编程中需要带图形用户界面,并且用户对象不再是出题老师,而是小初高学生。因为在个人项目中,两人分别使用C++和Python语言来编写的,而C++的图形用户界面感觉晦涩难懂,所有一致决定使用Python来开发结对编程项目,使用的工具为Python自带的Tkinter
结对编程项目要求:
用户:
小学、初中和高中学生。
功能:
1、用户注册功能。用户提供手机号码,点击注册将收到一个注册码,用户可使用该注册码完成注册;
2、用户完成注册后,界面提示设置密码,用户输入两次密码匹配后设置密码成功。密码6-10位,必须含大小写字母和数字。用户在登录状态下可修改密码,输入正确的原密码,再输入两次相同的新密码后修改密码成功;
3、密码设置成功后,跳转到选择界面,界面显示小学、初中和高中三个选项,用户点击其中之一后,提示用户输入需要生成的题目数量;
4、用户输入题目数量后,生成一张试卷(同一张卷子不能有相同题目,题目全部为选择题),界面显示第一题的题干和四个选项,用户选择四个选项中的一个后提交,界面显示第二题,...,直至最后一题;
5、最后一题提交后,界面显示分数,分数根据答对的百分比计算;
6、用户在分数界面可选择退出或继续做题;
7、小初高数学题目要求见个人项目。
项目原型:
在正式动工前,我们首先在纸上画了软件原型图,如下:
其中用红色线将该项目分为三个部分,两人分工编写
第一部分,登陆:
由于未能掌握数据库的处理,在保存账号密码的时候,使用Excel表格实现
在登陆界面只会验证Excel中是否有该手机号,以及手机号对应的密码是否正确,若没有找到手机号,或者找到手机号但密码对不上,则会弹出一个对话框提示手机号或密码输入错误
若没有注册手机号,可以点击“注册账号”按钮进入注册界面。在注册界面里,当点击“注册”按钮后会验证手机号、密码是否满足格式要求,这里使用正则表达式来实现验证功能,然后会验证两次输入的密码是否一致,以及验证码是否与发送到手机号的验证码一致。点击“获取验证码按钮”会发送验证码到对应手机号上,这里使用了腾讯云的免费试用发送短信功能,免费试用100条短信。注册完成后,注册界面会关闭,在登陆界面输入正确的手机号和密码即可登陆。
第二部分,选择:
登陆成功后会进入选择界面,在界面右上角可以修改密码,可以在“小学”,“初中”,“高中”三种难度中选择一种,选择后输入生成题目数量,会验证题目数量是否大于0。
第三部分,做题:
会按照选择的难度和输入题目的数量生成题目,每次生成一道题,生成一道题的代码复用的是C++的,代码如下:
1 //level为0代表难度为小学,1代表初中,2代表高中 2 string GetOneQuestion(int level) 3 4 stringstream ss; 5 int bracketNum = 0; //括号的数量,单位为对 6 int operateNum; //操作数 7 bool leftBracket; //判断该操作数前是否有左括号,若有,则在该操作数后不加右括号,因为要避免出现“(?)”的情况 8 bool need = false; //判断是否满足备注要求,初中题目至少一个根号或平方(概率皆为1/2),高中题目至少一个三角函数 9 if (level == 0) 10 11 operateNum = 2+rand()%4; //小学题目2~5个操作数 12 13 else 14 15 operateNum = 1+rand()%5; //初中和高中题目1~5个操作数 16 17 18 if (operateNum == 1) 19 20 if (level == 1) 21 22 if (rand()%2 == 0) 23 24 ss << "√" << 1+rand()%100; 25 26 else 27 28 ss << 1+rand()%100 << "^2"; 29 30 31 else if (level == 2) 32 33 string fun; 34 int num; 35 //tan值要存在 36 do 37 38 fun = g_triFun[rand()%3]; 39 num = g_triNum[rand()%46]; 40 41 while (fun == "tan(" && (num+90)%180 == 0); 42 ss << fun << num << "°" << ‘)‘; 43 44 45 else 46 47 //生成第一个操作数 48 if (rand()%4 == 0) 49 50 ss << ‘(‘; 51 bracketNum++; 52 53 54 if (level == 1 && rand()%4 == 0) //根号 55 56 need = true; 57 ss <<"√"; 58 59 60 if (level == 2 && rand()%4 == 0) //操作数,或者sin(?)cos(?)tan(?) 61 62 need = true; 63 string fun; 64 int num; 65 //tan值要存在 66 do 67 68 fun = g_triFun[rand()%3]; 69 num = g_triNum[rand()%46]; 70 71 while (fun == "tan(" && (num+90)%180 == 0); 72 ss << fun << num << "°" << ‘)‘; 73 74 else 75 76 ss << 1+rand()%100; 77 78 79 if (level == 1 && rand()%4 == 0) //平方 80 81 need = true; 82 ss << "^2"; 83 84 85 //生成后续运算符与操作数 86 for (int i = 0; i < operateNum; i++) 87 88 char c = g_operators[rand()%4]; //运算符 89 ss << c; 90 91 if (level == 1 && (rand()%4 == 0 || (!need && i == operateNum-1 && rand()%2 == 0))) //根号 92 93 need = true; 94 ss <<"√"; 95 96 97 leftBracket = false; 98 if (rand()%4 == 0 && i != operateNum-1) //左括号 99 100 ss << ‘(‘; 101 leftBracket = true; 102 bracketNum++; 103 104 105 if (level == 2 && (rand()%4 == 0 || (!need && i == operateNum-1))) //操作数,或者sin(?)cos(?)tan(?) 106 107 need = true; 108 string fun; 109 int num; 110 //不能发生除0的情况,并且tan值要存在 111 do 112 113 fun = g_triFun[rand()%3]; 114 num = g_triNum[rand()%46]; 115 116 while ((c == ‘/‘ && ((fun == "sin(" && num%180 == 0) || (fun == "cos(" && (num+90)%180 == 0))) 117 ||(fun == "tan(" && (num+90)%180 == 0)); 118 ss << fun << num << "°" << ‘)‘; 119 120 else 121 122 ss << 1+rand()%100; 123 124 125 if (level == 1 && rand()%8 == 0) //平方在操作数右边 126 127 need = true; 128 ss << "^2"; 129 130 if (rand()%4 == 0 && bracketNum > 0 && !leftBracket) //右括号 131 132 ss << ‘)‘; 133 bracketNum--; 134 135 if (level == 1 && (rand()%8 == 0 || (!need && i == operateNum-1))) //平方有可能在括号右边 136 137 need = true; 138 ss << "^2"; 139 140 141 while (bracketNum--) 142 143 ss << ‘)‘; 144 145 146 147 ss << ‘=‘; 148 if (g_questions.find(ss.str()) != g_questions.end()) 149 150 return GetOneQuestion(level); 151 152 else 153 154 g_questions.insert(ss.str()); 155 return ss.str(); 156 157
转换为Python代码时会有些不同,因为在个人项目中,只需要考虑出题,而在结对编程中还需要考虑出正确答案与干扰选项。生成题目的流程还是一样的,然后会用到Python的内置函数eval(),函数会把字符串当作正确的表达式来运行,可以借此来获得随机生成的表达式的值,当然前提是在调用eval()函数前要把表达式的根号换成sqrt函数,把圆周率π变成p,其中p=pi,把平方符号换成**2,这样才符合Python的正确表达式形式。通过修改该表达式中某一运算符,分别改成加减乘除,可以得到四个表达式,也就得到四个值,返回四个表达式与四个对应的值。这里没有决定哪个是正确选项,返回之后,程序再生成随机数来决定哪一个表达式是正确答案。
具体Python代码如下:
1 operators = [‘+‘, ‘-‘, ‘*‘, ‘/‘] 2 triFun = [‘sin(‘, ‘cos(‘, ‘tan(‘] 3 triNum = [‘0‘, ‘π/6‘, ‘π/4‘, ‘π/3‘, ‘π/2‘] 4 5 def createOneQuestion(level): 6 question = ‘‘ 7 questions = [] 8 answers = [] 9 p = pi 10 bracketNum = 0 11 need = False 12 if level==0: 13 operateNum = randint(2,5) 14 else: 15 operateNum = randint(1,5) 16 17 if operateNum==1: 18 if level==1: 19 s = set() 20 while (len(s)<4): 21 if randint(0,7)==0: 22 s.add(‘√(‘+str(randint(1,100))+‘)²‘) 23 elif randint(0,6)==0: 24 s.add(‘√(‘+str(randint(1,100))+‘²)‘) 25 elif randint(0,1)>0: 26 s.add(‘√(‘+str(randint(1,100))+‘)‘) 27 else: 28 s.add(str(randint(1,100))+‘²‘) 29 questions = list(s) 30 for i in range(4): 31 answers.append(eval(questions[i].replace(‘√‘,‘sqrt‘).replace(‘²‘,‘**2‘))) 32 else: 33 s = set() 34 while (len(s)<4): 35 fun = triFun[randint(0,2)] 36 num = triNum[randint(0,4)] 37 while (fun==‘tan(‘ and num==‘π/2‘): 38 fun = triFun[randint(0,2)] 39 num = triNum[randint(0,4)] 40 s.add(fun+num+‘)‘) 41 questions = list(s) 42 for i in range(4): 43 answers.append(eval(questions[i].replace(‘π‘,‘p‘))) 44 45 return questions, answers 46 else: 47 #第一个操作数 48 if randint(0,3)==0: 49 question += ‘(‘ 50 bracketNum += 1 51 if level==1 and randint(0,3)==0: 52 need = True 53 question += ‘√(‘ 54 bracketNum += 1 55 56 if level==2 and randint(0,3)==0: 57 need = True 58 fun = triFun[randint(0,2)] 59 num = triNum[randint(0,4)] 60 while (fun==‘tan(‘ and num==‘π/2‘): 61 fun = triFun[randint(0,2)] 62 num = triNum[randint(0,4)] 63 question += fun+num+‘)‘ 64 else: 65 question += str(randint(1,100)) 66 67 if level==1 and randint(0,3)==0: 68 question += ‘²‘ 69 70 #生成后续运算符与操作数 71 indexs = [] 72 for i in range(0,operateNum): 73 c = operators[randint(0,3)] 74 question += c 75 indexs.append(len(question)-1) 76 77 if level==1 and (randint(0,3)==0 or (not need and i==operateNum-1 and randint(0,1)==0)): 78 need = True 79 question += ‘√(‘ 80 bracketNum += 1 81 82 if randint(0,3)==0 and i!=operateNum-1: 83 question += ‘(‘ 84 bracketNum += 1 85 86 if level==2 and (randint(0,3)==0 or (not need and i==operateNum-1)): 87 need = True 88 fun = triFun[randint(0,2)] 89 num = triNum[randint(0,4)] 90 while ((fun==‘tan(‘ and num==‘π/2‘) or (c==‘/‘ and (((fun==‘sin(‘ or fun==‘tan(‘) and num==‘0‘) or (fun==‘cos(‘ and num==‘π/2‘)))): 91 fun = triFun[randint(0,2)] 92 num = triNum[randint(0,4)] 93 question += fun+num+‘)‘ 94 else: 95 question += str(randint(1,100)) 96 97 if level==1 and randint(0,7)==0: 98 need = True 99 question += ‘²‘ 100 if randint(0,3)==0 and bracketNum>0: 101 question += ‘)‘ 102 bracketNum -= 1 103 if level==1 and (randint(0,7)==0 or (not need and i==operateNum-1)): 104 need = True 105 question += ‘²‘ 106 107 question += ‘)‘*bracketNum 108 # print(indexs)#输出题目的运算符的位置 109 index = indexs[randint(0,operateNum-1)] 110 temp = operators.copy() 111 shuffle(temp) 112 for i in range(4): 113 question = question[:index]+temp[i]+question[index+1:] 114 try: 115 if level==0: 116 answers.append(eval(question)) 117 elif level==1: 118 answers.append(eval(question.replace(‘√‘,‘sqrt‘).replace(‘²‘,‘**2‘))) 119 elif level==2: 120 answers.append(eval(question.replace(‘π‘,‘p‘))) 121 except (ZeroDivisionError, ValueError): 122 answers.append(‘不存在‘) 123 questions.append(question) 124 if len(set(answers))<4: 125 # print(‘有相同答案‘) 126 # for i in range(4): 127 # print(questions[i], answers[i]) 128 return createOneQuestion(level) 129 return questions, answers
做题时会记录正确与否,做完题后会按照百分制输出分数。然后可以退出程序或者继续做题。
经验教训:
在开发图形用户界面的时候,先画出一个软件原型图会使得工作事半功倍,编程界面的时候一下子就完成了。但画完原型图还有一个工作要做,因为是分工合作,需要给出互相调用的接口,命名要一致。比如我做了登陆界面,登陆成功要跳转到选择界面,选择界面是队友在搞,这时候需要调用他写的类,类名要一致,这样当我们编好程后直接导入模块就可以进行测试了。
编写用户界面的时候,最好使用类来编写,这样类成员变量就相当于全局变量,类成员函数之间就可以直接使用类成员变量,而不需要global全局变量,也不需要考虑不同函数摆放的位置。一开始我们直接用函数来生成图形用户界面,但遇到了很多bug,换成类来编写逻辑就十分清晰明了。
复用个人项目实现结对编程项目
一、需求 1、用户注册功能。用户提供手机号码,点击注册将收到一个注册码,用户可使用该注册码完成注册; 2、用户完成注册后,界面提示设置密码,用户输入两次密码匹配后设置密码成功。密码6-10位,必须含大小写... 查看详情
结对编程搭档个人项目分析(代码片段)
看别人的代码,我觉得是一个痛苦又会有所收获的过程,很多和自己的逻辑不相符的算法思路都是皱着眉头硬看下去,但有的完全理解后,转念一想好像又确实没啥毛病,甚至还比自己的思路巧妙了那么一些,拓展了自己下一次... 查看详情
结对编程队友的个人项目代码分析
他的代码是用java在eclipse中编写的,基本实现了老师所要求的功能先说一下优点,优点就是代码精简,一百三十行完成,与我自己的代码相比,尤其是在生成题目的函数上,无疑更加精简并且算法巧妙,其函数只用一个n作为参数... 查看详情
结对编程项目报告
...此次结队编程项目是我和刘明杰共同完成的。此项目是在个人项目的基础上进行的。先前我们的个人项目均是使用C++编写的,考虑到图形界面。我们决定改用Java,且由于先前的C++代码量并不是很大,而且需要改动之前代码的逻... 查看详情
结对编程队友个人项目分析
队友代码分析:优点:1:首先在函数中对账号进行了判断具有良好的扩展性,也方便之后的功能里面增加新的账号,并且进行了注释2.结构的逻辑性良好,根据不同的年级,通过if语句能够跳转到对应的模块进行输出3.代... 查看详情
软工网络16结对编程(代码片段)
...621123011陈瑀https://www.cnblogs.com/eshy/码云记录2、PSP表格PSP2.1个人开发流程预估耗费时间(分钟)实际耗费时间Planning计划3035·Estimate明确需求 查看详情
结对编程---分析搭档个人项目代码
优缺点分析一、个人项目需求命令行输入用户名和密码,两者之间用空格隔开(程序预设小学、初中和高中各三个账号,具体见附表),如果用户名和密码都正确,将根据账户类型显示“当前选择为XX出题”,XX为小学、初... 查看详情
201571030314《小学生四则运算练习软件》结对项目(代码片段)
...和邻宿舍的小伙伴进行了两人结对编程,我们开发的结对项目的是小学生四则运算练习软件,具体就是随机生成n道题,供学生答题并返回正误记录答题结果,进行多轮。具体需求分析以及功能设计与实现如下。 github代码地... 查看详情
201521123072结对编程(代码片段)
...tps://gitee.com/HXY071/four_operations.git1.3结对照片:1.4所选代码个人博客地址5:http://www.cnblogs.com/NianQiFeng,源代码:https://git.coding.net/q 查看详情
网络四则运算结对编程(代码片段)
一、结对信息项目组合郭炜埕201521123065郑晓丽201521123066项目地址(https://gitee.com/vicheng/four_operations/tree/master)二、结对编程1、需求分析原来的代码只实现简单的两位数之间的加减乘除,而我们为需要改进其功能,实现了三位数的计... 查看详情
20165330结对编程项目-四则运算第二周(代码片段)
需求分析实现一个命令行程序,要求:自动生成小学四则运算题目(加、减、乘、除)可实现多个运算符一起运算可以真分数形式输出结果测试结果的正确性统计题目完成数并计算正确率设计思路实验首先是完成一个计算器的功能... 查看详情
软件工程网络15专业结对编程(代码片段)
结对编程作业总览项目成员:黄俊麟201521123022郑子杰201521123021项目码云地址:https://gitee.com/paitouzi/pair_programming/tree/master具体项目分析:1.需求分析本次结对编程,我们自己新编写了一个计算器程序,能够实现简单的加减乘除运算... 查看详情
结对编程作业(代码片段)
...同学尽量找男同学结对,但是不做强制要求;(2).从以往个人完成的项目中选择一个作品,例如:以往的数据结构课程设计或者其它具有比较完整功能的小系统,代码至少要大于100行;(3).将代码上传至个人GitHub或Coding.net系统中,... 查看详情
结对队友个人项目代码分析(代码片段)
项目要求项目名称:中小学数学卷子自动生成程序用户: 小学、初中和高中数学老师。功能: 1、命令行输入用户名和密码,两者之间用空格隔开(程序预设小学、初中和高中各三个账号,具体见附表),如果用户名和... 查看详情
软件工程结对编程博客(代码片段)
...结对编程的章节,明结对编程的优点和缺点。结对的每一个人的优点和缺点在哪里14、PSP表格15、松耦合结对编程博客1、GitHub项目地址项目GitHub地址2、PSP表格PSP2.1PersonalSoftwa 查看详情
结对项目(代码片段)
目录:一、相关地址二、预计在程序的各个模块开发上耗费的时间(psp):三、接口设计四、计算模块接口的设计和实现过程。五、计算模块接口部分的性能改进六、计算模块部分单元测试展示七、模块部分异常处理:八、界面... 查看详情
取长补短——结对编程项目之队友代码分析
...同样的需求,同样的项目,对照自己代码分析队友的代码个人觉得真的是一个很好的学习方法。小到如注释,命名规则一些惯用法,大到整个工程的编码思路甚至整个软件架构,对方好的方面积极吸取,坏的方面则尽量避免(对... 查看详情
结对编程项目总结
...程项目已经做完,总结一下这次做项目的感受。最开始的个人项目我是用c++写的,那个时候还不知道结对编程是做什么内容,结果要做UI,所以我决定把代码转成java,而且c++不能实现短信验证功能。其实在上个学期我们就已经上... 查看详情