zoukankan      html  css  js  c++  java
  • 第一次个人编程作业

    前言
    我回来了……先给大家说声DBQ 很过意不去=-= 本来是打算国庆写好之后给大家分享一下代码的架构思路和怎么写
    结果打比赛做项目每天没什么时间写代码 更不要说写博客了 QUQ 这1个月多每天都是上班导凌晨,回宿舍开始写(国庆什么的就别想了好吧)
    总结一下这段时间就是 白天上课,晚上打比赛,凌晨断断续续打代码,睡一会起来上课。不过所幸,比赛结果还是好的
    一直到15号才真正闲下来 真的有点肝不动了 ……… BY dzy

    链接

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

    具体分工

    邓泽源主要负责代码的编码部分
    姚彬锟主要负责博客的撰写、代码的分析测试。

    PSP表格

    PSP2.1 Personal Software
    Process Stages
    预估耗时(min) 实际耗时(min)
    Planning 计划 50 40
    Estimate 估计这个任务需要多少时间 50 40
    Development 开发 1610 1920
    Analysis 需求分析
    (包括学习新技术)
    600 750
    Design Spec 生成设计文档 60 50
    Design Review 设计复审 60 50
    Coding Standard 代码规范
    (为开发制定合适的规范)
    30 30
    Design 具体设计 200 200
    Coding 具体编码 500 570
    Code Review 代码复审 80 70
    Test 测试
    (自我测试,修改,提交修改)
    180 200
    Reporting 报告 135 150
    Test Report 测试报告 45 60
    Size Measurement 计算工作量 30 30
    Postmortem & Process
    Improvement Plan
    事后总结
    并提出过程改进计划
    60 60
    合计 1795 2110

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

    总体思路(后端)

    一拿到这道题,我的内心第一反应是头大(绝望)因为没打过十三水,规则不懂,又复杂
    但后来静下心来思考了一下(脑内口嗨了一下),有3种做法
    1.0 纯贪心算法:
    先从13张内,挑出最大的5张牌作为后墩,然后剩下的8张牌,挑出5张最大的作为中墩,剩下3张作为前墩
    2.0 搜索+判断比对权值算法:
    这个算法是我一开始就想到的,13张牌一共有13!(13 x 12 x 11 x……1)种排列方式,那我们把所有的排列方式储存起来,然后前3张就是前墩,中5张就是中墩,最后就是后墩
    接着,对每种排列的前中后墩判断一下,看一下他是哪一种牌型,给每种牌设定一个权值,计算一下他的权值总和,那么,13!种排列中权值最大的就是赢面最大的。
    后面又经过 兴源和海东大佬的启发提醒,发现不需要找出全排列,只需要挑出C13 5 x C8 5 x C3 3 的组合就行,于是只有7万多种组合,大大减小了算法时间复杂度
    3.0 搜索+权值细化+引入胜率概念
    权值细化就是在2.0的版本上,引入同级别牌型的比较,例如:前墩 A A 9> 7 5 3,中墩 3 3 3 5 5<4 4 4 6 6,每种牌型细化级别内的权值,而不是简单地判断一下牌
    胜率概念:这个东西我考虑了很久……因为一直觉得这个搜索算法不够智能,终于在某天早起惊醒(闹钟震醒)的时候,想到
    如果13张牌能排出多种组合,且组合的权值和都差不多,比如排法1是级别1,级别3,级别7,排法2是级别1,级别2,级别8,双方权值和都是1+3+7=1+2+8,就算引入权值细化,可能也不知道应该选啥(当然这个时候我觉得也是 人 也应该纠结的点)
    因此
    引入胜率:也就是根据每个牌型在每一墩的具体能打败x%的牌型作为他的胜率,
    例如:AA在前墩能击败98%的牌型,AA在中墩,只能击败10%的牌型,于是就能根据概率论分布计算出他的胜率。
    这时候再来看上面的牌型,级别1,3,7虽然看起来和1,2,8差不多,但是我3->2,胜率下降了10%,但是7->8因为7的牌型占比后墩比例很高,提升到级别8,一下胜率提高了30%,那么很明显我选后者。
    经过概率论计算,如下

    算法的步骤如下图所示:

    权值与各牌型分析

    为了方便,做了一张权值与比对表图如下(放大查看清晰大图)

    算法关键与版本对比

    这个算法的关键就是上面提到的暴力搜索+权值细化

    相对比2.0和3.0,1.0一个最大的优点就是在PY下跑的快(python的运行效率真是让人发指),至于对战应该是没有2.0和3.0来的智能的;
    而2.0胜率版本因为前墩的重要性,很有可能某些时候会出现极端保前墩的情况,根据和兴源大佬的比对 我让胜率》50%的时候使用这个,
    其余时候按3.0版本的权值细化版本来。

    网络接口的使用

    api请求使用的是python里的requests库
    以开起牌局post和验证get token为例

    **点此查看详细代码 + **
    
    def opengame():
        global token,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
    def login_check():
        global token
        url = "https://api.shisanshui.rtxux.xyz/auth/validate"
        headers = {"X-Auth-Token": token}
        response = requests.get(url,headers=headers)
        print(response.text)
    

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

    变量模块 功能
    poker_1,poker_2,poker_3 扑克牌分堆
    ans_1,ans_2,ans_3 暂时寄存排列答案
    temp_1,temp_2,temp_3 存放完整排列答案
    end_1,end_2,end_3 最终答案
    s1,s2,s3 标记
    flower 花色
    num 牌号
    token,id,use token,牌局ID,用户ID

    我们只有一个类,各方法的内部实现关系如下图所示:

    总体思路(前端)

    没错=-= 我这个憨批 又来了
    其实我把上面3个版本的后端都写了一下,1.0用的而是C++,2.0用的是Java,因为一开始是想开发web端,
    但是因为前端原因又转了python,于是3.0就用python实现了,
    网上搜寻了一下python的图形化界面,

    最终,根据3.0版本的后端,用python的游戏模块图形化工具pygame写了前端界面进行联动
    PS:前端其实还好,主要是麻烦,还有联动问题,但是用pygame和python后端联动可以直接封装调用,会舒服一点

    使用的pygame主要涉及模块与函数

    变量模块 功能
    pygame.cdrom 访问光驱
    pygame.cursors 加载光标
    pygame.display 访问显示设备
    pygame.draw 绘制形状、线和点
    pygame.event 管理事件
    pygame.font 使用字体
    pygame.image 加载和存储图片
    pygame.joystick 使用游戏手柄或者类似的东西
    pygame.key 读取键盘按键
    pygame.mixer 声音
    pygame.mouse 鼠标
    pygame.movie 播放视频
    pygame.music 播放音频
    pygame.overlay 访问高级视频叠加
    pygame.rect 管理矩形区域
    pygame.scrap 本地剪贴板访问
    pygame.sndarray 操作声音数据
    pygame.sprite 操作移动图像
    pygame.surface 管理图像和屏幕
    pygame.surfarray 管理点阵图像数据
    pygame.time 管理时间和帧信息
    pygame.transform 缩放和移动图像

    关键代码解释

    暴力搜索:
    13张牌,挑出5张,然后把剩下的8张牌再放入组合搜索函数嵌套搜索,最后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
    

    统计花色与牌号:
    统计牌型用桶排序,dict用于统计花色和牌号,list用于储存牌组结构体

        for i in range(1,3+1):
            hua[ans_3[i].flower] +=1
            number[ans_3[i].num]+=1
    

    权值判断与细化:
    以前墩部分牌型为例,总细化权值=细化权值 x 细化级别

    **点此查看详细代码+ **
    
     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 #散牌
    

    性能分析与改进

    • 改进的思路
      一开始的时候由于用python写速度会比较慢一些,运行时间到了10几秒
      经过性能分析,发现在每次抓组合数时候的桶排dict_init()还有constrast()判断函数消耗了很大一部分的时间,于是进行了优化,
      最后成功让算法的性能有所提高,达到了5-6秒钟作业。

    • 性能分析图和程序中消耗最大的函数
      性能分析图如下所示消耗最大的函数是Second,就是计算中墩的函数。
      改进后,发现在判断连对和炸弹等嵌套情况可以暂时储存数据,
      同时按牌数循环,将原有的O(n3)复杂度降到了O(n2),大大减少了中墩和后墩消耗的时间

    单元测试

    单元测试这部分我们测试主要对三个函数进行测试,其他函数因为功能十分简单,所以就没有进行测试。测试的三个函数分别是得到前墩、中墩、后墩的三个函数,由于结构基本一样,只有变量的改变,所以只给出一部分的代码。各测试数据都是在手机app“大头十三水”读出的数据,然后为了提高一些代码的覆盖,我们尽可能的挑选了不同的数据进行测试,尽可能的覆盖更多的代码分支。而且由于前墩中墩后墩的结果会互相影响,即前墩挑出后要先把前墩的牌剔除再放入中墩函数进行计算,所以中墩的测试数据是在手动剔除前墩的基础上得到的,后墩同理。最后得出的结果与我们设计的算法的思路是一致的。
    覆盖率:

    class MyTestCase(unittest.TestCase):
    def testfirst(self):
    	weig0 = 10
    	weig1 = 7
    	weig2 = 6
        self.assertEqual(shisanshui.first(str0), weig0)
        self.assertEqual(shisanshui.first(str1), weig1)
        self.assertEqual(shisanshui.first(str2), weig2)
    def testsecond(self):
    	weig0 = 10
    	weig1 = 9
    	weig2 = 8
        self.assertEqual(shisanshui.second(str0), weig0)
        self.assertEqual(shisanshui.second(str1), weig1)
        self.assertEqual(shisanshui.second(str2), weig2)
    def testthird(self):
    	weig0 = 10
    	weig1 = 9
    	weig2 = 8
        self.assertEqual(shisanshui.second(str0), weig0)
        self.assertEqual(shisanshui.second(str1), weig1)
        self.assertEqual(shisanshui.second(str2), weig2)
    

    Github的代码签入记录

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

    • 问题描述
      前端这一部分的编写。
      结对沟通的问题。
      除了算法其实都有问题,之前没有做过一个稍微完整的项目,所以很多东西都没有学过,也没有这方面的知识。
    • 做过哪些尝试
      因为刚开始讨论的时候算法用C++来写,而前端决定用python写,后来听到有人说什么python写出来的前端会有问题,导致进度一度拖着……后面dzy强势肝完了这些问题,把C++转成java又转python,学习pygame、pyqt…学的东西真的多。
      结对问题就用聊天工具,就差聊出火花了。
      对没有学习的东西,只能靠搜索引擎和B站了。
    • 是否解决
      都解决了都解决了,没解决就写不出这个博客了…
    • 有何收获
      感受就是速成太难受了,计算机的世界太复杂。
      原来为了学习也能够聊出火花。
      再次强调,搜索引擎是个好东西。

    评价你的队友

    • 值得学习的地方
      dzy真的太能肝了,学习能力也太强了,偷来羡慕的目光。
    • 需要改进的地方
      我觉得他tql,什么都不需要改进,如果必须要改进的话,那就是为了互联网+没空好好带我好好敲代码。

    学习进度条

    |第N周|新增代码(行)|累计代(行)|本周学习耗时(小时)|累计学习耗时(小时)|重要成长|
    | :------: | :------: | :------: | :-----: |
    |1 | 100 | 100 | 5 | 5| 学习了Axure RP的基本使用|
    |2 | 300 | 400 | 10 | 15 |学习了JAVA的常用语法与mySQL数据库的基本操作|
    |3 | 300 | 700 | 15 | 30 |学习了pyqt和pygame的基本使用|
    |4 | 300 | 1000 | 10 | 40 |进一步学习了pyqt和pygame的使用|

  • 相关阅读:
    Linux 开发之线程条件锁那些事
    Linux 开发之线程条件锁那些事
    Linux 开发之线程条件锁那些事
    洛谷3919:可持久化数组——题解
    洛谷3919:可持久化数组——题解
    洛谷3919:可持久化数组——题解
    洛谷3919:可持久化数组——题解
    长篇干货|以太坊智能合约 —— 最佳安全开发指南(附代码)
    长篇干货|以太坊智能合约 —— 最佳安全开发指南(附代码)
    长篇干货|以太坊智能合约 —— 最佳安全开发指南(附代码)
  • 原文地址:https://www.cnblogs.com/yaobink/p/11530809.html
Copyright © 2011-2022 走看看