• 第二次结对编程作业


    第二次结对编程作业

    一、链接

    1、结对队友博客-梅恒权

    2、本作业博客的链接

    3、Github地址

    二、具体分工

    杨欢:前端qt界面,以及网络接口

    梅恒权:后端AI出牌算法

    三、PSP表格

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

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

    4.1、网络接口的使用

    4.1.1、注册接口

        def signIn(self,account):#注册接口
            headers = {
                "Content-Type": 'application/json',
                "User-Agent": 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Mobile Safari/537.36'
            }
            response = requests.post('http://api.revth.com/auth/register2', json.dumps(account), headers=headers)
            reData = json.loads(response.text)
    

    4.1.2、接入登录接口的代码

    def login(self,account): #登陆
        # account=self.account
        headers = {
            "Content-Type": 'application/json',
            "User-Agent": 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Mobile Safari/537.36'
        }
        response = requests.post('http://api.revth.com/auth/login', json.dumps(account), headers=headers)
        reData = json.loads(response.text)
    

    4.1.3、接受到牌的接口

     def openGame(self,token):
         headers = {
         "X-Auth-Token": '',
         "User-Agent": 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Mobile Safari/537.36'
         }
         headers["X-Auth-Token"] = token
         response = requests.post('http://api.revth.com/game/open', headers=headers)
         reData=json.loads(response.text)
    

    4.1.4、排行榜的接口

    url = 'http://api.revth.com/rank'
    re = requests.get(url)
    self.rank_json = json.loads(re.text)
    

    4.1.5、历史记录的接口

     headers={
    	"X-Auth-Token":self.token,
     }
     data={
         "player_id":id,
         "limit":20,
         "page":self.page
     }
     response=requests.get("http://api.revth.com/history",data=data,headers=headers)
                self.listData=json.loads(response.text)["data"]
    

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

    sss5.jpg

    4.3、算法的关键与关键实现部分流程图

    算法使用了回溯搜索,关键在于减枝和分数矩阵评分的算法设计

    关键实现部分流程图如下:

    sss1.png

    五、关键代码解释

    搜索回溯

    optimize_back() {
        for (var b1 = 0; b1 < 9; ++b1) {
          for (var b2 = b1 + 1; b2 < 10; ++b2) {
            for (var b3 = b2 + 1; b3 < 11; ++b3) {
              for (var b4 = b3 + 1; b4 < 12; ++b4) {
                for (var b5 = b4 + 1; b5 < 13; ++b5) {
                  this.back = new WaveEvaluator(
                    [this.hand[b1], this.hand[b2], this.hand[b3],
                     this.hand[b4], this.hand[b5]], Back);
                  if (this.back.pattern == Junk) continue;
                  if (200 + this.back.value < this.threshold) continue;
    
                  var bits = (1<<b1) + (1<<b2) + (1<<b3) + (1<<b4) + (1<<b5);
                  this.optimize_center(bits);
                }
              }
            }
          }
        }
      }
    
      optimize_center(bits) {
        out:
        for (var c1 = 0; c1 < 9; ++c1) {
          if ((1 << c1) & bits) continue;
          for (var c2 = c1 + 1; c2 < 10; ++c2) {
            if ((1 << c2) & bits) continue;
            for (var c3 = c2 + 1; c3 < 11; ++c3) {
              if ((1 << c3) & bits) continue;
              for (var c4 = c3 + 1; c4 < 12; ++c4) {
                if ((1 << c4) & bits) continue;
                for (var c5 = c4 + 1; c5 < 13; ++c5) {
                  if ((1 << c5) & bits) continue;
    
                  this.center = new WaveEvaluator(
                    [this.hand[c1], this.hand[c2], this.hand[c3],
                     this.hand[c4], this.hand[c5]], Center);
                  if (this.back.is_smaller_than(this.center)) break out;
                  if (100 + this.center.value + this.back.value < this.threshold)
                    continue;
    
                  var center_bits = (1<<c1) + (1<<c2) + (1<<c3) + (1<<c4) + (1<<c5);
                  this.optimize_front(bits + center_bits);
                }
              }
            }
          }
        }
      }
    
      optimize_front(bits) {
        out:
        for (var f1 = 0; f1 < 11; ++f1) {
          if ((1 << f1) & bits) continue;
          for (var f2 = f1 + 1; f2 < 12; ++f2) {
            if ((1 << f2) & bits) continue;
            for (var f3 = f2 + 1; f3 < 13; ++f3) {
              if ((1 << f3) & bits) continue;
    
              this.front = new WaveEvaluator(
                [this.hand[f1], this.hand[f2], this.hand[f3]], Front);
              if (this.center.is_smaller_than(this.front)) break out;
    
              var sum_value = expected_points(this.front, this.center, this.back);
              var duplicate = false;
              for (var pos = 0; pos < this.top_waves.length; ++pos) {
                if (sum_value < this.top_waves[pos][0]) break;
                if (sum_value == this.top_waves[pos][0]) {
                  duplicate = true;
                  break;
                }
              }
              if (duplicate) continue;
              if (pos == 0 && this.top_waves.length == this.handicap + 1) continue;
    
              this.top_waves.splice(pos, 0, [sum_value].concat(
                    this.front.wave, this.center.wave, this.back.wave));
              if (this.top_waves.length > this.handicap + 1)
                this.top_waves.shift();
              this.threshold = this.top_waves[0][0];
            }
          }
        }
      }
    

    权重矩阵

    var pattern_points = [
      //           Tr       FH Qu SF  RF
      [1, 1, 1, 1, 3, 1, 1, 1, 1,  1,  1],  // front
      [1, 1, 1, 1, 1, 1, 1, 2, 8, 10, 20],  // center
      [1, 1, 1, 1, 1, 1, 1, 1, 4,  5, 10],  // back
    ];
    
    var junk_value = [
      //2   3   4   5   6   7   8   9   T   J   Q   K   A
      [ 0,  0,  0,  0,  0,  1,  1,  2,  2,  4,  7, 15, 34],
      [ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1],
      [ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0]
    ];
    
    var junk_value0 = [
      //2   3   4   5   6   7   8   9   T   J   Q   K   A
      [ 0, 20, 20, 21, 21, 22, 23, 24, 26, 30, 34, 42,  0],  //A?
      [ 0,  9,  9, 10, 10, 11, 11, 12, 13, 15, 18,  0,  0],  //K?
      [ 0,  5,  5,  5,  6,  6,  7,  7,  8,  8,  0,  0,  0]   //Q?
    ];
    
    var one_pair_value = [
      //2   3   4   5   6   7   8   9   T   J   Q   K   A
      [45, 47, 49, 51, 53, 56, 60, 64, 68, 73, 81, 89, 97],
      [ 2,  3,  3,  4,  5,  6,  8, 10, 12, 15, 18, 24, 33],
      [ 0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  2,  2,  3]
    ];
    
    var one_pair_value0 = [
      //2   3   4   5   6   7   8   9   T   J   Q   K   A
      [96, 96, 96, 96, 96, 96, 97, 97, 97, 97, 98, 98,  0],  //A?
      [86, 86, 86, 86, 86, 87, 87, 88, 89, 89, 90,  0, 91],  //K?
      [76, 76, 77, 77, 77, 78, 78, 78, 79, 80,  0, 82, 83]   //Q?
    ];
    
    var one_pair_value1 = [
      //2   3   4   5   6   7   8   9   T   J   Q   K   A
      [ 0,  0, 30, 31, 31, 32, 32, 33, 33, 34, 35, 36,  0],  //A?
      [ 0,  0, 23, 23, 23, 23, 23, 24, 25, 25, 26,  0, 27],  //K?
      [ 0,  0, 17, 17, 18, 18, 18, 19, 19, 20,  0, 21, 22]   //Q?
    ];
    
    var two_pair_value = [
      //2   3   4   5   6   7   8   9   T   J   Q   K   A
      [ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
      [ 0, 37, 37, 39, 41, 43, 46, 49, 54, 58, 62, 64, 64],
      [ 0,  3,  3,  4,  4,  5,  7,  8, 10, 11, 13, 14, 14]
    ];
    var continuous_value = [
      //2   3   4   5   6   7   8   9   T   J   Q   K   A
      [ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
      [ 0, 37, 37, 39, 41, 43, 46, 49, 54, 58, 62, 64, 64],
      [ 0,  3,  3,  4,  4,  5,  7,  8, 10, 11, 13, 14, 14]
    ];
    var triple_value = [
      //2   3   4   5   6   7   8   9   T   J   Q   K   A
      [99, 99, 99, 99, 99,100,100,100,100,100,100,100,100],
      [63, 66, 69, 71, 72, 72, 74, 74, 74, 75, 75, 75, 76],
      [12, 13, 13, 15, 16, 16, 16, 16, 16, 14, 15, 15, 15]
    ];
    
    var straight_value = [
      //2   3   4   5   6   7   8   9   T   J   Q   K   A
      [ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
      [ 0,  0,  0, 77, 79, 81, 83, 85, 87, 88, 89, 91, 92],
      [ 0,  0,  0, 16, 18, 20, 22, 24, 26, 28, 31, 34, 37]
    ];
    
    var flush_value = [
      //2   3   4   5   6   7   8   9   T   J   Q   K   A
      [ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
      [ 0,  0,  0,  0,  0, 93, 92, 92, 93, 94, 95, 97, 98],
      [ 0,  0,  0,  0,  0, 35, 37, 38, 38, 40, 44, 50, 61]
    ];
    
    var flush_value2 = [
      //2   3   4   5   6   7   8   9   T   J   Q   K   A
      [ 0,  0,  0,  0, 53, 54, 55, 56, 57, 59, 62, 65,  0],  //A?
      [ 0,  0,  0, 44, 44, 45, 46, 47, 48, 49, 52,  0,  0],  //K?
      [ 0,  0,  0, 41, 41, 41, 42, 42, 44, 45,  0,  0,  0]   //Q?
    ];
    
    var full_value = [
      //2   3   4   5   6   7   8   9   T   J   Q   K   A
      [ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
      [98, 99, 99, 99, 99, 99, 99, 99,100,100,100,100,100],
      [65, 66, 69, 71, 73, 75, 78, 80, 82, 85, 88, 91, 94],
    ];
    
    var quadruple_value = [
      //2   3   4   5   6   7   8   9   T   J   Q   K   A
      [ 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],
      [ 94, 94, 95, 95, 95, 96, 97, 97, 97, 97, 98, 98, 98]
    ];
    

    六、性能分析与改进

    6.1、改进的思路

    改进的时候就是看时间是否满足调节,通过算法的优化减小时间的耗费。

    从暴搜到简单搜索到牌型贪心组合。枚举13张牌可能组成的牌型,从单张(junks)到顺子(straights),每种牌型从大到小排序,再从中枚举组合出后中前墩的可能出牌模式,最后枚举判断是否合法即可。

    6.2、性能分析图

    可见CPU运行达到峰值,在出牌的AI算法上

    ss4.PNG

    6.3、消耗最大函数

    由以上可知,由于是回溯搜索,所以时间主要在三墩牌的组合上。

    七、单元测试

    7.1、单元测试代码

    function test(arr) {
      for (var i = 0; i < arr.length; ++i ) {
        var mypos = Math.floor(Math.random() * (arr.length - i));
        var item = arr[mypos];
        arr[mypos] = array[arr.length - 1 - i];
        arr[arr.length - 1 - i] = item;
      }
      return arr;
    }
    console.time("running time");
    for (var i =0 ; i<=1000 ;++i )
    {
        tmp=optimize_hand(test([...Array(52).keys()]));
    }
    console.timeEnd("running time");
    

    7.2、测试函数说明

    随机测试出牌情况,输出运行时间。

    7.3、构造测试数据的思路

    随机数据生成,保证算法的鲁棒性,随机生成出1000次牌局,尽可能争取达到各种各样的牌型与决策。

    八、Github的代码签入记录

    sss2.PNG

    ss3.PNG

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

    问题描述

    结对没有尽早开始写代码,拖延得比较后面。每周都在deadline各种赶(linux,实验,比赛等等)

    做过哪些尝试

    意识到来不及了,就赶快写了,连续熬夜一两天战斗了

    是否解决

    已解决

    有何收获

    队友是一个好队友。

    在deadline前效率是最高,但过了之后,真的很伤身体

    十、评价你的队友

    值得学习的地方

    强者风范,不紧不满,胸有成竹

    需要改进的地方

    好像没有什么需要改进的,总的来说,感谢我的队友,考虑到我的各种原因,包揽

    了大部分的工作。平心而论,如果这次是个人作业,我可能就完成不了了,或者说只会做出一个非常难受的UI界面。

    十一、学习进度条

    第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
  • 相关阅读:
    最近有人说我欺骗消费者,今天来一波视频分享
    前端 Java Python等资源合集大放送
    dubbo源码学习(四):暴露服务的过程
    dubbo源码学习(二) : spring 自定义标签
    Dubbo多注册中心和Zookeeper服务的迁移
    线程各种状态转换分析
    java并发之同步辅助类CountDownLatch
    工作5年的Java程序员,才学会阅读源码,可悲吗?
    【阿里面试系列】Java线程的应用及挑战
    「阿里面试系列」搞懂并发编程,轻松应对80%的面试场景
  • 原文地址:https://www.cnblogs.com/JustNo/p/11766723.html
Copyright © 2020-2023  润新知