1.相关链接
[结对同学博客连接]
https://www.cnblogs.com/panther0416/p/11754419.html
[本作业博客连接]
https://www.cnblogs.com/lylinyi/p/11768104.html
[Github项目地址]
https://github.com/panther0416/13water
2.具体分工
潘松波:负责前端实现、博客撰写
林逸:负责后端算法、接口编写
3.PSP表格
- 潘松波
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 30 |
·Estimate | ·估计这个任务需要多少时间 | 1250 | 1600 |
Development | 开发 | 300 | 360 |
·Analysis | ·需求分析 (包括学习新技术) | 120 | 240 |
·Design Spec | ·生成设计文档 | 60 | 120 |
·Design Review | ·设计复审 | 30 | 40 |
·Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 60 | 60 |
·Coding | ·具体编码 | 300 | 400 |
·Code Review | ·代码复审 | 90 | 90 |
·Test | ·测试(自我测试,修改代码,提交修改) | 90 | 90 |
Reporting | 报告 | 60 | 60 |
·Test Repor | ·测试报告 | 60 | 60 |
·Size Measurement | · 计算工作量 | 20 | 20 |
·Postmortem & Process Improvement Plan | ·事后总结, 并提出过程改进计划 | 30 | 30 |
合计 | 1250 | 1600 |
- 林逸
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 30 |
·Estimate | ·估计这个任务需要多少时间 | 2000 | 2400 |
Development | 开发 | 300 | 360 |
·Analysis | ·需求分析 (包括学习新技术) | 120 | 240 |
·Design Spec | ·生成设计文档 | 60 | 45 |
·Design Review | ·设计复审 | 30 | 40 |
·Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 60 | 60 |
·Coding | ·具体编码 | 840 | 1095 |
·Code Review | ·代码复审 | 90 | 90 |
·Test | ·测试(自我测试,修改代码,提交修改) | 300 | 300 |
Reporting | 报告 | 60 | 60 |
·Test Repor | ·测试报告 | 60 | 60 |
·Size Measurement | · 计算工作量 | 20 | 20 |
·Postmortem & Process Improvement Plan | ·事后总结, 并提出过程改进计划 | 30 | 30 |
合计 | 2000 | 2400 |
4.解题思路描述与设计实现说明
网络接口的使用
调用 requests库中的get/post函数实现get/post请求,把如登录、注册等等操作所需要的请求封装成 不同函数放在一个api.py文件下,使用时导入此文件就可以起飞了。
requests基本用法简单方便,易于上手。
下面以获取对战详情为例
def get_detail(token, id):
url = "http://api.revth.com/history/{}".format(id)
header = {
"X-Auth-Token": token,
}
response = requests.get(url, headers=header)
print(response.text)
re_js = response.json()
if re_js["status"] == 0:
return re_js
else:
return False
代码组织与内部实现设计(类图)
-
后端算法代码组织与内部实现设计
-
前端代码组织与内部实现设计
利用qt dersigner 将设计好的界面自动转化为py文件,每张界面都有对应的py文件,再自己编写运行窗口和连接服务器的代码,将各界面的代码模块结合在一起,并进行修改、美化。
说明算法的关键与关键实现部分流程图
- 算法关键
- 普通牌型的判断算法(部分):
def is_tpair(self): cnt = 0 max_num = -1 for i in range(len(self.cnt_num)): if self.cnt_num[i] == 2: cnt += 1 max_num = (i if (i > max_num) else max_num) if cnt == 2: return max_num return False def is_triple(self): for i in range(len(self.cnt_num)): if self.cnt_num[i] == 3: return i return False def is_straight(self): for i in range(len(self.card) - 1): if self.card[i][1] + 1 != self.card[i + 1][1]: return False return self.card[len(self.card) - 1][1] def is_TongHua(self): for i in self.cnt_color: if i == 5: return max(self.card, key=takeSecond)[1] return False
- 遍历算法
max = -1 ans = [] iterator = itertools.combinations(card_list, 5) for iter in iterator: card1 = list(iter) tmp_card = card[:] for c in card1: tmp_card.remove(c) iterator2 = itertools.combinations(tmp_card, 5) for iter2 in iterator2: card2 = list(iter2) tmp_card2 = tmp_card[:] for c in card2: tmp_card2.remove(c) card3 = tmp_card2 n1 = get_weight(2, card1) n2 = get_weight(1, card2) n3 = get_weight(0, card3) if (n1 > n2 and n2 > n3): if(n1[2] + n2[2] + n3[2] > max): ans = card3 + card2 + card1 max = n1[2] + n2[2] + n3[2]
- 普通牌型的判断算法(部分):
5.关键代码解释
-
后端:
- 牌型判断放在pattern.py文件中,每次判断牌型创建一个Card对象,并对该对象进行初始化,cnt_color存放花色,cnt_num存放牌的数值。避免了每次判断牌型时的重复计算。
- 遍历算法没啥特别的地方,主要就是排列组合遍历三墩所有可能的牌组,再计算每一种牌组获胜概率,三墩获胜概率之和最大的就是最优结果。这里用到了itertools库来遍历牌的所有组合。
-
前端:
- 利用分别用各界面的代码模块新建窗口类,需要跳转到某个窗口时再实例化,新建对象,显示在主窗口上。
6.性能分析与改进
改进的思路
原先算法经过服务器的测试发现得分情况一般,后来又看了下十三水得分规则,根据不同牌型的得分情况不同,对权值计算进行了优化。
对于一部分不需要遍历的情况做了跳过处理。
性能分析图和程序中消耗最大的函数
由图可见solve函数消耗最大,程序的时间主要都花在牌型的遍历以及计算权值上。
7.单元测试
-
下图是测试用到的函数,代码比较长,限于篇幅不全展开
-
主要代码展示
import unittest from pattern import Card class TestCard(unittest.TestCase): def test_is_tcpair(self): cards = [(1, 2), (1, 2), (1, 3), (0, 3), (2, 5)] c = Card(cards) self.assertEqual(c.is_tcpair(), 3) def test_is_pair(self): cards = [(1, 2), (1, 2), (1, 3), (0, 4), (2, 5)] c = Card(cards) self.assertEqual(c.is_pair(), 2) cards2 = [(1, 2), (1, 9), (1, 3), (0, 4), (2, 5)] c = Card(cards2) self.assertFalse(c.is_tcpair()) def test_is_triple(self): cards = [(1, 2), (1, 2), (1, 2), (0, 5), (3, 8)] c = Card(cards) self.assertEqual(c.is_triple(), 2) if __name__ == '__main__': unittest.main()
-
测试结果:
-
8.Github的代码签入记录
9.遇到的困难及解决方法
困难描述 | 解决尝试 | 是否解决 | 有何收获 |
---|---|---|---|
界面开发工具的选择 | 先是学习了html和css,但是后来由于我队友先用python写好后端,该路pass,听团队的小伙伴说qypt5可以自动转为py文件,就确定用该工具 | 是 | qypt5通过拖拽形成ui文件,并且可以通过PYUIC转为py文件,这个非常方便,不用狂打代码 |
QT dersigner 全英文 | 寻找汉化包 or 自我适应 | 是 | 汉化包很多需要money,下载了一个不用money,但是配置一直出问题。最后就是提高英语水平 |
排行榜、历史战局、登录注册要从服务器得到数据并展示 | 查找资料、询问大佬、求助队友 | 是 | 这部分我感觉是前端部分最吃力的,要自己写,问题很多,但我对如何从服务器获取数据有了更加深入的了解 |
如何设计算法实现最优牌型的选择 | 第一想法是贪心,但是后来仔细想想贪心并不能保证最优,只能接近最优,后来想到组合数,并尝试解决 | 是 | 学习了组合数算法,但是没有自己造出轮子,有点遗憾,不过不得不说py确实方便,调个itertools库,直接起飞 |
10.评价队友
- 评价人:潘松波
-
值得学习的地方:无时无地不在学习新知识并敲代码
-
需要改进的地方:无,真的挺好的了
-
- 评价人:林逸
-
值得学习的地方 : 很强,学习新知识的速度很快
-
需要改进的地方 : 太强了让人太有压力
-
11.学习进度条
- 潘松波
第N周 | 新增代码(行) | 累计代码(行 | 本周学习耗时(小时) | 累计学习耗时(小时) | 重要成长 |
---|---|---|---|---|---|
1 | 0 | 0 | 10 | 10 | 对项目的需求分析和原型设计的了解更深,学习使用原型分析工具 |
2 | 0 | 0 | 5 | 15 | 学习pyqt5基本知识 |
3 | 323 | 323 | 10 | 25 | 学习使用qtdesigner,着手设计界面 |
4 | 554 | 877 | 15 | 40 | 深入学习pyqt5,完善设计界面,尝试从服务器获取数据,修改代码 |
- 林逸
第N周 | 新增代码(行) | 累计代码(行 | 本周学习耗时(小时) | 累计学习耗时(小时) | 重要成长 |
---|---|---|---|---|---|
1 | 0 | 0 | 10 | 10 | 对项目的需求分析和原型设计的了解更深,学习使用原型分析工具 |
2 | 0 | 0 | 5 | 15 | 构思算法 |
3 | 382 | 382 | 45 | 60 | 学习py,初步实现特殊牌型的判断算法 |
4 | 733 | 1105 | 45 | 90 | 通过对牌型的组合比较,实现普通牌型的最优判断算法 |