结对编程作业

https://github.com/CNllb/pig_end

学号 姓名 分工 博客链接
031902610 刘凌斌 前端界面,模型设计,游戏逻辑 https://www.cnblogs.com/CNLLB/p/15456141.html
131901121 肖清江 AI算法 https://www.cnblogs.com/xiao-qingjiang/p/15456122.html

一、原型设计

(1.1)原型作品链接为:https://app.mockplus.cn/s/WSoYi3myuw7c

(1.2)原型开发工具:在本次结队编程作业中,我们小组采用了操作起来较为简单的Mockup工具对原型进行设计。

(1.3)原型简单说明:

(1)缺点和不足:

① 本次原型设计是由两位直男协同完成的,在审美方面或许还有较大的欠缺,希望大家批评指正。

② 作品链接中的原型作品的原型组件未进行及时更新,较为简陋,下文博客提供实现前后对比。

(2)主要页面原型和实际效果对比:、

原型和小程序实现的机型:iPhone X(812*375)

主要效果的区别产生在原型设计未导入相关字体库和相关图标,实际界面与原型在实现上存在计算误差。

登录页

① 原型:

this is image

② 实际效果:

this is image

首页:

① 原型:

image

② 实际效果:

image

对战界面:

① 原型:

this is image

② 实际效果:

this is image

(1.4)遇到的困难和解决方法:

困难:本次制作原型是我们小组第一次使用原型制作工具,在这过程中最难熬的就是想出一个好的idea,并做好颜色搭配。这对于两个理工男来说并不友好。我们也想过直接使用暴发户气息爆棚的传统斗地主风格,或者直接竖屏实现按钮点击,带出汽配城风格,但还是想着,既然要自己从0开始做一个小程序,那么不管结果如何,总要尽自己的可能,尽可能实现效果好一些。

解决方法:多次讨论之后,我们决定背道而行,将棋牌游戏打出养生的感觉,所以,在图片方面,选择了色调较为柔和的水墨山水画,再结合莫兰迪色系,调出了属于我们小组的软件设计风格。

收获:在原型开发的过程中,我们成员之间可以天马行空,可以一次次地进行犯错,颜色搭配有问题就马上更改颜色,再进行分析,这是软件开发中极为有趣的一部分,我们也开始能够理解UI小姐姐没有灵感时候的痛楚。在这过程中,我们又掌握了一个对软件开发非常有帮助的开发工具。

二、原型设计实现

简易思维导图:

this is image

(2.1)代码实现思路:

(1)网络接口的使用

  • 登录接口的使用

    • 在实现过程中,使用input进行账号和密码的输入,点击登录实现网络通信,成功获取用户信息

    • 登录函数设置了常规输入检测,保证用户名和密码内容不为空,并对登录返回的status进行了判断。

          login: function (e) {
                  var that = this;
                  let formData = e.detail.value;
                  this.setData({
                      student_id:formData.student_id,
                      password:formData.password
                  })
                  console.log(formData);
                  if (that.data.student_id == ""||that.data.password == "") {
                    wx.showModal({
                      title: "错误",
                      content: "用户名或密码不能为空"
                    });
                    that.isname = false;
                    that.ispass = false;
                  } else {
                    that.isname = true;
                    that.ispass = true;
                  }
                  if (that.ispass && that.isname){
                      wx.request({
                          url: 'http://172.17.173.97:8080/api/user/login',
                          header:{
                              "Content-Type":"application/x-www-form-urlencoded"
                          },
                          data: formData,
                          method: "POST",
                          success: function (res) {
                              console.log(res.data);
                              if (res.data.status == 200) {
                                  that.setData({
                                      id_token: res.data.data.token,
                                      response: res
                                  }),
                                  wx.setStorageSync('id_token', that.data.id_token),
                                  wx.navigateTo({
                                      url: '../../pages/home/home',
                                  })
                              }else{
                                  wx.showModal({
                                      title: "错误",
                                      content: "密码或账号错误"
                                    });
                              }
                              
                          },
                          fail: function (res) {
                              console.log(res.data);
                              console.log('is failed');
                              console.log('获取信息失败');
                          }
                      })
                  }
              }
    
  • 获取房间信息的实现

      getHome:function (params) {
          var that = this;
          wx.request({
            url: 'http://172.17.173.97:9000/api/game/index',
            method: "get",
            data:{
              page_size:that.data.page_size,
              page_num:that.data.page_num,
            },
            header:{
              "Authorization": wx.getStorageSync('id_token'),
            },
            success: function (res) {
              console.log(res);
              that.setData({
                home_detail:res.data.data.games,
                isOpenHome:false,
                total_home:res.data.data.total,
                total_pages_num:res.data.data.total_page_num
              })
              console.log(that.data.home_detail);
              console.log(that.data.total_pages_num);
            },
            fail:function(err){
              console.log(err)
            }
          })
        }
  • 加入房间接口实现
      joinHome: function (e) {
          var that = this;
          console.log(e.currentTarget.dataset.uuid);
          wx.request({
            url: 'http://172.17.173.97:9000/api/game/'+this.data.uuid,
            method: "POST",
            header:{
              "Authorization": wx.getStorageSync('id_token'),
              "content-type":'application/json'
            },
            data:{
              uuid:e.currentTarget.dataset.uuid
            },
            success: function (res) {
              that.setData({
                Gaming:true
              })
            },
            fail:function(err){
              console.log(err)
            }
          })
        },
  • 创建房间的接口实现
      createHome: function () {
            var that = this;
            wx.request({
              url: 'http://172.17.173.97:9000/api/game',
              method: "POST",
              data:{
                "private":that.data.private
              },
              header:{
                "Authorization": wx.getStorageSync('id_token'),
              },
              success: function (res) {
                that.setData({
                  uuid: res.data.uuid
                })
                console.log(res);
                console.log(that.data.uuid);
              },
              fail:function(err){
                console.log(err)
              }
            })
        },

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

this is image

(3)贴出你认为重要的/有价值的代码片段,并解释

​ 人机对战之中,AI的实现感觉比较有意思,我们小组是采用设置延时进行实现。在实现的时候,经过2000ms之后,自动实现AI的步骤,模拟较为有效

      setTimeout(() => {
            // 延迟后操作
            that.selectWay()
          }, 2000)

(4)描述你改进的思路

  • 在本来的代码中,对战过程只使用一个界面进行展现,但是在传参过程中,多次造成传参错误,或者逻辑混乱的问题。
  • 在这样的前提下,我们决定了重构代码,一个界面实现两次刷新,这样每个数据都能够单独处理,大大降低了发生逻辑错误的概率。

(5)展示出项目部分单元测试代码,并说明测试的函数,构造测试数据的思路。

  • 本次结队编程项目,我们小组采用的是微信小程序进行实现,出于微信小程序的局限性,并未进行小程序代码的单独单元测试。但对各个函数进行了单独封装,并进行多次单例测试。
      // 封装的抽牌函数
      POP_Get_pork_1: function () {
          var that = this;
          this.data.last_value = this.data.now_value;
          this.data.now_pork = this.data.get_pork_set.pop();
          this.data.now_value = this.data.now_pork.value;
          this.data.set_pork_set.push(this.data.now_pork)
          switch (Math.floor((this.data.now_pork.value - 1) / 13)) {
            case 0:
              this.setData({
                get_pork_black_peach_count: this.data.get_pork_black_peach_count - 1,
              })
              break;
            case 1:
              this.setData({
                get_pork_red_heart_count: this.data.get_pork_red_heart_count - 1,
              })
              break;
            case 2:
              this.setData({
                get_pork_black_flower_count: this.data.get_pork_black_flower_count - 1,
              })
              break;
            default:
              this.setData({
                get_pork_red_block_count: this.data.get_pork_red_block_count - 1
              })
              break;
          };
          that.check_card_1();
          that.check_winner();
          this.setData({
            now_pork: this.data.now_pork,
            now_index: (this.data.now_index + 1) % 2,
            set_pork_block: this.data.set_pork_set.length == 0 ? false : true,
            get_pork_block: this.data.get_pork_set.length == 0 ? false : true,
            player1_black_peach_count: this.data.player1_black_peach.length,
            player1_red_heart_count: this.data.player1_red_heart.length,
            player1_black_flower_count: this.data.player1_black_flower.length,
            player1_red_block_count: this.data.player1_red_block.length
          });
          that.set_top_card_1();
          if (this.data.get_pork_set.length == 0) {
            this.setData({
              get_pork_block: true
            })
          }
        },
      // 封装的检查牌堆函数
      check_card_1: function () {
          if (Math.floor((this.data.now_value - 1) / 13) == Math.floor((this.data.last_value - 1) / 13)) {
            while (this.data.set_pork_set.length != 0) {
              var pork_1 = this.data.set_pork_set.pop();
              console.log(pork_1);
              switch (Math.floor((pork_1.value - 1) / 13)) {
                case 0:
                  this.data.player1_black_peach.push(pork_1);
                  break;
                case 1:
                  this.data.player1_red_heart.push(pork_1);
                  break;
                case 2:
                  this.data.player1_black_flower.push(pork_1);
                  break;
                default:
                  this.data.player1_red_block.push(pork_1);
                  break;
              }
            }
            this.data.last_value = null;
            this.data.now_value = null;
          }
        },
      // 封装的设置牌顶的函数
      set_top_card_1: function () {
          this.setData({
            player1_top_black_peach: this.data.player1_black_peach.pop(),
            player1_top_red_heart: this.data.player1_red_heart.pop(),
            player1_top_black_flower: this.data.player1_black_flower.pop(),
            player1_top_red_block: this.data.player1_red_block.pop()
          })
          if (this.data.player1_top_black_peach != null) {
            this.data.player1_black_peach.push(this.data.player1_top_black_peach)
          }
          if (this.data.player1_top_red_heart != null) {
            this.data.player1_red_heart.push(this.data.player1_top_red_heart)
          }
          if (this.data.player1_top_black_flower != null) {
            this.data.player1_black_flower.push(this.data.player1_top_black_flower)
          }
          if (this.data.player1_top_red_block != null) {
            this.data.player1_red_block.push(this.data.player1_top_red_block)
          }
        },
      // 封装的检查对局胜利的函数
      check_winner: function () {
          if (this.data.get_pork_set.length == 0) {
            this.setData({
              Gaming: false
            })
            if (this.data.player1_black_peach_count + this.data.player1_red_heart_count + this.data.player1_black_flower_count + this.data.player1_red_block_count > this.data.player2_black_peach_count + this.data.player2_red_heart_count + this.data.player2_black_flower_count + this.data.player2_red_block_count) {
              this.setData({
                winner: this.data.player_2
              })
            } else {
              this.setData({
                winner: this.data.player_1
              })
            }
          }
        }

(2.2)贴出Github的代码签入记录,合理记录commit信息。

小组的很大的不足:小组成员欠缺日常对Github的使用习惯,没有养成及时push代码的习惯,我们的commit记录并不好

this is image

小组有设置todo的习惯,以下是我们小组的todo记录截图(使用的是“敬业签”APP):

this is image

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

(1)在代码模块异常方面,前期的网络通信采用Postman进行模拟网络通信,和实际实现校园网通信有很大的不同,微信小程序对局域网通信的不支持也是一个很大的问题。在刚接入校园网的时候,各种报错,是真的头大。

解决办法:微信开发者工具强行不检查网络的证书和合法性,再接入校园网,成功获取信息。

(2)结队困难:首先,这是和队友的第一次合作,在实现代码的过程中,没有那么的默契。其次,两个人对各自负责的领域,了解得都不够深刻,前端对微信开发者工具的相关合法性不够了解,后端对框架不够熟练,这就造成了到处碰壁。

解决方法:通过制定todo进行计划,保证项目顺利地进行。

(2.4)评价你的队友。

  • 值得学习的地方:

    学习能力很强,也很热衷学习新事物,今后我也要做到这一点,无论是在软件开发领域还是其他领域。

  • 需要改进的地方:

    有时候联系不上哈哈,希望之后可以保持更紧密的联系哈哈。

(2.5)提供此次结对作业的PSP和学习进度条(每周追加)

N周 新增代码(行) 累计代码(行) 本周学习耗时(小时) 累计学习耗时(小时) 重要成长
1 0 0 12 12 前端:学习安卓开发和微信小游戏的开发;后端:考虑使用Java进行后端编程,对Java基础知识进行巩固
2 1000 1000 12 24 前端:学了一周的游戏引擎和微信小游戏开发后,果断放弃,短时间把握不住,做了无用功,第2周,对原型进行设计,并实现微信小程序界面;后端:学习使用flask框架的python后端开发;
3 2500 3500 8 32 前端:实现微信小程序打牌逻辑,制作简易的人机对战;后端:完成AI的百分80代码。
4 1000 4500 10 42 前端:对代码进行封装,使得游戏的逻辑清晰明了,遗憾是,在线对战代码重构还未全部完成;后端:完成AI,并制作接口

三、心得

刘凌斌:

作业难度:本次作业给我带来的最大的困难应该是在游戏逻辑的实现,犯了专业性的错误,对各个操作的代码并未实现有效的封装。造成了后期代码需要重构,浪费了很多的时间;其次是对时间的规划不够合理,前期想要实现很多附属功能,后面发现附属功能还未完成,主要功能来不及实现,只能草草的实现,效果很差,这是犯的很致命的错误。

作业感想:即使本次作业完成的并不完善,但我们小组仍然会在后期将这个项目实现完全,也会开始学会习惯使用GitHub进行代码的pull和push,也借此提高自己的代码能力。

启发:制定项目需求一定要合理,要与实力相互匹配,不能好高骛远,要一直学下去,我们不会的还有很多东西。

肖清江:

作业难度: 这次作业难度我个人感觉较大,因为之前没有开放一个可以联网的功能(在线对战),只做过命令行小游戏,并且也没有做过前后端分离的工作(之前甚至分不清前后端),所以这次的作业对我挑战还是相当大的。
作业感想: 即使这次作业难度较大,但我还是尽量根据完成作业的需要去学相对应的内容。虽然起步的时候相当困难,但好在b站大学有各种各样的学习资料嘿嘿,终于还是学会了flask框架来实现后端,总而言之,完成这次作业还是相当有满足感的,尤其是看到自己的代码能给成功应用的时候!
启发: 这次给我最大的启发就是,要勇于尝试新事物,之前一直害怕学来不及,但不管如何,尽力而为,最终一定能得到收获,相信自己,勇于尝试新事物!

原文地址:https://www.cnblogs.com/xiao-qingjiang/p/15456122.html