• 第二次结对编程作业


    一、

    二、给出具体分工

    鲍冰如:主要负责后端代码,一些前端,对算法进行性能分析,进行单元测试,以及博客除接口部分外的撰写
    苏凯婷:主要负责前端代码,写出主要框架,美化页面并且进行定位和交互处理,接口的使用,以及博客的接口部分
    第一次做游戏完全没经验,所以一开始我们的分工不是很明确,前端和后端有些是一起做的,但是后来我们逐渐确定了需求,进一步分工,实现各自负责的部分,并学习需要使用到的技术,接着对完成各部分功能,对代码进行整合,进行性能分析和单元测试,并编写博客。

    三、PSP表格

    PSP2.1 Personnal Software
    Process Stagese
    预估耗时
    (分钟)
    实际耗时
    (分钟)
    Planning 计划 60 75
    * Estimate * 估计这个任务需要多少时间 60 75
    Development 开发 10080 10080
    * Analysis * 需求分析(包括学习新技术) 720 720
    * Design Spec * 生成设计文档 150 150
    * Design Review * 设计复审 50 75
    * Coding Standard * 代码规范(为目前的开发制定合适的规范) 120 150
    * Design * 具体设计 300 500
    * Coding * 具体编码 3000 3000
    * Code Review * 代码复审 200 200
    * Test * 测试(自我测试,修改代码,提交修改) 300 320
    Reporting 报告 100 110
    * Test Repor * 测试报告 60 45
    * Size Measurement * 计算工作量 30 30
    * Postmortem & Process
    Improvement Plan
    * 事后总结,并提出过程改进计划 60 70
      * 合计 15230 15530

    四、解题思路描述与设计实现说明

    (1)网络接口的使用



    (2)代码组织与内部实现设计(类图)




    (3)说明算法的关键与关键实现部分流程图

    算法关键:

    Step.1 暴力枚举后中墩的情况,剩余牌自动归为前墩;

    Step.2 对于枚举结束之后的三墩,进行合法性检测;

    Step.3 对于合法的一组手牌,我们用权重数组算出这组牌赢的概率的估计值,利用估计值进行牌组的选择。

    流程图:

    五、关键代码解释

    代码比较长,关键代码即暴力枚举十三章牌可能组成的牌型,从单张(junks)到顺子(straights),每种牌型从大到小排序,再从中枚举组合出后中前墩的可能出牌模式,利用权重数组进行胜率的计算,不断替换迭代寻找胜率最高的牌组。
    
    def RecommendHands( card_list ):
        sz = len(card_list)
        q = []
        heapq.heapify(q)
        nw_hands = []
        #last O(n^5) using the brute force to enumerate the combination of the last hands
        for i in range(0,sz,1):
            nw_hands.append(card_list[i])
            for j in range(i+1,sz,1):
                nw_hands.append(card_list[j])
                for k in range(j+1,sz,1):
                    nw_hands.append(card_list[k])
                    for g in range(k+1,sz,1):
                        nw_hands.append(card_list[g])
                        for t in range(g+1,sz,1):
                            nw_hands.append(card_list[t])
                            _c = nw_hands; _w = get_weight(_c, 2)
                            heapq.heappush(q, Hands(_c, -_w))
                            if len(q) > hyper_n:
                                _ = heapq.heappop(q)
                            nw_hands.pop()
                        nw_hands.pop()
                    nw_hands.pop()
                nw_hands.pop()
            nw_hands.pop()
        
        last_hands = []; middle_hands = []; header_hands = []
        while len(q)>0:
            last_hands.append(heapq.heappop(q))
    
        #last_hands = [ ([(1,1),(1,2),(1,3),(1,4),(1,5)],weight), (), (), ... () ].dtype = Hands([(),()],w)
        for _ in last_hands:
            #fir every last_hands choose the middle_hands and header_hands
            tp_card_list = card_list.copy()
            for i in _.list:
                for j in range(len(tp_card_list)):
                    if tp_card_list[j] == i:
                        tp_card_list.pop(j)
                        break
            
            #now tp_card_list contain only 8 cards for middle and header
            sz = len(tp_card_list)
            for i in range(0,sz,1):
                nw_hands.append(tp_card_list[i])
                for j in range(i+1,sz,1):
                    nw_hands.append(tp_card_list[j])
                    for k in range(j+1,sz,1):
                        nw_hands.append(tp_card_list[k])
                        for g in range(k+1,sz,1):
                            nw_hands.append(tp_card_list[g])
                            for t in range(g+1,sz,1):
                                nw_hands.append(tp_card_list[t])
                                _c = nw_hands; _w = get_weight(_c, 1)
                                heapq.heappush(q, Hands(_c, -_w))
                                if len(q) > hyper_n:
                                    _ = heapq.heappop(q)
                                nw_hands.pop()
                            nw_hands.pop()
                        nw_hands.pop()
                    nw_hands.pop()
                nw_hands.pop()
            
            while len(q)>0:
                X = heapq.heappop(q)
                middle_hands.append(X)
                tp2_card_list = tp_card_list.copy()
                szz = len(middle_hands)
                for i in middle_hands[szz-1].list:
                    for j in range(len(tp2_card_list)):
                        if i == tp2_card_list[j]:
                            tp2_card_list.pop(j)
                            break
                _c = tp2_card_list; _w = get_weight(tp2_card_list, 0)
                header_hands.append(Hands(_c, -_w))
        
        my_hands = []
        for lst in last_hands:
            for j in range(hyper_n):
                my_hands.append(  [(header_hands[j].list, header_hands[j].weight),
                                   (middle_hands[j].list, middle_hands[j].weight),
                                   (lst.list, lst.weight)] ) 
        #for i in my_hands:
        #   print(i)
        
        return my_hands
        
        #middle O(n^5) using the brute force to enumrate the combination of the middle hands 
        #first the rest, no choise to choose
    

    六、性能分析与改进

    (1)改进思路

    改进前的思路:设计实现时,第一种方法是使用爆搜或者10重for的嵌套,简单粗暴;第二种方法是爆搜或者5重for,先选出后墩,再选出中墩,即后中墩是分开选择的。

    存在问题:第一种方法时间会很久;第二种方法虽然比第一种方法快很多,但是会出现倒水的情况,即无法保证三墩的大小关系。

    改进后的思路:采用先搜模式,匹配原始牌组,最后出牌的方法

    (2)性能分析

     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):每个函数调用的具体信息
    

    (3)消耗最大的函数

    def AutoRecommend(tp_cards, junks, pairs, triples, booms, straights, flushs, _2_pairs, _32_tps):
        _third  = booms + _32_tps + flushs + straights + triples + _2_pairs + pairs + junks
        _second = booms + _32_tps + flushs + straights + triples + _2_pairs + pairs + junks
        _first  = triples + pairs + junks
        nw_cards = tp_cards.copy()
        nw_cards.sort(key=lambda x:-x[1])
        #print("nw_cards = ", nw_cards)
        q = []
        hyper_n = 20
        my_weight = [1/5, 2/5, 2/5]
        heapq.heapify(q)
    
        for i in _third:
        
            #print("i = ",i)
            nwcs = nw_cards.copy()
            #print("nwcs0 ", nwcs)
        
            tail = i.copy()
            for ii in tail:
                nwcs.remove(ii)
        
            tp_nwcs0 = nwcs.copy()
            #print("nwcs after ii ", nwcs)
            tp_tail = tail.copy()
            for j in _second:
                nwcs = tp_nwcs0.copy()
                #print("j = ",j)
                tail = tp_tail.copy()
                mid = j.copy()
                flg = 1
                for jj in mid:
                    if ( jj in nwcs ):
                        nwcs.remove(jj)
                    else:
                        flg = 0
                        break
                if ( flg == 0 ):
                    continue
                
                tp_nwcs1 = nwcs.copy()
                #print("nwcs = ", nwcs)
                #print("nwcs after jj ", nwcs)
                tp_mid = mid.copy()
                for k in _first:
                    nwcs = tp_nwcs1.copy()
                    #print("k = ",k)
                    tail = tp_tail.copy()
                    mid = tp_mid.copy()
                    head = k.copy()
                    flg = 1
                    for kk in head:
                        if ( kk in nwcs):
                            nwcs.remove(kk)
                        else:
                            flg = 0
                            break
                    if ( flg == 0 ):
                        continue
                    
                    #print("nwcs the rest ", nwcs)
                    #print("nw_cards_0 = ", head, mid, tail)
                    #complete the head
    
                    #print(head); print(mid); print(tail)
                    
                    tpp = nw_cards.copy()
                    #print("tpp = ", tpp)
                    for hd in head:
                        tpp.remove(hd)
                    for mi in mid:
                        tpp.remove(mi)
                    for tl in tail:
                        tpp.remove(tl)
                    
                    pos = 0
                    while ( pos < len(tpp) ):
                        if ( len(head) < 3 and pos < len(tpp) ):
                            head.append(tpp[pos])
                            pos += 1
                        if ( len(mid) < 5 and pos < len(tpp) ):
                            mid.append(tpp[pos])
                            pos += 1
                        if ( len(tail) < 5 and pos < len(tpp) ):
                            tail.append(tpp[pos])
                            pos += 1
                
                    w_h, w_m, w_t = get_weight(head,0), get_weight(mid,1), get_weight(tail,2)
                    nw_w = (np.array([w_h,w_m,w_t])*np.array(my_weight)).sum()
                    #print("nw_cards_1 = ", head, mid, tail)
                    chk_val = chk_ordered(head, mid, tail)
                    if ( chk_val[0] == 1 ):
                        if ( len(q) < hyper_n ):
                            heapq.heappush(q,HandCard(head+mid+tail, nw_w))
                        else:
                            if ( nw_w > q[0].weight ):
                                heapq.heappushpop(q, HandCard(head+mid+tail, nw_w))
    
        result_cards = []
        while ( len(q) > 0 ):
            result_cards.append(heapq.heappop(q))
        ret = result_cards[len(result_cards)-1].list
        return ret
    

    七、单元测试

    构造思路

    使用unittest.TestSuite()
    按牌型顺序进行判牌单元测试
    pair 2pairs triple boom straight flush fullhouse分别判断
    输出判断的值
    

    单元测试代码

    #按牌型顺序进行判牌单元测试
    #pair 2pairs triple boom straight flush fullhouse分别判断
    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)
    

    八、Github的代码签入记录

    (因为我们是在自己测试无误可以运行之后才放到github上的只有一条记录)

    九、遇到的代码模块异常或结对困难及解决办法

    (1)没有经验,知识不足

    问题描述:由于以前都没有学过关于前端还有js的知识,所以一开始不知道怎么分工,虽然前人的经验是一人前端一人算法,但是脑子一抽我们俩一开始好像都觉得自己不太能胜任算法部分,所以前端和算法我们俩都有参与。

    做过哪些尝试:边学边敲代码,前端每个人写一部分最后整合起来,算法也一起研究了

    是否解决:是,解决了,还好前端比较容易写,边学边写代码没有很困难,js也认真学了

    有何收获:对前端有了更深的了解,增加了实战经验。学习了js,十分受用

    (2)制作弹窗

    问题描述:原型设计的时候便把排行榜,往期对战结果,往期对战结果详情都做成弹窗形式,在往期对战结果按钮中点击战局ID按钮能显示出往期对战结果详情,在弹窗中再制作一个弹窗,由于这次作业才学了前端,对弹窗的制作不熟悉

    做过哪些尝试:尝试将代码放在div按钮的前中后

    是否解决:是,解决了,将代码放在div按钮的后面,和js结合点击触发弹窗的效果

    有何收获:学会了弹窗的使用,了解了更多变量的作用,学会将前端和js结合使用

    十、评价你的队友

    苏凯婷:

    值得学习的地方:

    值得学习的地方太多了,队友很关心我们结对编程的进度,所以经常会叫上我一起去教室,杜绝宿舍摸鱼行为;主动扛下弹窗的工作;实现前端的时候,由于我们有了新的想法,对弹窗的设计做出改变,她总会问我意见,一提就改,说一不二,到后来我觉得她的审美以及非常OK,完美;还有接口也是她完成的,很感动;没有怪我摸鱼,很感动;我们已经不是鱼精组合了,因为她变成跃了龙门的鲤鱼!她很优秀!(我开始忏悔),一定是命运把她派到我身边,我能想到最浪漫的事,就是和她一起完成十三水编程作业,因为有她,我的编程生活都不枯燥了,充满信心和期待地完成了任务,夸不完了......
    

    需要改进的地方:

    就算摸鱼的队友是同伴同学也不能心怀大爱,她总是包容我本人的摸鱼行为,其实我内心墙裂要求被队友压榨(不是。
    

    鲍冰如:

    值得学习的地方:

    感谢鲍老师疯狂暴夸,感觉鲍老师比较的稳重(看起来比较)无论是面前的困难怎么样的大,鲍老师都很稳,没有像我容易打鸡血也容易变得很丧,我需要鲍老师一起就不会想要摸鱼,后期加上我们两个都有接入网这门课需要考试,任务就突然加重了,鲍老师主动包揽了博客的而大部分,令我十分感动,而且我觉得鲍老师的办事效率更高。我们鱼精组合圆满完成任务(划掉)
    

    需要改进的地方:

    没有。如果,只是如果,希望接入网不要考试QAQ.
    

    十一、学习进度条

    第N周 新增代码(行) 累计代码(行) 本周学习耗时(小时) 累计学习耗时(小时) 重要成长
    1 0 0 10 10 学习axure的使用方法
    2 2000+ 2000+ 130 140 学习html,css,js,前端制作
    3 1000+ 3000+ 20 160 算法
    ...
  • 相关阅读:
    javaSE基础(三)
    javaSE基础(二)
    javaSE基础(一)
    文件目录爬虫
    前自增 与 后自增
    查找 与 排序 总结
    python 使用 grpc
    python3.7 安装 uwsgi
    go
    go
  • 原文地址:https://www.cnblogs.com/katy0308/p/11741837.html
Copyright © 2020-2023  润新知