作者:黄浩伟 黄飞越
一 、Github项目地址:
https://github.com/Flying123haha/123.git
二、psp表格:
PSP2.1 |
Personal Software Process Stages |
预估耗时(分钟) |
实际耗时(分钟) |
Planning |
计划 |
30 |
30 |
· Estimate |
· 估计这个任务需要多少时间 |
30 |
30 |
Development |
开发 |
1310 |
1500 |
· Analysis |
· 需求分析 |
120 |
65 |
· Design Spec |
· 生成设计文档 |
60 |
70 |
· Design Review |
· 设计复审 |
40 |
60 |
· Coding Standard |
· 代码规范 |
30 |
40 |
· Design |
· 具体设计 |
100 |
90 |
· Coding |
· 具体编码 |
800 |
900 |
· Code Review |
· 代码复审 |
60 |
80 |
· Test |
· 测试(自我测试,修改代码,提交修改) |
100 |
100 |
Reporting |
报告 |
130 |
150 |
· Test Report |
· 测试报告 |
60 |
80 |
· Size Measurement |
· 计算工作量 |
30 |
30 |
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
40 |
40 |
合计 |
|
1470 |
2320 |
三、效能分析
1、分数处理: 因为题目要求,我们将每个数都当作分数,因此为了提高分数、假分数在题目中的运算,我们创建了一个fracHandle()的函数、专门用于处理分数与字符串的关系,以及分数之间的关系;大大减少了后面判断的功夫,提高了不少的效能。
class fracHandle: def __init__(self): self #分数变为字符串 def fracToStr(self,fraction): numer = fraction.numerator denom = fraction.denominator if denom == 0: return False INT = int(numer / denom) LEFT = numer % denom if LEFT==0 or denom >= numer: return str(Fraction(numer, denom)) else: return str(INT) + '\'' + str(Fraction(LEFT, denom)) #字符串变为分数 def strToFrac(self,string): #如果是带分数 if '\'' in string: fullFrac = string.split('\'') INT = int(fullFrac[0]) NUMERATOR = int((fullFrac[1].split('/'))[0]) DENOMINATOR =int((fullFrac[1].split('/'))[1]) return Fraction((INT*DENOMINATOR+NUMERATOR),DENOMINATOR) elif '/' in string: NUMERATOR = int((string.split('/'))[0]) DENOMINATOR = int((string.split('/'))[1]) return Fraction(NUMERATOR,DENOMINATOR) else : return Fraction(int(string),1) #分数的计算 def fracAccount(self,frac1,frac2,sign): if(sign == '+'): return frac1+frac2 elif(sign == '-'): if frac1<frac2: return False else: return frac1-frac2 elif(sign == '*'): return frac1*frac2 else: if frac2 == 0: return False else: return frac1/frac2
四、代码说明
1、一开始觉得这个题目就不简单,首先我创建了一个erxercise()类获取参数题目数量和题目范围;创建题目中使用了makeExe()函数,创建了两个文件:题目和答案文件,随后我封装了一个类demo_random()随机生成题目,在makeExe()可直接生成一位数并判断生成哪种类型的算题;
import random import time from demo_random import randomMake from fracHandle import fracHandle from isRepeat import testRepeat from fractions import Fraction class exercise : def __init__(self,account = 100,range = 10): self.account = account self.range = range #生成题目 def makeExe(self): localtime = time.asctime(time.localtime(time.time())) #清理文件内容 with open("Exercise.txt", 'w') as exercise_file: exercise_file.write("题目数量 : "+ str(self.account)+ "\t时间 :" + localtime+ "\n") exercise_file.close() with open("Answer.txt", 'w') as Answer_file: Answer_file.close() que_order = 0 repeat = testRepeat() makeQue = randomMake(repeat,self.range) #生成account道题 while que_order < self.account: choose2_3 = 2+random.randint(0,1) #两个数的运算题生成 if choose2_3 == 2: makeQue.question_2bits(que_order+1) #三个数的运算题生成 elif choose2_3 == 3: makeQue.question_3bits(que_order+1) que_order+=1
2、对于题目的生成在此就不赘述了,都封装在demo_random()里,但是我们在式子中是假设所有的数都为分数,因此使用在这个类中我封装了random_frac()并且为了方便封装了random_sign()随机生成分数;话就嫌多,直接上带有注释的代码
def random_sign(self): randomSign = random.randint(0, 3) if randomSign == 0: sign = '+' elif randomSign == 1: sign = '-' elif randomSign == 2: sign = '*' else: sign = '÷' return sign #随机生成分数 def random_frac(self): while(True): numer = random.randint(0, self.range) # 分子 dno = random.randint(1, self.range) # 分母 Num = Fraction(numer, dno) if Num: break return Num
3、在查重方面,我在随机生成的函数中使用了两个字典分别时Numberlist和signlist用于记录每一次的符号和数字,放入isrepeat()类的两个列表,每次生成题目都会使用这两个列表进行查重、以便使生成的题目不可能是相同的。
class testRepeat: def __init__(self): self.oldNumber = {} #已有的数字组合 self.signDic = {} #已有的符号组合 #检测是否式子重复 def isRepeat(self,numberList,signList): numberList.sort() signList.sort() if self.oldNumber: for key,value in self.oldNumber.items(): if value==numberList and self.signDic[key]==signList: return False self.oldNumber[key+1] = numberList self.signDic[key+1] = signList else: self.oldNumber[0] = numberList self.signDic[0] = signList return True
4、在核对答案时,我在exercise()中封装了confirmExe()的函数分别判断各种类型的题目、从而获取其答案,对于位数为2的题目会比较简单就不赘述了;对位数为3的题目,就需要先判别其括号的位置从而获取其中的式子中的优先级、代码较多因此在此不赘述了。
五、设计实现过程
六、测试运行
总体测试
(1)在命令行中对-n、-r 输入范围,产生所需的题目
(2)在文件中产生问题与答案文档
(3)用户产生答案文档进行校队,产生答题情况文档
多个测试用例
(1) 改变参数-n,-r的值
(2) 产生10000题目
(3)做一部分题目,进行校对
确认程序正确的原因:
(1)多次测试程序未出现重复题目以及未出现错误
(2) 使用多文件校对答案出现预期结果
(3) 给予很多用户使用,未出现不良反应
七、项目小结
我是黄飞越,通过软件工程我获取了第一次做结对项目的机会;这次做项目直接感受就是这个结对大法是真的好、首先它增进我和同伴的友谊,以前我和这位同伴是不太相熟的人,但从此形影不离;其二,结对项目能大大增快项目的历程,通过与同伴的分工,我再也不会打码打得头晕从而造成了编程的瓶颈、除此,在项目在暂停许久后再次开始时我与同伴交流能很快的进入这个程序的分析状态;其三,结对项目能很好地中和我与同伴间的性格,取长补短,就比如说在这次项目中:我时不时对项目的进展会有所担忧,而浩伟哥就很好心态地安慰我、当浩伟哥拖延症不想做项目时,我就会催促他让他拜托拖延快点做。因此,这次结对项目真是让我受益匪浅啊!很期待下次的结对项目!!!
----------------------------------------------------------------------------------------------------------------------------------------------------------------
我是黄浩伟,在软件工程作业的驱动下进行第一次结对项目,以前都是自己书写代码,这次和同伴合作才知道制作一个软件并没有自己一人写代码那么容易,要考虑到彼此的能力以及对同一项目的同一分析、分配任务、完成项目。按理说两个人写代码效率应会更快,但事实却没有,可能是不够熟悉结对合作的流程,但这次后,有了经历,之后与别人的合作会更加流畅。这次结对项目,受益匪浅。