1、队友链接
- 曾世缘: FormerAutumn
- 队员本次作业博客: 地址
- Fork的仓库地址: Seeclong
2、分工
- 我负责UI的编写以及在前端加入api接口与界面交互相连接
- 出牌算法大部分由大哥完成,我负责了其中特殊牌型的判断
3、PSP表格
PSP2.1 | Personal Software Process Stages |
预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 40 |
· Estimate | · 估计这个任务 需要多少时间 |
10 | 20 |
Development | 开发 | 960 | 1250 |
· Analysis | · 需求分析 (包括学习新技术) |
120 | 240 |
· Design Spec | · 生成设计文档 | 30 | 40 |
· Design Review | · 设计复审 | 30 | 20 |
· Coding Standard | · 代码规范 (为目前的开发 制定合适的规范) |
30 | 30 |
· Design | · 具体设计 | 60 | 40 |
· Coding | · 具体编码 | 480 | 360 |
· Code Review | · 代码复审 | 30 | 40 |
· Test | · 测试(自我测试, 修改代码,提交修改) |
180 | 480 |
Reporting | 报告 | 170 | 270 |
· Test Repor | · 测试报告 | 90 | 120 |
· Size Measurement | · 计算工作量 | 20 | 30 |
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
60 | 120 |
合计 | 1160 | 1560 |
4、解题思路描述与设计实现说明
思路描述
- 首先,数据规模为$n=13$很容易想到枚举算法(大概是$O(13^{5} * 8^{5}$)?
貌似也没有限时),只要暴力枚举前中墩的情况即可,因 - 为前中墩枚举结束后,剩余牌自动归为前墩。 - 其次,对于枚举结束之后的三墩,先进行合法性检测,即三墩需满足:前墩$\lt$中墩$\lt$后墩
等号取不到 - 再者,对于合法的一组手牌,我们算出这组牌赢的概率的估计值。对,是概率的估计值,那么如何计算?因为我们偷到了一个权重数组,同时,我们维护一个大小为25的大根堆
队友说25吉利,显然最后堆顶的牌组就是我们考虑的最优组合。 - 最后,发到服务器,等待出分。
设计实现说明
- 爆搜或者10重for的嵌套。简单粗暴,除了久一点,没什么问题。
- 爆搜或者5重for,先选出后墩,再选出中墩。即后中墩是分开选择的。显然可以出解,而且比上一种方法快很多。但是,会出现倒水的情况,即无法保证三墩的大小关系。
- AI算法,笔者没有头绪。
- 最后选择了方法1
因为一开始写的是方法2,发现倒水了,就被队友说服去写方法1了
类图
流程图
5、关键代码解释
#从api请求返回的排行榜数据 # 将json格式转换成单元格内容 item = [(j, c, data[c].values()) for j in range(3) for c in range(len(data))] for v in item: #print('行下标%s,列下标%s,值:%s' % (v[1], v[0], list(v[2])[v[0]])) newitem = QTableWidgetItem(str(list(v[2])[v[0]])) newitem.setTextAlignment(Qt.AlignHCenter | Qt.AlignBottom) if v[0]==1 or v[0]==0: self.tableWidget.setItem(v[1], v[0]+1, newitem) else: self.tableWidget.setItem(v[1], v[0]-2, newitem)
6、性能分析与改进
ncalls tottime percall cumtime percall 64 0.001 0.000 15.890 0.248 Algorithm_fight.py:142(get_battle) 32 0.030 0.001 8.021 0.251 Algorithm_fight.py:155(decode_data) 32 0.001 0.000 3.058 0.096 Algorithm_fight.py:168(my_choose) 800 0.000 0.000 0.000 0.000 Algorithm_fight.py:180(<lambda>) 32 0.001 0.000 7.483 0.234 Algorithm_fight.py:204(send_2_system) 32 0.055 0.002 26.529 0.829 Algorithm_fight.py:221(_start) 1 0.000 0.000 26.530 26.530 Algorithm_fight.py:239(main) 416 0.000 0.000 0.000 0.000 Algorithm_fight.py:29(chg) 1 0.000 0.000 0.000 0.000 Algorithm_fight.py:37(Hands) 50944 0.019 0.000 0.025 0.000 Algorithm_fight.py:38(__init__) 292872 0.034 0.000 0.034 0.000 Algorithm_fight.py:42(__lt__) 32 0.125 0.004 3.056 0.096 Algorithm_fight.py:49(RecommendHands) 1 0.000 0.000 26.767 26.767 Algorithm_fight.py:7(<module>) 1 0.000 0.000 0.000 0.000 GetWeight.py:7(<module>) 50944 0.240 0.000 2.790 0.000 GetWeight.py:99(get_weight)
参数解释:
- ncalls:表示函数调用的次数。
- tottime:表示指定函数的总的运行时间,除掉函数中调用子函数的运行时间。
- percall:(第一个 percall)等于 tottime/ncalls。
- cumtime:表示该函数及其所有子函数的调用运行的时间,即函数开始调用到返回的时间。
- percall:(第二个 percall)即函数运行一次的平均时间,等于 cumtime/ncalls。
- filename:lineno(function):每个函数调用的具体信息
- 其实,撇开网络请求,自我感觉完成得还是不错的。
7、单元测试
class UnitTest(unittest.TestCase): @classmethod def setUpClass(self): pass @classmethod def tearDownClass(self): pass def tst_jdg_pair(self): ct = 0 for i in open('./UnitTest-in.txt').readlines(): ct += 1 nw = []; cards = i.split() for j in cards: nw.append((suit_sa[j[0]],number_sa[j[1:len(j)]])) #print(nw) print("card %d " % (ct), end="") print(jdg_pair(nw)) def tst_jdg_2pairs(self): ct = 0 for i in open('./UnitTest-in.txt').readlines(): nw = []; cards = i.split() for j in cards: nw.append((suit_sa[j[0]],number_sa[j[1:len(j)]])) #print(nw) ct += 1 print("card %d " % (ct), end="") print(jdg_2pairs(nw)) def tst_jdg_triple(self): ct = 0 for i in open('./UnitTest-in.txt').readlines(): nw = []; cards = i.split() for j in cards: nw.append((suit_sa[j[0]],number_sa[j[1:len(j)]])) #print(nw) ct += 1 print("card %d " % (ct), end="") print(jdg_triple(nw)) def tst_jdg_boom(self): ct = 0 for i in open('./UnitTest-in.txt').readlines(): nw = []; cards = i.split() for j in cards: nw.append((suit_sa[j[0]],number_sa[j[1:len(j)]])) #print(nw) ct += 1 print("card %d " % (ct), end="") print(jdg_boom(nw)) def tst_jdg_straight(self): ct = 0 for i in open('./UnitTest-in.txt').readlines(): nw = []; cards = i.split() for j in cards: nw.append((suit_sa[j[0]],number_sa[j[1:len(j)]])) #print(nw) ct += 1 print("card %d " % (ct), end="") print(jdg_boom(nw)) def tst_jdg_flush(self): ct = 0 for i in open('./UnitTest-in.txt').readlines(): nw = []; cards = i.split() for j in cards: nw.append((suit_sa[j[0]],number_sa[j[1:len(j)]])) #print(nw) ct += 1 print("card %d " % (ct), end="") print(jdg_flush(nw)) def tst_jdg_fullhouse(self): ct = 0 for i in open('./UnitTest-in.txt').readlines(): nw = []; cards = i.split() for j in cards: nw.append((suit_sa[j[0]],number_sa[j[1:len(j)]])) #print(nw) ct += 1 print("card %d " % (ct), end="") print(jdg_fullhouse(nw)) test_lists = ["tst_jdg_pair","tst_jdg_2pairs","tst_jdg_triple","tst_jdg_boom","tst_jdg_straight","tst_jdg_flush","tst_jdg_fullhouse"] if __name__ == "__main__": for i in test_lists: suit = unittest.TestSuite() suit.addTest(UnitTest(i)) runner = unittest.TextTestRunner() runner.run(suit)
8、贴出Github的代码签入记录
9、遇到的代码模块异常或结对困难及解决方法
问题描述
曾世缘:
- 结对没有尽早开始写代码,拖延得比较后面。
国庆当然是快乐 - 关于算法结果有冲突。
倒水我是不想重写的
庄锡荣:
- PyDesinger每个页面制作完成后,在页面的切换出现问题,无法通过按钮相互切换
- Mainwindow弹窗功能使用不了
做过哪些尝试
曾世缘:
- 意识到快来不及了,马上动工
233 - 队友说得对,就重写吧。
庄锡荣:
- 查阅别人实现的代码,阅读Pyqt5接口文档
- 根据别人的用法基础上修改,找到能使自己的Mainwindow可以弹窗的用法
是否解决
曾世缘:
+较好解决。显然我们完成了作业,我也解决了倒水。
庄锡荣:
- 解决且实现了弹窗问题和窗口页面相互切换调用
有何收获
曾世缘:
- 队友是个好队友,我就不知道了。
- 学了一下python自带堆heapq的使用
庄锡荣:
- 依旧是觉得做前端很累
- 学习新语言的使用还是要多尝试,在实践中不断踩坑,在踩坑中不断成长
10、评价你的队友
值得学习的地方
- 儒雅随和,不紧不慢。
需要改进的地方 - 老是喊累,不想进取。
11、学习进度条
第N周 | 新增代码(行) | 累计代码(行) | 本周学习耗时(小时) | 累计学习耗时(小时) | 重要成长 |
---|---|---|---|---|---|
1 | 0 | 0 | 10 | 10 | 学会markdown写博客 |
2 | 500 | 500 | 26 | 36 | 学会json格式使用 使用request库调用API |
3 | 0 | 0 | 21 | 57 | 使用Axure进行原型设计 设计出征战十三水原型 |
4 | 600 | 1100 | 16 | 73 | 使用Pyqt进行UI设计 设计出征战十三水UI |
… | … | … | … | … | … |
心得:
曾世缘:
1、感谢我的队友,考虑到我的各种原因,包揽了前端,还写了特殊牌型得判断,最后放我来写我自己最熟悉的算法部分,同时队友也非常体谅我的进度。平心而论,如果这次是个人作业,我可能就完成不了了,或者说只会做出一个非常丑陋的UI界面。
2、一开始想写爆搜,怕爆栈就丢了for上去,确实除了慢点没什么问题,剪了剪枝也没有非常出乎意料的提升。暴力出奇迹,这是我写过最暴力的工程代码,但是却有着极低的编程复杂度。
庄锡荣:
1、这次的结对作业也算为之后的团队作业打下基础吧,自己应该学会如何去管理调整整个项目的进度,合理的发挥每个人的长处,而不是都堆积在一起实现一两个功能。
2、应该尽早开始做提前准备工作,而不是临时开始学习要用的东西,赶工出来的结果一定不会是最优秀的作品。