第二次结对编程作业
一、链接
- 结对同学的博客链接
- 本作业的博客链接
- Github项目地址
二、具体分工
- 吴之昊:前端和后端的代码
- 杨雨丝:代码测试、性能分析与博客撰写
三、PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
Planning | 计划 | 60 | 30 |
· Estimate | · 估计这个任务需要多少时间 | 60 | 30 |
Development | 开发 | 1960 | 2190 |
· Analysis | · 需求分析 (包括学习新技术) | 600 | 800 |
· Design Spec | · 生成设计文档 | 60 | 50 |
· Design Review | · 设计复审 | 60 | 60 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 60 | 60 |
· Design | · 具体设计 | 300 | 300 |
· Coding | · 具体编码 | 600 | 600 |
· Code Review | · 代码复审 | 80 | 70 |
· Test | · 测试(自我测试,修改代码,提交修改) | 200 | 250 |
Reporting | 报告 | 125 | 140 |
· Test Repor | · 测试报告 | 45 | 60 |
· Size Measurement | · 计算工作量 | 30 | 30 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 50 | 50 |
---- | 合计 | 2145 | 2360 |
四、解题思路描述与设计实现说明
1. 网络接口的使用
- 使用了python的requests库
例子:登录、开始牌局:
def login(username,password):
global token,use
url = "https://api.shisanshui.rtxux.xyz/auth/login"
payload = "{\"username\":"+"\""+username+"\""+","+"\"password\":"+"\""+password+"\""+"}"
headers = {'content-type': 'application/json'}
response = requests.post(url, data=payload, headers=headers)
message = response.json() # 登录
token = message["data"]["token"]
use=message["data"]["user_id"]
print (response.text)
return message
def opengame():
global token
global id
url = "https://api.shisanshui.rtxux.xyz/game/open"
headers = {"X-Auth-Token": token}
response = requests.post(url, headers=headers)
message=response.json()
id=message["data"]["id"]
card=message["data"]["card"]
print(response.text)
return card
2. 代码组织与内部实现设计
Part1.前端
因为有之前画原型的经历,所以很早就开始思考前端的问题,因为没有接触过这方面,刚开始是考虑用html、js和css写,也为了学这三门语言熬夜两天,后来突然惊喜地发现了python有一个模块专门用来写游戏,也就是pygame,可以很方便地实现简单交互,同时python对后端封装函数的调用也非常方便,直接impot as就可了,所以在研究了一个小时以后就决定用pygame实现图形化,然而事情没有那么简单,我很快发现这玩意儿根本没有输入框这个模块(也可能是我没找到),还有一些奇奇怪怪的问题,好在最后还是写出了一个半吊子的前端
- python的图形化界面
- 添加人机交互控件(Button、Text_box等)并编写相应的函数。
- 在主事件循环中等待用户触发事件响应。
- 用pygame写界面
其中主要用的是pygame
- 本次使用的pygame主要涉及模块与函数
函数模块 | 功能 |
pygame.cursors | 加载光标 |
pygame.display | 访问显示设备 |
pygame.draw | 绘制形状、线和点 |
pygame.event | 管理事件 |
pygame.font | 使用字体 |
pygame.image | 加载和存储图片 |
pygame.key | 读取键盘按键 |
pygame.mixer | 声音 |
pygame.mouse | 鼠标 |
pygame.music | 播放音频 |
pygame.overlay | 访问高级视频叠加 |
pygame.rect | 管理矩形区域 |
pygame.scrap | 本地剪贴板访问 |
pygame.sprite | 操作移动图像 |
pygame.surface | 管理图像和屏幕 |
pygame.surfarray | 管理点阵图像数据 |
pygame.time | 管理时间和帧信息 |
pygame.transform | 缩放和移动图像 |
Part2.后端
因为还要打互联网+的原因,时间非常少,一开始抱着只要不相公就行了的想法写后端,输赢随缘,所以一开始只打算写个贪心,但是在巨佬的点拨下,我含着泪写了第二种算法的后端,两种思路主要如下:
- 贪心算法:
只需根据规则写一个选出5张最大牌型的函数,先跑一次从13张内挑出5张最大的作后墩,然后跑第二次将剩下8张中最大的5张作中墩,剩下的3张直接放在前墩,这样实现非常容易,但是经过一晚上测试,我发现这种算法跟我差不多菜,于是先写了一版保底,开始研究其他算法。 - 搜索、权值比对算法:
主要是通过遍历所有情况并比对提前赋好的权值来判断出牌的方案。前中后墩总共13张牌,也就是有(C13 5 x C8 5 x C3 3)种组合,放在同一个list里面,跑一次遍历把所有的组合的情况,结合每种情况的三墩牌判断每墩牌的权值,可以得到一个总的权值,在接到服务器发牌的时候先将其分到三墩的数组中,搜索并赋权值,将所有情况进行比对,选出总权值最大的情况,返回结果。
五、关键代码解释
分堆 : 13张牌,先搜出5张,嵌套再搜5张,剩下3张
def dfs_1(d, index_1): #/ * 枚举组合 * /
for i in range(d,13+1):
s1[i] = 1#标记,防止重复拿取
temp_1[index_1] = poker_1[i]#挑选
if index_1 == r1 :#r1=5,挑选够5张进入下一个dfs_2()函数,架构与dfs_1一样
init_1()#初始化dfs_2()函数,清空等操作
dfs_2(1, 1)
else:
dfs_1(i + 1, index_1 + 1)
s1[i] = 0
统计牌型用桶排序:
for i in range(1,3+1):
hua[ans_3[i].flower] +=1
number[ans_3[i].num] +=1
权值判断与细化:
for i in range(1,4+1):
if hua[i] == 3:
if shunzi3(ans_3[1].num) == 1:
k=(9.0+0.9 / 11.0 * (ans_3[1].num - 1))
score += k
return k # 3张同花顺
for i in range(3,0,-1):
if number[ans_3[i].num] == 1:
x = ans_3[i].num
if number[ans_3[i].num] == 2:
k=(1.0 + 0.9/(130+13)((ans_3[i].num - 1)10+x-1)1.0)
score += k
return k#单对
k=0.9 / (1300.0 + 130.0 + 13.0)((ans_3[3].num - 1) * 100 + (ans_3[2].num - 1) * 10 + (ans_3[1].num - 1))
score += k
return k #散牌
六、性能分析与改进
经过性能分析,发现运行速度较慢
改进:优化了排序dict_init()以及判断函数constrast()
性能分析图:
- 消耗最大的函数:mid 即分配中墩的函数,因为在规则中中墩需要考虑的比较多
七、单元测试
- 单元测试数据来自现有的福建十三水app(各种出牌和对战),为了提高代码的覆盖,我们尽可能的挑选不同的数据进行测试(对各种函数覆盖率高),但是根据写的函数,还是需要手动删除前墩的数据测试中墩,同理测试后墩。
- 设计的数据主要对三个函数进行测试。这三个函数分别是得到前墩、中墩、后墩的三个函数,基于这三个函数的相似性我们只展示其中一个。
class MyTestCase(unittest.TestCase):
def testqian(self):
weig0 = 10
weig1 = 7
weig2 = 6
self.assertEqual(shisanshui.qian(str0), weig0)
self.assertEqual(shisanshui.qian(str1), weig1)
self.assertEqual(shisanshui.qian(str2), weig2)
def testzhong(self):
weig0 = 10
weig1 = 9
weig2 = 8
self.assertEqual(shisanshui.zhong(str0), weig0)
self.assertEqual(shisanshui.zhong(str1), weig1)
self.assertEqual(shisanshui.zhong(str2), weig2)
def testhou(self):
weig0 = 10
weig1 = 9
weig2 = 8
self.assertEqual(shisanshui.zhong(str0), weig0)
self.assertEqual(shisanshui.zhong(str1), weig1)
self.assertEqual(shisanshui.zhong(str2), weig2)
八、贴出Github的代码签入记录
九、遇到的代码模块异常或结对困难及解决方法
问题描述
- 问题1:队友沟通问题
- 问题2:后端算法十分难完善
- 问题3:对python的运用程度突如其来完成这个项目难度大
- 问题4:用python写前端的经验少
做过哪些尝试
- 通过各种聊天软件与队友沟通,了解队友进度
- 对权值的细分以及判读如何出牌只能慢慢写,理清逻辑,在细节上不断完善
- 不停使用搜索引擎,疯狂看博,现学现卖
- 对各种混乱加以命名上的改善,这样能减少错误
是否解决
是
有何收获
在短时间内完成一个没做过的事情固然很难,但是知道了如何在不会的情况下极限运用搜索引擎,更加知道了高效的学习方式,而不是像平时应付考试。和队友的沟通很重要,如果进度不一样,那一方等另一方的后果很严重,所以要及时沟通解决问题,步调一致,才能共同前行。
十、评价你的队友
值得学习的地方:非常乐观
需要改进的地方:希望能多花点心思在学习代码上
十一、学习进度条
第N周 | 新增代码(行) | 累计代码(行) | 本周学习耗时(小时) | 累计学习耗时(小时) |
1 | 93 | 93 | 20 | 20 |
2 | 178 | 271 | 15 | 35 |
3 | 182 | 453 | 45 | 80 |
4 | 125 | 578 | 20 | 100 |