此作业要求参考:https://edu.cnblogs.com/campus/nenu/2019fall/homework/7631
结对伙伴:刘信鹏
1.项目分析及编程收获
项目说明,本次项目使用了Python作为开发语言,该语言较为简易灵活,对多平台的支持较好。
- 开发环境是 windows
- 开发工具是 pycharm
- Python语言版本为 3.7
- 版本控制选用 Git
1.1 功能一
要求:四则运算:支持出题4个数的四则运算题目
1.1.1 功能一重点、难点
(1)通过判断表达式对应的奇偶数位置来判定该位置是操作数还是运算符,并将操作数和运算符分别封装到两个函数。
(2)通过数据结构中“栈”的概念引入,将中缀表达式转换为后缀表达式,通过对比优先级的不同进行出栈操作,
1.1.2 重要代码展示
重要代码展示1(区分操作数与运算符):
for j in range(4 + 3): if j % 2 == 0: # 随机生成操作数 exp.append(self.generate_operand()) else: # 随机生成运算符 exp.append(self.generate_operation())
重要代码展示2(中缀表达式变为后缀表达式):
def middle_to_after(s): expression = [] ops = [] for item in s: if item in ['+', '-', '*', '/']: while len(ops) >= 0: if len(ops) == 0: ops.append(item) break op = ops.pop() if op == '(' or op_rules[item] > op_rules[op]: ops.append(op) ops.append(item) break else: expression.append(op) elif item == '(': ops.append(item) elif item == ')': while len(ops) > 0: op = ops.pop() if op == '(': break else: expression.append(op) else: expression.append(item) while len(ops) > 0: expression.append(ops.pop()) return expression
重要代码展示3(四则运算的计算过程):
# 四则运算规则 def cal_rules(numb1, numb2, op): if op == '+': return numb1 + numb2 if op == '-': return numb1 - numb2 if op == '*': return numb1 * numb2 if op == '/': return numb1 / numb2 # 计算后缀表达式 def cal_suffix_exp_value(expression): stack_value = [] for item in expression: if item in ['+', '-', '*', '/']: n2 = stack_value.pop() n1 = stack_value.pop() result = cal_rules(n1, n2, item) stack_value.append(result) else: stack_value.append(int(item)) return stack_value[0]
执行效果图:
1.1.3 功能一编程收获
在实现功能一的过程中,使用了本科数据结构中所学习的栈得知识点,在栈的使用和与四则运算的关系上下了很大功夫。在制定四则运算法则是,我们通过把其封装成函数,在调用期间十分方便,整个程序中功能一是基础也是重点,在实现功能一的过程中的经理给予了我和刘信鹏很大的收获。
1.2 功能二
要求:支持括号
1.2.1 功能二重点、难点
(1) 加括号:在功能一实现的同时对功能二加以实现,由于是四则运算所以括号出现次数不会大于2次。
(2)关于括号的的随机出现位置问题,括号的成对生成:由于要保证表达式出现的随机性,所以推断对号最多出现位置为2次,而出现位置为4个,所以可以知道出现括号的情况为10种,我们通过查阅资料了解到可以通过设定矩阵,来对这十种情况进行随机抽取。
1.2.2 重要代码展示
重要代码展示1(如何对括号进行生成):
# 判断是否要括号 if is_need_parenteses: expression = ''.join(self.generate_parentheses(exp)) else: expression = ''.join(exp)
def generate_parentheses(self, exp): expression = []
重要代码展示2(括号的随机生成):
position_matrix = [[-1, 0, 0, 0, 1, 0, 0, 0, 0, 2, 2], [-1, 0, 0, 0, 0, 0, 1, 0, 0, 2, 2], [0, 0, -1, 0, 0, 0, 1, 0, 0, 2, 2], [0, 0, -1, 0, 0, 0, 0, 0, 1, 2, 2], [0, 0, 0, 0, -1, 0, 0, 0, 1, 2, 2], [-1, 0, 0, 0, 1, 0, -1, 0, 0, 0, 1], [-1, -1, 0, 0, 0, 1, 0, 0, 1, 0, 0], [-1, 0, 0, -1, 0, 0, 0, 1, 1, 0, 0], [0, 0, -1, -1, 0, 0, 0, 1, 0, 0, 1], [0, 0, -1, 0, 0, -1, 0, 0, 0, 1, 1] ] # 生成括号表达式 def generate_parentheses(self, exp): expression = [] # 从10种情况中选取一种 position = random.randint(0, 9)
执行效果图:
1.2.3 功能二编程收获
在编程过程中我们出现的最大问题莫过于对于括号的生成的随机性判断,但是通过细心考虑,反复推敲,发现这个问题的实现难度并不大,随机的种类也不是无法操作的,最后通过查阅资料找到了枚举括号位置的可能性的方法,对随机功能成功实现
1.3 功能三
要求:限定题目数量,打印输出,避免重复
1.3.1 重点、难点:
(1)命令行参数限定题目数量,在控制台判断参数中是否含有“-c”并控制生成的题目数量。
(2)打印输出内容写入文件:对输出题目的个数的校验,即输入的个数必须为正整数,小数和负数不符合要求
1.3.2 重要代码展示
重要代码展示1(命令行参数题目数量控制):
def main(argv): a = Test() if '-c' in sys.argv: a._fun3(sys.argv[2]) else: # 要求1、2 a._fun12()
def __init__(self): pass def _f4(self): pass def _fun3(self,num): if num.isdigit() and int(num) > 0: print_exp_result(int(num)) else: print('题目数量必须是 正整数。') return (0) def _fun12(self): num = 20 i = 0 while i < num: mid_experison = Exp_Generator.Generator() generator = mid_experison.generate() print(generator + '= ?', end="") suffix_expression = middle_to_after(generator) value = cal_suffix_exp_value(suffix_expression) answer = input() if '?' in answer: answer = answer.replace('?', '') print_result(float(answer), value) i += 1 print('你一共答对' + str(rightCount) + '道题,共20道题。') return (0) def _fun3(self,num): print_exp_result(num) return (0)
执行效果图:
1.3.3 功能三编程收获
由于在上次作业中对命令行参数有过体验,所以在理解问题上没有花费太多时间,但对于校验题目个数上花费了一定时间,最后结合了很多人的想法完成了功能三。
2.结对编程的体会
由于是我和刘信鹏两个人结对编程,在结对过程中真的有1+1>2的体会,对于一个既有项目,我们各自发挥了各自的优势,会大大提升整体的时间。在遇到问题时,两个人寻找解决方案的效率远远大于1个,刘信鹏编程能力远在我之上,所以本次作业很大程度上要归功于他,所以这里深深感谢他对于本次作业的付出,而我的主要工作则是在整理,发文和理解上。结对编程不仅一定意义上增强了我对于编程的兴趣,更多的时间两个人一起面对问题,一起寻找解决办法,以及对于编程收获的分享都是结对编程的魅力。由于对于结对编程的兴趣,我们俩早早就开始了老师发布的任务,通过满满的两天周末初步完成了该项目(后期可能进行增强和改进)。所以通过本次经历,开阔了思路,也找到了提升效率的方法,在很多方面都有巨大收获。
3.花费时间较长的事件,或收获较大的时间
收获:
3.1 对于任务的分配工作
在进行任务前,我们进行了很久的任务分配工作。对3个功能的编程,测试样例的提出,以及时间的整理,我们都进行了公正的分配。一个好的工作完成,一定是团队里的每个人都发挥出自己的最大优势,而这个项目上我们恰恰是如此。
3.2 功能分析
在正式编程前,我们对老师所布置的作业内容进行,想出特殊的测试用例,穷尽一切找出可能出现bug的可能,虽然整个期间过程很长,但却帮助我们在后续的过程中少走弯路,大大提升了效率。
费时:
3.3 是枚举还是随机
遇到添加括号问题时,起初以为枚举费时费力,最先想到的是随机,但伴随这项目的进行发现实现起来十分困难,所以推到重来进行枚举,最后通过计算得出存在的十种可能,并借助此功能成功完成了功能三。
3.4 关于栈在四则运算的使用
由于对本科学习的数据结构内容有所遗忘,导致在该部分花费了一定时间,通过查阅教材,教程等等,由于逆波兰和栈的使用是重点所以遇到困难我们仍然坚持使用,最后慢慢摸索,实现了该功能。
3.5 研究如何避免生成重复问题
解决的办法在前文的文字和代码中已经有所体现,但在该部分确实花费了较多时间,我们通过积极思考,积极交流,最终找出当下的办法。
4.给出照片1张,包括结对的2位同学、工作地点、计算机,可选项包括其他能表达结对编程工作经历的物品或场景。
工作地点:冬华B 601寝室
使用本人的电脑进行编程
5.Git地址
本次程序的Git地址:https://e.coding.net/secret/ASETest1_3.git