Individual projects reuse code for pair programming project

Preface:

  In the individual event, the early realization of small high math topic and requires only command-line program, but needs to pair programming with a graphical user interface, and the user object is no longer out of the question the teacher, but the beginning of a small high students. Because in the individual event, the two were using C ++ and Python language written in C ++ and feel of the graphical user interface obscure, all unanimously decided to use Python to develop pair programming project, using tools for Python comes with Tkinter

 

Pair programming project requirements:

user:

  Elementary, middle and high school students.

Features:

  1, user registration function. The user's phone number, click on the registration will receive a registration code, the user can use this registration code to complete the registration;

  2, after the completion of user registration, password prompt interface, user input password matches the password twice after the success. Password 6-10, the case must contain letters and numbers. Users can change the password, enter the correct password in the log in the original state, change your password after successfully re-enter the same new password twice;

  3, after the password has been set, jump to the selection interface, display interface elementary, middle and high school three options, the user clicks on one of them, prompting the user to enter the number of items need to be generated;

  4, the number of items the user input, generating a piece of paper (with a roll can not have the same title, all entitled multiple choice), the interface displays the first question and casual working four options, the user selects one of the four options submission interface displays the second question, ... until the last question;

  5, after the submission of the last question, the display interface, the score is calculated based on the percentage of correct answers;

  6, the user interface can opt out of the score or continue to do problems;

  7, small high math problem and asked to see the beginning of a personal project.

 

Project Prototype:

  Before the official start, we drew on paper first software prototype map, as follows:

 

 

 

   With a red line which the project is divided into three parts, two of the division of writing

 

The first part, visit:

  The failure to grasp the handle of the database, save the account password when using an Excel spreadsheet to achieve

  在登陆界面只会验证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,换成类来编写逻辑就十分清晰明了。

Guess you like

Origin www.cnblogs.com/wwht233/p/11587547.html