一、实验目标
1)体验敏捷开发中的两人合作。
2)进一步提高个人编程技巧与实践。
二 、实验内容
1)根据以下问题描述,练习结对编程(pair programming)实践;
2)要求学生两人一组,自由组合。每组使用一台计算机,二人共同编码,完成实验要求。
3)要求在结对编程工作期间,两人的角色至少切换 4 次;
4)编程语言不限,版本不限。建议使用 Python 或 JAVA 进行编程。
三、队员信息
称 |
队员 |
博客地址 |
GitHub仓库地址 |
选择课题 |
XYZ |
王慧 |
生命游戏 |
||
叶啟文 |
四、代码规范
参考:https://www.cnblogs.com/niansi/p/7751374.html
1.代码编排
a.缩进。4个空格的缩进(编辑器都可以完成此功能),不使用Tap,更不能混合使用Tap和空格。
b.每行最大长度79,换行可以使用反斜杠,最好使用圆括号。换行点要在操作符的后边敲回车。
c.如无特殊情况,文件一律使用UTF-8编码。
2.文档编排
a.模块内容的顺序:模块说明和docstring—import—globals&constants—其他定义。其中import部分,又按标准、三方和自己编写顺序依次排放,每组之间空一行。
b.不要在一句import中多个库
3.空格的使用(总体原则,避免不必要的空格。)
a.逗号、冒号、分号前不要加空格。
b.操作符左右各加一个空格,不要为了对齐增加空格。
c.不要将多句语句写在同一行,尽管使用‘;’也不允许。
4.注释(总体原则,错误的注释不如没有注释。)
a.块注释,在一段代码前增加的注释。在‘#’后加一空格。段落之间以只有‘#’的行间隔。
b .行注释,在一句代码后加注释。
c. 至少使用两个空格和语句分开,避免无谓的注释。
5.命名规范
a. 尽量单独使用小写字母‘l’,大写字母‘O’等容易混淆的字母。
b.函数命名使用全部小写的方式,可以使用下划线; 常量命名使用全部大写的方式,可以使用下划线。
c.类名使用驼峰命名风格,首字母大写,私有类可用一个下划线开头。
五、程序的总体设计
六、结对编程过程
我们小组通过QQ屏幕分享来通过实现代码编程,通过在GitHub上托管代码来实现代码保存与更新。
1.针对python代码讨论代码规范
2.针对代码不同模块进行结对编程
交互 |
驾驶员 |
观察员 |
编程内容 |
第1次 |
王慧 |
叶啟文 |
细胞生命初始化模块 |
第2次 |
叶啟文 |
王慧 |
游戏规则设置模块 |
第3次 |
王慧 |
叶啟文 |
接收动图长度值 |
第4次 |
叶啟文 |
王慧 |
绘制动图模块 |
第5次 |
王慧 |
叶啟文 |
代码升级,实现地图从N* N到N* M |
第6次 |
叶啟文 |
王慧 |
代码优化,删除冗余代码、简化注释等 |
部分过程记录:
七、功能模块
1.细胞生命初始化模块
# 初始化细胞生命状态 def randomGrid(N):# returns a grid of NxN random values return np.random.choice(vals, N * N, p=[0.2, 0.8]).reshape(N, N)
2.游戏规则设置模块
#更新细胞生命状态 def update(frameNum, img, grid, N): newGrid = grid.copy() for i in range(N): for j in range(N):# 检测网格的8个边缘。用取模运算符让值在边缘折返 total = int((grid[i, (j - 1) % N] + grid[i, (j + 1) % N] + grid[(i - 1) % N, j] + grid[(i + 1) % N, j] + grid[(i - 1) % N, (j - 1) % N] + grid[(i - 1) % N, (j + 1) % N] + grid[(i + 1) % N, (j - 1) % N] + grid[(i + 1) % N, (j + 1) % N])) if grid[i, j] == ON: if (total < 2) or (total > 3): newGrid[i, j] = OFF else: if total == 3: newGrid[i, j] = ON # update data img.set_data(newGrid) grid[:] = newGrid[:] return img
3.绘制动图模块
# declare grid grid = randomGrid(N) parser = argparse.ArgumentParser() parser.add_argument('--interval', dest='interval', required=False) # 设置动画更新间隔的毫秒数 args = parser.parse_args() # 设置动画 fig, ax = plt.subplots(facecolor='Lavender') # 配置 matplotlib 的绘图和动画参数 img = ax.imshow(grid, cmap=cmap,interpolation='nearest') # 用plt.show()方法将这个矩阵的值显示为图像,并给 interpolation 选项传入'nearest'值,以得到尖锐的边缘(否则是模糊的) ani =animation.FuncAnimation(fig, update, fargs=(img, grid, N,),frames=10,interval=50,save_count=50) # animation.FuncAnimation()调用函数 update(),该函数在前面的程序中定义,根据命游戏的规则更新网格。 plt.show()
4.接收动图长度值
print("请输入一个地图的大小值:") N = input() try: if N and int(N) > 8: N = int(N) except ValueError: print('The input is not a number!') sys.exit(0)
5.代码升级,实现地图从N* N到N* M
# set grid size print("请输入一个地图的长与宽:") M = input() N = input() try: if M and int(M) > 8: M = int(M) if N and int(N) > 8: N = int(N) except ValueError: print('The input is not a number!') sys.exit(0)
# 实现环形边界条件 def update(frameNum, img, grid, N ,M): newGrid = grid.copy() for i in range(N): for j in range(M): # 检测网格的8个边缘。用取模运算符让值在边缘折返 total = int((grid[i, (j - 1) % M] + grid[i, (j + 1) % M] + grid[(i - 1) % N, j] + grid[(i + 1) % N, j] + grid[(i - 1) % N, (j - 1) % M] + grid[(i - 1) % N, (j + 1) % M] + grid[(i + 1) % N, (j - 1) % M] + grid[(i + 1) % N, (j + 1) % M])) if grid[i, j] == ON: if (total < 2) or (total > 3): newGrid[i, j] = OFF else: if total == 3: newGrid[i, j] = ON # update data img.set_data(newGrid) grid[:] = newGrid[:] return img
结果显示:
1.输入参数有误时:
2.N*N的动图
3.N*M的动图
4.动图显示为:
八、项目github地址
commit记录:
九、问题解决
1.python模块下载慢
此次实验中我们用到了numpy和matplotlib两个模块,但是在python的官方网站下载模块不仅速度特别慢,中途还会无缘无故发生无法下载的情况。为了下载这两个模块我们花了比较长的时间,也尝试过在CSDN中下载,最后终于下载过来。
2.python安装模块pip需升级
参考教程我先在python中安装模块(在cmd中进入python安装的文件位置,输入命令:python -m pip install numpy),结果报错提示:pip需要先升级。
根据提示我输入命令:python -m pip install --upgrade pip,但是更新到一半又报错了。后查找资料,有博主给出新的命令:python -m pip install -U pip,但是执行还是在中途中断。
最后看见别人说命令需要多尝试几次,我用系统提示的命令运行了3、4次后,最终pip升级成功。
接下来进入python的scripts中安装两个模块都成功了。
3.pycharm安装模块报错
参考在pycharm中导入模块的教程,我在本次实验的项目中安装两个模块,但是一直不成功。参考很多教程后,找到了问题所在:由于python与pycharm安装路径不同,导致pycharm的sys.path中少了三个重要的路径。
解决方法为:file->setting->project->Project Interpreter-> 小齿轮 ->Show All-> 加号->System Interpreter->找到python安装文件中的python.exe->点击确定。然后再导入两个模块即可。
4.无法生成动态地图
每次执行代码,结果都只显示一张静态图,我们一直以为是代码有问题。针对绘制动图的animation模块的函数,我们在详细学习后还是找不到问题出现的原因。最后查找资料发现pycharm只显示一帧的解决方案,通过设置后成功显示动图。
5.设置地图长宽颠倒
在升级代码从N*N的地图到N* M的地图时,我们以N为长(横轴),M为宽(纵轴)来执行时,在游戏规则模块发现有数组下标越界的情况,且结果显示的一张静态图的长与宽与我们设想的不一致,所以我们发现长与宽颠倒了。我们将NM交换后,运行成功。
例:我们输入长N为20,宽M为30,结果报错下标越界,长宽颠倒了。
十、实验总结
1.在进行代码编辑之前的准备工作,我们就面临了很多问题,比如模块下载不成功、模块导入不成功等。寻找能正真解决问题的方法也比较漫长,不是方法不适用就是方法不正确,我们参考多个平台(百度、CSDN、博客园等)最终找到解决问题的方法。在成功导入模块之后,我们感觉之前所遇到的问题都不算什么,遇到错误不要怕也不要烦躁,主动去了解都能解决,不要把问题看得过于困难,正是因为我们不懂才会觉得难。解决问题的过程中,我们学习到很多,不仅仅是理论知识,更多的是解决问题的方法与面对错误时的态度。
2.由于之前学习python只是比较浅显的知识,对于实验中导入的numpy和matplotlib模块了解甚少,所以即使是在参考别人的代码时理解起来还是比较吃力。遇到不会的函数通过查资料,理解其中每个参数的作用,由来及去向,疏通了整个代码的实现流程。在理解得基础上,我们通过调试代码,删除冗余的数据,简化复杂的代码,增加注释最后使代码实现更高效。我们还成功将地图从固定的大小升级为自定义的地图大小。
3.最终我们的代码实现只有仅仅六十几行,相对比其他代码而言是非常简洁的,可以发现python在可视化方面有着很大的功能与作用。
结对编程第一阶段:https://www.cnblogs.com/yqw0710/p/12542668.html
参考文献:
1、python模块下载地址:https://pypi.org/project https://www.lfd.uci.edu/~gohlke/pythonlibs
2、pip升级解决:https://blog.csdn.net/lanluyug/article/details/82878152
3、python numpy安装方法:https://blog.csdn.net/swjian1997/article/details/82027013?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
4、pycharm中导入模块报错解决:https://www.cnblogs.com/zhiyuanxiong/p/8948500.html
5、python设置执行参数argparse介绍:https://blog.csdn.net/Samaritan_x/article/details/84146029
6、python绘制动图animation模块的使用:https://blog.csdn.net/u013180339/article/details/77002254
7、pycharm 无法显示动态图片解决:https://www.jianshu.com/p/c6b362fde21c