个人项目复用代码实现结对编程项目

前言:

  在个人项目中,实现小初高数学出题程序只需要命令行,但在结对编程中需要带图形用户界面,并且用户对象不再是出题老师,而是小初高学生。因为在个人项目中,两人分别使用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,换成类来编写逻辑就十分清晰明了。

原文地址:https://www.cnblogs.com/wwht233/p/11587547.html

时间: 2024-10-06 23:20:27

个人项目复用代码实现结对编程项目的相关文章

复用个人项目实现结对编程项目

项目需求 注册功能:用户提供手机号码获取验证码,验证码正确后可以设置登录密码. 修改密码:输入正确原密码,两次输入相同新密码,即可成功修改密码. 显示分数:最后一题提交后,显示得分和答对题数百分比. 退出系统:在获取得分后可以选择退出系统或者继续做题. 项目实现问题回顾 结对编程的项目实现了用户友好的UI界面,基本上实现了项目需求,但这过程中也遇到了一些相对棘手的问题,下面举例说明. 注册功能: 这一部分是我们俩都遇到很大问题的一个模块,即短信验证码如何处理,最后我们调用了阿里云的短信服务API

结对编程项目:带UI的小初高数学学习软件

用户: 小学.初中和高中学生. 功能: 1.用户注册功能. 2.登录,修改密码 3.在线做题,评分 经验总结 这次的结对编程并没有实现对个人项目的复用,经过对结对编程需求的分析发现个人项目的出题逻辑完全不能用于小初高数学学习软件, 因为在个人项目中的出题逻辑是几乎是采用的完全随机,在结对编程项目中这种逻辑是行不通的,没有办法采用答案,而且在个人项目中我们 都是采用的面向过程的方法,同时我们的个人项目结构也有点混乱,导致了复用的难度很大.所以我们完全重新写了代码,实现了登录/注测, 修改密码,选择

结对编程项目的反思总结

此次的结对编程项目是对个人项目的一次升级,在个人项目的需求上加入了新的需求——界面.注册和验证码发送. 界面的编写难度并不高,如果真的要说难点的话,那就是繁杂的界面布局和按钮功能的实现以及各种界面出现的触发逻辑.另外,对于运算结果及选项生成的逻辑我也选择了放在界面的实现中,而生成题目的方法则复用了队友陈建航的题目生成逻辑.计算答案的逻辑我在对应的界面类中另写了一个函数,采用了递归的方式,先算括号,并将括号和括号中的表达式替换为相应的数. 用户注册的实现则采用了文件输入输出流的方式,将用户的信息存

软件工程导论——结对编程项目总结

结对编程总结 1.关于复用个人项目实现结对编程项目 在与结对伙伴的讨论后,决定了各自负责的需求,那么我负责的是实现生成试卷以及答题窗口.对比个人项目,我需要实现的功能是显示一个答题窗口,而且每次显示一题,在答完了一题之后才可以进行答下一题,直到答完最后一题,点击提交试卷就会显示试卷分数.所以如何复用呢?相对于在个人项目中直接的生成试卷并写在txt文件中,这一次我把试卷题目和答案存储在一个二维字符串数组里,并且把生成试卷的方法以及显示窗口的方法写在两个类中,在显示窗口的类中调用生成试卷的类并实现其

结对编程项目——四则运算

1. 结对编程项目---四则运算 (10分) 基本功能要求: 1) 实现一个带有用户界面的四则运算.2) 生成的题目不能重复.3) 支持负数,例如-1,-1/2,-3‘4/5等.(达成) 需要支持的基本设定参数 1) 题目的数量  2) 数值的范围  3) 题目中最多几个运算符(目前没有达成)  4) 题目中或运算过程中有无有分数(比如进行整数除法的时候不能除尽) 5) 题目中是否有乘除法  6) 题目中是否有括号 (目前没有达成) 7) 题目中或运算过程中有无负数         学习感受:

结对编程项目(除附加题)开发过程

结对编程项目(除附加题)开发过程 结对同伴:李云涛 一.照片 结对同伴在家,等回校后补上. 二.结对编程评价 优点: 1.两个人的编程思想.算法.代码风格可以互相借鉴和学习,对于两人的编程水平的提高都很有帮助. 2.两个人可以分工写不同的相对独立的模块,加快开发的进度. 3.自己程序的bug可能自己怎么找都找不到,而自己的同伴就能很快找到. 缺点: 有些工作必须得两人在一起才能进行,而两人都空闲的时间不是太多,很多时候需要通过线上进行交流,导致工作被耽搁. 我自己的优点:做事认真.有恒心.有学习

在复杂的项目开发中使用结对编程

在复杂的项目开发中使用结对编程 卢占辉译 在开发软件项目时,不仅写出相应功能的模块很重要:确保写出的模块的易维护性(bug 修复,代码重构)也同样重要. 主打互联网技术和门户网站的Perpetuum 手机公司曾开展了一个长期的软件项目,以研制出一套基于web的内容管理软件.Perpetuum公司的许多开发者都参与了这个项目.项目中大部分复杂的模块都是完全靠个人开发的(非多人协作完成).维护这些模块(即非多人协作完成的模块)非常困难.因为开发某一模块的人还需要开发新的模块或者维护另一既有模块,这需

结对编程项目——电梯调度

电梯调度 现有一新建办公大厦,共有21层,共有四部电梯,所有电梯基本参数如下表所示: 电梯编号 可服务楼层 最大乘客数量 最大载重量 1 全部楼层 10 800 kg 2 单层 10 800 kg 3 双层 20 1600 kg 4 全部楼层 20 2000 kg 其使用规定如下: 1.楼层号为0~20,其中0号为地下一层: 2.有楼层限制的电梯不在响应楼层停靠,如单双层: 3.所有电梯采用统一按钮控制 请根据上述要求设计并实现一个电梯控制程序,如果有图形显示就更好了. 伙伴介绍与评价: 本次结

课后作业-结对编程项目总结

经过一个多月的时间,结对编程项目已经接近了尾声,通过软件工程这门课,让我和我的搭档学会了如何合作,如何一起处理bug,如何结对编程. 我们所做的项目是利用python自带的pygame来编写一个小程序贪吃蛇,这个游戏我们大概分为了以下个步骤,并且逐一实现,现在就来总结一下: 1.窗口和方块:首先每一个游戏必备的步骤就是主循环以及一个背景,所以我们首先做一个背景以及蛇头的初步实现,代码如下: game_screen = pygame.display.set_mode((game_screen_wi