• 第二次结对编程


    1.各链接

    结对同学博客连接
    本作业博客连接
    Github项目地址

    2.具体分工

    王嵚:负责前端实现、博客内容指导and部分材料提供
    陈荣杰:负责后端算法、博客撰写

    3.PSP表格

    • 王嵚
    PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
    Planning 计划 60 90
    ·Estimate ·估计这个任务需要多少时间 2600 2900
    Development 开发 3250 3960
    ·Analysis ·需求分析 (包括学习新技术) 1800 2000
    ·Design Spec ·生成设计文档 90 60
    ·Design Review ·设计复审 120 120
    ·Coding Standard · 代码规范 (为目前的开发制定合适的规范) 30 50
    ·Coding ·具体编码 400 560
    ·Code Review ·代码复审 450 720
    ·Test ·测试(自我测试,修改代码,提交修改) 240 300
    Reporting 报告 130 115
    ·Test Repor ·测试报告 50 60
    ·Size Measurement · 计算工作量 20 10
    ·Postmortem & Process Improvement Plan ·事后总结, 并提出过程改进计划 20 10
    合计 3440 4165
    • 陈荣杰
    PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
    Planning 计划 30 30
    ·Estimate ·估计这个任务需要多少时间 2200 2600
    Development 开发 400 460
    ·Analysis ·需求分析 (包括学习新技术) 120 240
    ·Design Spec ·生成设计文档 40 30
    ·Design Review ·设计复审 30 20
    ·Coding Standard · 代码规范 (为目前的开发制定合适的规范) 30 30
    ·Coding ·具体编码 1000 1200
    ·Code Review ·代码复审 90 90
    ·Test ·测试(自我测试,修改代码,提交修改) 300 800
    Reporting 报告 60 60
    ·Test Repor ·测试报告 60 60
    ·Size Measurement · 计算工作量 20 20
    ·Postmortem & Process Improvement Plan ·事后总结, 并提出过程改进计划 30 30
    合计 2150 3130

    4.解题思路描述与设计实现说明

    网络接口的使用

    根据样例的提示,调用 requests库中的get/post函数实现get/post请求,把如登录、注册等等操作所需要的请求封装成 不同函数放在一个httpfunctions.py文件下,使用时导入此文件就可以了。
    具体代码如下:

    def  entry(account):#注册+绑定接口
        url='http://api.revth.com/auth/login'
        data={
            "username": account["username"],
            "password": account["password"]
        }
        headers={
            "Content-Type":"application/json"
        }
        response=requests.post(url=url,headers=headers,data=json.dumps(data),verify=False);
        print(response.text)
        r = response.json()
        return r
    

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

    • 后端算法代码组织与内部实现设计
      如果是特殊牌的话,服务器会自动识别,也就是说只要分堆就好,因此不考虑特殊牌的判别,直接对拿到的手牌进行组合,利用组合的思想对所有牌型进行比较,择取最优选择。

    • 前端代码组织与内部实现设计

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

    • 算法关键
      • 分墩算法:对手牌进行组合,遍历一副手牌可以组成的所有情况,将当前的组合与当前的最优组合进行比较,按照等级及牌面对应权重矩阵赋权值,三墩相加再比大小,比到最后可以得出一个权值最大的组合,就选中这个组合为最优。
      • 因此算法关键应该是对牌型合法的判断和判牌的策略,初始定的赋权值策略是按照牌型等级及牌面直接赋值,可在实测是产生了许多意料之外的bug,debug到自闭,后来了解到有权重矩阵的存在,摸了摸头顶,果断选择改变策略。
    • 关键实现部分流程图

    5.关键代码解释

    • 后端
      • 先处理传入字符串,将其转化为列表类型数据,每个列表的第一个值为牌面值,第二个值为花色,方便操作,再利用组合的思想对所有牌型进行比较,择取最优牌型
    def do(lll):#算法主函数,执行分墩步骤
    
        sda = [#十三水权重矩阵,亲测可用,建议上手
            [  # 1   2   3   4   5   6   7   8   9   T   J   Q   K   A   JUNK
                [0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 4, 7, 14, 33],
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1],
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
            [  # 1   2   3   4   5   6   7   8   9   T   J   Q   K   A   PAIR
                [0, 46, 48, 50, 51, 54, 56, 60, 63, 68, 74, 81, 89, 97],
                [0, 2, 3, 4, 4, 5, 7, 8, 10, 12, 15, 19, 24, 33],
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 3]],
            [  # 1   2   3   4   5   6   7   8   9   T   J   Q   K   A   TWO_PAIRS
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 36, 37, 38, 40, 44, 46, 49, 54, 57, 62, 64, 0],
                [0, 0, 2, 3, 4, 4, 6, 7, 8, 10, 11, 13, 13, 0]],
            [  # 1   2   3   4   5   6   7   8   9   T   J   Q   K   A   TWO_PAIRS
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 31, 38, 39, 41, 45, 47, 50, 55, 58, 63, 65, 0],
                [0, 0, 3, 4, 5, 5, 7, 8, 9, 11, 12, 14, 14, 0]],
            [  # 1   2   3   4   5   6   7   8   9   T   J   Q   K   A   TRIPLE
                [0, 99, 99, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100],
                [0, 63, 65, 69, 71, 72, 73, 73, 73, 74, 74, 75, 75, 75],
                [0, 11, 12, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15]],
            [  # 1   2   3   4   5   6   7   8   9   T   J   Q   K   A   STRAIGHT
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 77, 78, 81, 83, 85, 87, 88, 90, 91, 92],
                [0, 0, 0, 0, 16, 17, 20, 22, 24, 26, 28, 32, 33, 36]],
            [  # 1   2   3   4   5   6   7   8   9   T   J   Q   K   A   FLUSH
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 93, 93, 93, 93, 94, 95, 97, 98],
                [0, 0, 0, 0, 0, 0, 36, 36, 37, 38, 40, 44, 49, 61]],
            [  # 1   2   3   4   5   6   7   8   9   T   J   Q   K   A   FULL_HOUSE
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 98, 98, 99, 99, 99, 100, 100, 100, 100, 100, 100, 100, 100],
                [0, 64, 67, 70, 71, 73, 75, 77, 80, 82, 85, 88, 91, 94]],
            [  # 1   2   3   4   5   6   7   8   9   T   J   Q   K   A   FOUR_OF_A_KIND
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100],
                [0, 93, 94, 95, 95, 96, 96, 96, 97, 97, 98, 98, 98, 98]],
            [  # 1   2   3   4   5   6   7   8   9   T   J   Q   K   A   STRAIGHT_FLUSH
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 100, 100, 100, 100, 100, 100, 100, 100, 100, 0],
                [0, 0, 0, 0, 98, 98, 99, 99, 99, 99, 99, 99, 100, 0]],
            [  # 1   2   3   4   5   6   7   8   9   T   J   Q   K   A   ROYAL_FLUSH
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100],
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100]]
        ];
        card=lll
        card_type=["","",""]#牌型
        matrix=[[0,0,],[0,0,],[0,0,],[0,0,],[0,0,],[0,0,],[0,0,],[0,0,],[0,0,],[0,0,],[0,0,],[0,0,],[0,0,]]#拿到的牌的列表,即为牌库
        dun=[[],[],[]]#分墩后存储的位置
        j=0;
        a=0;
        max=0
        for pai in card:#遍历字符串,转换需要的列表数据即拿到的牌
            if pai=="*":i=4;
            elif  pai=="$":i=1;
            elif pai == "&":
                i = 2;
            elif pai=="#":i=3;
            if pai.isdigit():
                if pai=="1":matrix[j][0]=10;matrix[j][1]=i;j=j+1;
                elif pai!="0":matrix[j][0]=int(pai);matrix[j][1]=i;j=j+1;
            elif pai=="J":matrix[j][0]=11;matrix[j][1]=i;j=j+1;
            elif pai=="Q":matrix[j][0]=12;matrix[j][1]=i;j=j+1;
            elif pai=="K":matrix[j][0]=13;matrix[j][1]=i;j=j+1;
            elif pai=="A":matrix[j][0]=14;matrix[j][1]=i;j=j+1;
    
        for i in combinations(matrix, 5):#调用combinations函数得出matrix的组合
            sum=0;
            test= list(i)
            test_data1 = matrix.copy()#备份牌库
            test = sorted(test, key=lambda x: (x[0], -x[1]))#排序,以牌面升序排序
            if test[0] in test_data1:#将选出的牌从牌库中去掉以免影响后续操作
                test_data1.remove(test[0])
            if test[1] in test_data1:
                test_data1.remove(test[1])
            if test[2] in test_data1:
                test_data1.remove(test[2])
            if test[3] in test_data1:
                test_data1.remove(test[3])
            if test[4] in test_data1:
                test_data1.remove(test[4])
            for k in combinations(test_data1, 5):#从牌库剩余的8张牌中,抽出5张得到中墩,余下3张为后墩
                test_data2=test_data1.copy()#备份
                if k[0] in test_data2:#将抽出的牌从备份牌库中去掉
                    test_data2.remove(k[0])
                if k[1] in test_data2:
                    test_data2.remove(k[1])
                if k[2] in test_data2:
                    test_data2.remove(k[2])
                if k[3] in test_data2:
                    test_data2.remove(k[3])
                if k[4] in test_data1:
                    test_data2.remove(k[4])
                pp=list(k)
                test1=list(sorted(pp, key=lambda x: (x[0], -x[1])))#排序,以牌面升序排序
                test2=list(sorted(test_data2,key=lambda x: (x[0], -x[1])))#排序,以牌面升序排序
                list1=list(operation(test))#判断各个分墩的牌型以及此牌型中牌面最大的值,如炸弹中炸弹的牌面、两对中最大的对子牌面,返回牌型等级及牌面最大值
                list2=list(operation(test1))
                list3=list(ope(test2))
                if list1[0] < list2[0] or list2[0] < list3[0] or list1[0] == list2[0] and list1[1] < list2[1] or list3[0] ==list2[0] and list2[1] < list3[1]or (list1[0]==list2[0]==7and list1[2]<list2[2]):#根据牌型等级及牌面最大值判断分墩是否合法,若不合法则跳过后续步骤直接下一个循环
                    continue
                else:
                    value1 = sda[list1[0] - 1][2][list1[1] - 1]#从权重表中取得对应权值
                    value2 = sda[list2[0] - 1][1][list2[1] - 1]
                    value3 = sda[list3[0] - 1][0][list3[1] - 1]
    
                    sum = value1 + value2 + value3
                    if sum > max:#比较三墩总权值,大的留下
                        dun = [test2, test1, test]
                        max = sum
                        card_type[2] = get_type(list1[0])#将牌型对应名称赋值进对应墩
                        card_type[1] = get_type(list2[0])
                        card_type[0] = get_type(list3[0])
        s = jiema(dun)#将处理完后的列表转换为字符串数据
        s=s+["三墩牌型:"]+card_type
        print(s)#输出分墩情况及牌型
        return s
    
    • 判断各个分墩的牌型以及此牌型中牌面最大的值,如炸弹中炸弹的牌面、两对中最大的对子牌面,返回牌型等级及牌面最大值
    def operation(list):#判别牌型,返回牌型对应数字与此牌型中关键牌值,传入参数升序排列的列表
        sum=[0,0,0];
        a=[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]]#a[0]代表此位置对应牌的牌面,a[1]代表此牌面的牌有几张,可通过a[1]判断炸弹、葫芦、三条等有多张同牌面的牌型,
        for list1 in list:
            for count in range(5):
                if a[count][0]==list1[0]:
                    a[count][1]=a[count][1]+1
                    break
                elif a[count][0]==0:
                    a[count][0] = list1[0]
                    a[count][1] = a[count][1] + 1
                    break
            count=0
        if(list[0][0]+4==list[1][0]+3==list[2][0]+2==list[3][0]+1==list[4][0]):#按序排列
            if list[0][1]==list[1][1]==list[2][1]==list[3][1]==list[4][1]:#同花色
                sum=[10,list[4][0]]#同花顺
                return sum
        else:
            count=0
            for jojo in a:
                if jojo[1]==4:
                    sum= [9,jojo[0]]#炸弹
                    return sum
                elif jojo[1]==3:
                        if a[a.index(jojo)+1][1]==2:
                            sum= [8,jojo[0]]#葫芦
                            return sum
                        elif list[0][1]==list[1][1]==list[2][1]==list[3][1]==list[4][1]:
                            sum=[7,list[4][0],list[3][0]]#同花
                            return sum
                        elif (list[0][0] + 4 == list[1][0] + 3 == list[2][0] + 2 == list[3][0] + 1 == list[4][0]):
                            sum=[6,list[4][0],list[3][0]]#顺子
                            return sum
                        else :
                            sum=[5,jojo[0]]#三条
                            return sum
                elif jojo[1]==2:
                    if a[1][1]==3:
                        sum= [8,a[1][0]]#葫芦
                        return sum
                    elif list[0][1] == list[1][1] == list[2][1] == list[3][1] == list[4][1]:
                        sum =[7, list[4][0],list[3][0]] # 同花
                        return sum
                    elif (list[0][0] + 4 == list[1][0] + 3 == list[2][0] + 2 == list[3][0] + 1 == list[4][0]):
                        sum = [6,list[4][0]]  # 顺子
                        return sum
                    elif a[a.index(jojo)+1][1]==2:
                        if jojo[0]+1==a[a.index(jojo)+1][0]:
                            sum= [4,a[a.index(jojo)+1][0]]#连队
                            return sum
                        else:
                            sum=[3,a[a.index(jojo)+1][0]] #两对
                            return sum
                    elif a[a.index(jojo)+2][1]==2:
                        sum =[3 ,a[a.index(jojo)+2][0]] # 两对
                        return sum
                    else:
                        sum=[2,jojo[0]] #对子
                        return sum
            if list[0][1] == list[1][1] == list[2][1] == list[3][1] == list[4][1]:
                sum =[7 ,list[4][0] ,list[3][0]]# 同花
                return sum
            elif (list[0][0] + 4 == list[1][0] + 3 == list[2][0] + 2 == list[3][0] + 1 == list[4][0]):
                sum =  [6 ,list[4][0]] # 顺子
                return sum
    
            else:
                sum =  [1,list[4][0]]
                return sum
        if list[0][1] == list[1][1] == list[2][1] == list[3][1] == list[4][1]:
            sum =[7,list[4][0]]   # 同花
            return sum
        elif (list[0][0] + 4 == list[1][0] + 3 == list[2][0] + 2 == list[3][0] + 1 == list[4][0]):
            sum = [6 ,list[4][0]] # 顺子
            return sum
    
        else:
            sum =  [1,list[4][0]]#散牌
            return sum
        return sum
    def ope(list3):#求前墩的牌型,返回值与operation()相同
        sum=0
        if list3[0][0]==list3[1][0]==list3[2][0]:#三条
            sum=[5,list3[2][0]]
            return sum
        elif list3[0][0]==list3[1][0]:#对子
            sum=[2,list3[1][0]]
            return sum
        elif list3[2][0]==list3[1][0]:#对子
            sum=[2,list3[1][0]]
            return sum
        else:
            sum=[1,list3[2][0]]#散牌
            return sum
    
    • 前端
    from login_register_platform import LoginRegisterPlatform
    from user_platform import UserPlatform
    from record_platform import RecordPlatform
    from game_platform import GamePlatform
    from register_platform import RegisterPlatform
    from list_platform import ListPlatform
    from detail_platform import DetailPlatform
    #以上是导入UI模块
    
    from connector.sign_up import regiseterAndBind          #导入注册接口
    from connector.Login import entry           #导入登入接口
    from connector.asd import start             #导入开始游戏接口
    from connector.lishizhanji import paihang   #导入排行榜接口
    from connector.lishizhanji import see       #导入历史列表接口
    from connector.lishizhanji import zhanju    #导入战局详情接口
    from connector.Logout import chupai         #导入出牌接口
    from connector.division import do           #导入出牌函数
    
    from PyQt5.Qt import *
    
    
    if __name__ == '__main__':
        import sys
        app = QApplication(sys.argv)
        token = "a_random_string"
        game_id = 0
        card = "*1 *2 *3 *4 *5 *6 7 *8 *9 *J *Q *K"
    
        window_login = LoginRegisterPlatform()              #创建登入界面
        window_login.setObjectName("Login")
        window_login.setStyleSheet("#Login{border-image: url(resource/image/login.png);}")
    
    
        window_register = RegisterPlatform()            #创建注册界面
        window_register.setObjectName("Register")
        window_register.setStyleSheet("#Register{border-image: url(resource/image/login.png);}")
    
    
        window_user = UserPlatform()            #创建用户界面
        window_user.setObjectName("User")
        window_user.setStyleSheet("#User{border-image: url(resource/image/user_background.jpg);}")
        window_user.head.setStyleSheet("border-image: url(resource/image/user_head.jpg)")
    
    
        window_game = GamePlatform()            #创建游戏界面
        window_game.setObjectName("Game")
        window_game.setStyleSheet("#Game{border-image: url(resource/image/record_background.jpg);}")
        window_game.head.setStyleSheet("border-image: url(resource/image/user_head.jpg)")
    
    
        window_record = RecordPlatform()            #创建排行榜界面
        window_record.setObjectName("Record")
        window_record.setStyleSheet("#Record{border-image: url(resource/image/record_background.jpg);}")
    
        window_list = ListPlatform()                #创建历史战局列表界面
        window_list.setObjectName("List")
        window_list.setStyleSheet("#List{border-image: url(resource/image/record_background.jpg);}")
    
        window_detail = DetailPlatform()                #创建历史战局详情界面
        window_detail.setObjectName("Detail")
        window_detail.setStyleSheet("#Detail{border-image: url(resource/image/record_background.jpg);}")
    
    
    
    
        def show_user_platform(login_text,register_text):           #由登入界面跳转到用户界面的函数
            global token
            account = {"username": login_text, "password": register_text}
            r = entry(account)
            flag = r["status"]
            print(flag)
            if (flag == 0):
                global token
                data = r["data"]
                token = data["token"]
                QMessageBox.about(window_login, "登入结果", "登入成功")
                window_user.show()
                window_login.hide()
            else:
                QMessageBox.about(window_login, "登入结果", "登入失败,账号或密码错误")
    
        def show_login_platform_f_r():
            print("回到登入界面")
            window_login.show()
            window_register.hide()
    
        def show_register_platform():
            print("展示注册界面")
            window_register.show()
            window_login.hide()
    
        def show_login_platform_f_u():
            print("展示登入平台")
            window_login.show()
            window_user.hide()
    
        def show_game_platform():  #由用户界面跳转到游戏界面的函数
            window_user.hide()
            window_game.show()
    
        def show_record_platform():           #由用户界面跳转到排行榜界面的函数
            print("展示排行榜平台")
            window_record.show()
            window_user.hide()
    
        def show_list_platform():
            print("展示历史战局列表平台")
            window_list.show()
            window_user.hide()
    
        def show_detail_platform():
            print("展示历史战局详情平台")
            window_detail.show()
            window_user.hide()
    
        def show_user_platform_f_g():  # 由游戏界面跳转到用户界面的函数
            print("展示用户平台")
            window_user.show()
            window_game.hide()
    
        def show_user_platform_f_r():           #由排行榜界面跳转到用户界面的函数
            print("展示用户平台")
            window_user.show()
            window_record.hide()
    
        def show_user_platform_f_l():
            print("展示用户平台")
            window_user.show()
            window_list.hide()
    
        def show_user_platform_f_d():
            print("展示用户平台")
            window_user.show()
            window_detail.hide()
    
        def register(UserName,PassWord,StudentId,JwcPassWord):         #注册函数
            account = {"username": UserName, 'password': PassWord}
            jwc = {"student_number": StudentId, "student_password": JwcPassWord}
            flag = regiseterAndBind(account,jwc)
            if (flag == 0):
                QMessageBox.about(window_register, "注册结果", "注册成功")
                window_login.show()
                window_register.hide()
            elif (flag == 1002):
                QMessageBox.about(window_register, "注册结果", "学号已绑定")
                window_login.show()
                window_register.hide()
            elif (flag == 1003):
                QMessageBox.about(window_register, "注册结果", "教务处认证失败")
            else :
                QMessageBox.about(window_register, "注册结果", "注册失败")
    
        def record_get_data():          #获取排行榜
            r = paihang()
            x = len(r)
            window_record.tableWidget.setRowCount(x)
            for i in range(0,x):
                y = r[i]
                idItem = QTableWidgetItem(str(y["player_id"]))
                window_record.tableWidget.setItem(i,0,idItem)
                nameItem = QTableWidgetItem(y["name"])
                window_record.tableWidget.setItem(i, 1, nameItem)
                scoreItem = QTableWidgetItem(str(y["score"]))
                window_record.tableWidget.setItem(i, 2, scoreItem)
            #newItem = QTableWidgetItem('张三')
            #TableWidget.setItem(0, 0, newItem)
    
        def list_get_data(player_id):
            global token
            print(player_id)
            response = see(token,player_id)
            data = response["data"]
            lenth = len(data)
            window_list.history_game_list.setRowCount(lenth)
            for i in range(0,lenth):
                now_data = data[i]
                card_list = "".join(now_data["card"])
                id_Item = QTableWidgetItem(str(now_data["id"]))
                window_list.history_game_list.setItem(i, 0, id_Item)
                card_Item = QTableWidgetItem(card_list)
                window_list.history_game_list.setItem(i, 1, card_Item)
                score_Item = QTableWidgetItem(str(now_data["score"]))
                window_list.history_game_list.setItem(i, 2, score_Item)
                timestamp_Item = QTableWidgetItem(str(now_data["timestamp"]))
                window_list.history_game_list.setItem(i, 3, timestamp_Item)
    
        def detail_get_data(game_id):
            global token
            response = zhanju(token,game_id)
            data = response["data"]
            detail = data["detail"]
            lenth = len(detail)
            window_detail.history_game_detail.setRowCount(lenth)
            for i in range(0,lenth):
                now_detail = detail[i]
                card_list = "".join(now_detail["card"])
                game_id_Item = QTableWidgetItem(str(data["id"]))
                window_detail.history_game_detail.setItem(i,0,game_id_Item)
                player_id_Item = QTableWidgetItem(str(now_detail["player_id"]))
                window_detail.history_game_detail.setItem(i, 1, player_id_Item)
                name_Item = QTableWidgetItem(now_detail["name"])
                window_detail.history_game_detail.setItem(i, 2, name_Item)
                card_Item = QTableWidgetItem(card_list)
                window_detail.history_game_detail.setItem(i, 3, card_Item)
                score_Item = QTableWidgetItem(str(now_detail["score"]))
                window_detail.history_game_detail.setItem(i, 4, score_Item)
    
        def start_game():           #开始游戏但是还没出牌
            print("已经点击开始游戏按钮")
            QMessageBox.about(window_game, "提示", "点击出牌后可再次点击开始游戏,重复点击开始游戏将导致进入多个战局而无法出牌")
            global token,game_id,card
            # print(token)
            r = start(token)
            flag = r["status"]
            data = r["data"]
            id = str(data["id"])
            game_id = data["id"]
            card = data["card"]
            print(card)
            if (flag == 0):
                window_game.game_id.setText(id)
                QMessageBox.about(window_game,"提示","成功进入战局")
            else:
                QMessageBox.about(window_game, "开始游戏结果", "开始游戏失败,错误状态码:" + str(flag))
    
        def show_poker():
            print("已经点击出牌按钮")
            global token,game_id,card
            s = do(card)
            response = chupai(token,game_id,s)
    
            c = s[0]
            d = ''
            type_1 = list()
            for i in c:
                if i == ' ':
                    if d[0] == '#':
                        d = '方块' + d
                    elif d[0] == '$':
                        d = '黑桃' + d
                    elif d[0] == '&':
                        d = '红桃' + d
                    elif d[0] == '*':
                        d = '梅花' + d
    
                    type_1.append(d)
                    d = ''
                    continue
                d += i
            if d[0] == '#':
                d = '方块' + d
            elif d[0] == '$':
                d = '黑桃' + d
            elif d[0] == '&':
                d = '红桃' + d
            elif d[0] == '*':
                d = '梅花' + d
            type_1.append(d)
            window_game.one_poker_1.setText(type_1[0])
            window_game.one_poker_2.setText(type_1[1])
            window_game.one_poker_3.setText(type_1[2])
    
            type_2 = list()
            c = s[1]
            d = ''
            for i in c:
                if i == ' ':
                    if d[0] == '#':
                        d = '方块' + d
                    elif d[0] == '$':
                        d = '黑桃' + d
                    elif d[0] == '&':
                        d = '红桃' + d
                    elif d[0] == '*':
                        d = '梅花' + d
                    type_2.append(d)
                    d = ''
                    continue
                d += i
            if d[0] == '#':
                d = '方块' + d
            elif d[0] == '$':
                d = '黑桃' + d
            elif d[0] == '&':
                d = '红桃' + d
            elif d[0] == '*':
                d = '梅花' + d
            type_2.append(d)
            window_game.tow_poker_1.setText(type_2[0])
            window_game.tow_poker_2.setText(type_2[1])
            window_game.tow_poker_3.setText(type_2[2])
            window_game.tow_poker_4.setText(type_2[3])
            window_game.tow_poker_5.setText(type_2[4])
    
            type_3 = list()
            c = s[2]
            d = ''
            for i in c:
                if i == ' ':
                    if d[0] == '#':
                        d = '方块' + d
                    elif d[0] == '$':
                        d = '黑桃' + d
                    elif d[0] == '&':
                        d = '红桃' + d
                    elif d[0] == '*':
                        d = '梅花' + d
                    type_3.append(d)
                    d = ''
                    continue
                d += i
            if d[0] == '#':
                d = '方块' + d
            elif d[0] == '$':
                d = '黑桃' + d
            elif d[0] == '&':
                d = '红桃' + d
            elif d[0] == '*':
                d = '梅花' + d
            type_3.append(d)
            window_game.three_poker_1.setText(type_3[0])
            window_game.three_poker_2.setText(type_3[1])
            window_game.three_poker_3.setText(type_3[2])
            window_game.three_poker_4.setText(type_3[3])
            window_game.three_poker_5.setText(type_3[4])
    
            flag = response["status"]
            if (flag == 0):
                QMessageBox.about(window_game,"提示","出牌成功可以再次开始游戏")
            else:
                QMessageBox.about(window_game,"提示","出牌失败")
    
    
    
    
    
        window_login.account_password_signal.connect(show_user_platform)                           #登入界面中连接跳转到用户界面的函数
        window_login.register_signal.connect(show_register_platform)                    #登入界面到注册界面的连接
        window_register.return_to_login_signal.connect(show_login_platform_f_r)        #注册界面回到登入界面
        window_user.return_to_login_platform_signal.connect(show_login_platform_f_u)     #自己看函数名
        window_user.start_game_signal.connect(show_game_platform)                       #用户界面中连接跳转到游戏界面的函数
        window_user.go_to_rank_signal.connect(show_record_platform)                     #用户界面中连接跳转到排行榜界面的函数
        window_user.go_to_list_signal.connect(show_list_platform)
        window_user.go_to_detail_signal.connect(show_detail_platform)
        window_game.return_to_user_platform_signal.connect(show_user_platform_f_g)       #游戏界面中连接跳转到用户界面的函数
        window_record.return_to_user_platform_signal.connect(show_user_platform_f_r)     #排行榜界面中连接跳转到用户界面的函数
        window_list.return_to_user_signal.connect(show_user_platform_f_l)
        window_detail.return_to_user_signal.connect(show_user_platform_f_d)
        window_register.register_sinal.connect(register)                                  #连接向服务器发送注册信息的函数
        window_record.get_data_signal.connect(record_get_data)             #更新排行榜数据
        window_list.get_data_signal.connect(list_get_data)                 #更新历史列表数据
        window_detail.get_data_signal.connect(detail_get_data)             #更新战局详情列表
        window_game.start_game_signal.connect(start_game)                  #开始游戏请求
        window_game.show_poker_signal.connect(show_poker)                  #出牌
    
        window_login.show()
    
    
        sys.exit(app.exec_())
    

    6.性能分析与改进

    改进的思路

    • 一开始定的权值策略不佳,导致容易出现葫芦拆成三条和对子,甚至偶尔会出现不合法的情况,后来苦心查阅各方资料问大佬同学,了解到权值矩阵的存在,一用上就体会到前所未有的顺滑
    • 用了权值矩阵之后,偶尔还是会有报错,多次debug后发现是在判断合不合法的条件语句出问题,后面改成判断是否不合法,相对简单一些。
    • 一开始憋着一股劲,一股脑把算法敲出来,后来发现敲出来的东西bug实在太多,其实应该再开始前就先查阅资料,了解背景,然后打码的时候也得保持冷静,大脑发热万万不可

    性能分析图和程序中消耗最大的函数

    本次性能分析是利用pycham自带性能分析模块


    由图中可以看出operation函数消耗最大,即黄色的函数块

    7.单元测试

    • 下图是测试用到的函数,代码比较长,限于篇幅不全展开
      • 主函数代码展示
    class TestDo(TestCase):
        def test_best_cards_type():
            card_dic = []
            for i in ['*', '#', '&', '$']:
                for j in ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']:
                    card_dic.append(i + j)
            num = 10
            while num:
                cards = ""
                s = copy(card_dic)
                for i in range(13):
                    j = numpy.random.randint(0, len(s))
                    if i != 12:
                        cards += s[j] + ' '
                    else:
                        cards += s[j]
                    s.pop(j)
                num -= 1
                do(cards)
        test_best_cards_type()
    
    • 对do函数即分牌函数进行单元测试
      测试数据:随机生成,不特意构造
      测试思路:利用随机生成的数据对division进行测试,可完成对其实用性和可靠性检测

    • 利用coverage对测试程序进行覆盖率分析

      • 运行结果

    8.Github的代码签入记录

    9.遇到的困难及解决方法

    • 陈荣杰
    困难描述 解决尝试 是否解决 有何收获
    排行榜、历史战局、登录注册要从服务器得到数据并展示 查找资料、根据十三水api上的样例来仿作、求助队友 第一次尝试调用网络接口,requests真的好用
    分墩赋权值算法不够优 查阅资料、询问大佬 原来还有十三水权值矩阵这东西,真好用嘿嘿
    如何设计算法实现最优牌型的选择 第一下想法是判断自己有何牌型,然后从牌型到的到小的剔除,再重新判断,后面用了组合的想法来判牌、分牌 学习了组合数算法,itertools库真好用
    • 王嵚
    困难描述 解决尝试 是否解决 有何收获
    实现前端的方法很多不知道用什么好 之前第一次个人编程作业的时候下载了pycharm 也学习了一些python,于是决定用pyqt5来完成这次作业 熟悉了python语法,初步掌握了pyqt5
    熟悉的同学里没有使用相同工具的,遇到问题比较困扰 百度、视频教程和自己瞎试 锻炼了自学能力

    10.评价队友

    • 值得学习的地方
      主动承担起前端大梁,儒雅随和,不紧不慢,是个好队友
    • 需要改进的地方
      无,挺好了

    11.学习进度条

    • 王嵚
    第N周 新增代码(行) 累计代码(行 本周学习耗时(小时) 累计学习耗时(小时) 重要成长
    1 0 0
    2 500 500 20 20 pyqt没学会多少python的语法倒是学了不少
    3 1000 1500 30 50 实现了前端
    • 荣杰
    第N周 新增代码(行) 累计代码(行 本周学习耗时(小时) 累计学习耗时(小时) 重要成长
    4 0 0 10 10 对项目的需求分析和原型设计的了解更深
    6 800+ 800+ 5 15 十三水出牌算法的实现,以及py自带堆的学习
  • 相关阅读:
    十五、docker的隔离namespace和资源限制cgroup
    十四、docker-compose
    十三、搭建SSL的私有harbor仓库
    帆软常用JS
    oracle_ cursor.executemany
    sql常用语句
    考勤清洗
    JAVA基础教程day03--运算符
    B站视频爬虫
    ES6
  • 原文地址:https://www.cnblogs.com/jie0207/p/11767702.html
Copyright © 2020-2023  润新知