• 第二次结对编程作业


    一、链接集合

    二、具体分工

    • 丁枢桐: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

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

    • 网络接口的使用

    我根据永福给的几个前端的接口,还有get,post参数,写了接永福服务器的接口写了接口,然后进行数据的发送和获取数据并加以展示,将他的所给的牌将牌给储存下来。再和后端交接,把后端所给的字符串交给永福的服务器。我选择我连的一部分接口来详细描述。

    • 注册接口

    接入注册接口的代码,根据用户所填写的用户名,学号,密码,教务处 ,密码,将所填写的内容传递到服务器,并且根据服务器返回的内容,来提醒用户。

    function register() {
       var reg_data = ($('#reg_form').serializeJson());
       if (reg_data.username == undefined || reg_data.password == undefined) {
           alert("用户名或密码不能为空");
           return;
       }
       $.ajax({
           type: "POST",
           dataType: "json",
           url: "https://api.shisanshui.rtxux.xyz/auth/register",
           data: JSON.stringify(reg_data), //提交的数据
           contentType: "application/json;charset-UTF-8",
           success: function (result) { //todo
               console.log(result); //打印服务端返回的数据(调试用)
               if (result.status == 0) {
                   alert("注册成功");
                   window.location.href = '登入.html'
               };
           },
           error: function (jqXHR, textStatus, errorThrownt) {
               
               var responseText = jQuery.parseJSON(jqXHR.responseText);
               if (responseText.status == 1001) {
                   alert("用户名已被使用");
               };
               if (responseText.status == 1002) {
                   alert("学号已绑定");
               };
               if (responseText.status == 1003) {
                   alert("教务处认证失败");
               }
           }
       });
    }
    
    • 接入登录接口的代码

    function begin() {
       var login_data = ($('#login_form').serializeJson());
       if (login_data.username == undefined || login_data.password == undefined) {
           alert("用户名或密码不能为空");
           return;
       }
       $.ajax({
           type: "POST",
           dataType: "json",
           url: "https://api.shisanshui.rtxux.xyz/auth/login",
           data: JSON.stringify(login_data), //提交的数据
           contentType: "application/json;charset-UTF-8",
           success: function (result) { //todo
               console.log(result); //打印服务端返回的数据(调试用)
               if (result.status == 0) {
                   token=result.data.token;
                   user_id=result.data.user_id;
                   username=login_data.username
                   console.log(token);
                   localStorage.setItem("token1",token);
                   localStorage.setItem("user_id1",user_id);
                  localStorage.setItem("username1",username);
                   alert("登录成功");
                   window.location.href = '游戏大厅.html'
               };
           },
           error: function (res) {
               // $("#login_form").reset();
               alert("用户名或密码错误");
           }
       });
    }
    function logout(){
       token=localStorage.getItem("temp");
       $.ajax({
           type: "POST",
           url: "https://api.shisanshui.rtxux.xyz/auth/logout",
           beforeSend: function(xhr) {
                   xhr.setRequestHeader("X-Auth-Token",token);
               },
           success: function (result) { //todo
                   console.log(result);
                   console.log(token);
                   alert("注销成功");
                   window.location.href = '点入.html'
               },
           error: function (res) {
               alert("注销失败");
           }
       });
    }
    
    • 接收到牌的接口

    接收到牌的时候,用一个字符串数组储存起来,并且交给AI,AI根据所穿的字符串数组来给出牌来交给服务器。

    • 排行榜的接口

    在排行榜的接口中, 我先接入服务器的接口使用的是get 方式,并根据服务器所返回的数据现场生成一个表格。

    • 接口分析的小结

    这次连接接口的过程中,学习到了ajax,并且了解了get和post两种方式的不同之处。GET - 从指定的资源请求数据。POST - 向指定的资源提交要被处理的数据

    • 使用ajax进行http请求操作,样例如下:

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

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

    算法关键在于三墩回溯中剪枝函数的设计以及分数矩阵评分算法的设计
    流程图如下:

    五、关键代码解释

    • 分数矩阵

    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]
    ];
    
    
    • 三墩回溯

      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];
            }
          }
        }
      }
    
    

    六、性能分析与改进

    • 改进思路

    使用评分矩阵进行评分,并且依据评分进行剪枝,减少回溯的时间。

    • 性能分析图

      • 三次提交出牌结果的CPU性能分析图,可见,在AI算法运行期间,cpu使用达到峰值。

    • 消耗最大函数

      • 局部CPU性能分析图,可见,本AI算法主要是用回溯法找到最优解,所以时间主要花在三墩回溯上。

    七、单元测试

    • 单元测试代码

    function shuffle(array) {
      for (var i = 0; i < array.length; ++i) {
        var pos = Math.floor(Math.random() * (array.length - i));
        var item = array[pos];
        array[pos] = array[array.length - 1 - i];
        array[array.length - 1 - i] = item;
      }
      return array;
    }
    console.time("run time");
    for (var i =0 ; i<=1000 ;++i )
    {
    	tmp=optimize_hand(shuffle([...Array(52).keys()]));
    }
    console.timeEnd("run time");
    
    • 测试代码说明

    随机构造一千种出牌情况,在nodejs上进行测试,输出运行时间。

    • 构造测试数据的思路

    生成大量随机数组,进行随机评测。最坏情况一次46ms,最好情况可以达到一次8ms,主要分布在8-15ms。

    八、Github代码签入记录

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

    • 问题描述

    • 由于前端使用的是浏览器端,一开始我使用的是python写AI,导致了之后前后端无法相连,浏览器限制不能执行本地文件。

    • 在前端设计上,队友和我持不同意见。

    • 做过哪些尝试

    • 最后使用js又写了一遍AI,使得代码能够嵌入html中,得以相连。

    • 相互阐述理由,说服对方。

    • 是否解决

    • 有何收获

    • 掌握了JavaScript一些编程的基本技巧,以及如何嵌入html,在浏览器上运行。

    • 增强了自己的沟通能力。

    十、评价你的队友

    • 值得学习的地方

    能够主动地去找一些素材并使用,主页除了不是动图外,做的还是挺棒的。

    • 需要改进的地方

    有点拖延的习惯,并且不能按时完成自己承诺的项目进度,但是还算比较认真,希望她能改变自己,在今后的工作中越来越棒吧。

    十一、学习进度条

    第N周 新增代码(行) 累计代码(行) 本周学习耗时
    (小时)
    累计学习耗时
    (小时)
    重要成长
    1 100 100 24 24 掌握了一些web前端设计方法,以及python的flask,requests框架
    2 400 500 24 48 掌握了服务器端与客户端的交互方式,并且可以通过编程实现交互,并在谷歌云上设计开发了自己的个人网站
    3 1000 1500 2 50 掌握了nodejs使用和JavaScript编程

    十二、UI展示

  • 相关阅读:
    如何得到运行程序的路径,以及如何得到路径的文件夹,文件名,以及类型等等信息
    STL的心得(4)运用(MFC)
    STL的心得(3)---运用(控制台)
    【Css】清除浮动,独占一行
    [Html]加链接提示
    【JS】清除子节点
    【CSS】使Div在父元素中水平居中
    [JS]回前页
    【JS】鼠标移动到链接上变手型
    【jQuery】改变控件的使能状态
  • 原文地址:https://www.cnblogs.com/wadx2019/p/11675166.html
Copyright © 2020-2023  润新知