2023软工K班结对编程任务

github项目链接
Bilibili视频地址

一、结对探索(4分)(汉字序号为一级标题,下同)

1.1 队伍基本信息(1分)(阿拉伯数字序号为二级标题,下同)

结对编号:_ 17__;队伍名称:_ 星之队___;

学号姓名作业博客链接具体分工
102101431林宏宇https://blog.csdn.net/2201_75609739/article/details/133799248?spm=1001.2014.3001.5502UI界面设计、博客、后端
102101414韦星星https://bbs.csdn.net/topics/617402113原型设计、前端页面设计、AI算法

1.2 描述结对的过程(1分)
宿舍就在同一楼层,就近原则,同班同学,平时熟悉,便于交流讨论。

1.3 非摆拍的两人在讨论设计或结对编程过程的照片(2分)

在这里插入图片描述

二、原型设计(16分)

2.1 原型工具的选择(2分)

(在此处说明选择了什么原型设计工具?为什么选择这一款原型软件?)

采用的是墨刀原型工具,因为墨刀可以在线协作,团队成员可以很方便的在同一个原型上面做修改,免去了其他原型工具要传文件的麻烦,同时墨刀对初学者比较友好,上手几乎没说什么难度,可以很好的实现所要实现的界面,还有墨刀免费试用,对我们这样的学生党比较友好。

2.2 遇到的困难与解决办法(3分)

(原型设计过程中的困难描述、解决尝试、是否解决、有何收获)

  • 原型设计过程中的困难描述:
    • 在原型设计过程中,找到合适的无水印图片和图标是一大挑战。
  • 解决尝试:
    -在文心一言和ChatGPT的推荐下找了一些免费的UI设计的资源网站,如https://www.iconfont.cn/ (可用于寻找一些矢量图标,同时也是免费的)、https://unsplash.com/ (可用于寻找一些风景的图片,优点是所有图片都是由其创作者自愿免费分享出来,无需经过允许即可任意使用,同时都是非常优质的高清图片,本次作业使用的背景图片也是来自这个网站,免去了图片版权的争议)、https://www.flaticon.com/ (提供很多免费矢量图标,图标样式非常全,很多都支持SVG格式免费下载)等.
  • 是否解决
    • 这些网站上的资源都极大地帮助了我解决原型设计中的素材问题,最后成功解决了素材的问题.
  • 有何收获
    • 这次经历教会我,当遇到困难时,要善于利用搜索引擎和大模型工具。很多时候,这些工具能起到事半功倍的效果。在大模型时代,我们需要跟上时代的步伐,才不会被淘汰。在未来,我会继续运用这些工具,以高效、精准的方式解决工作中的问题。

2.3 原型作品链接(5分)

(静态原型作品得2分,交互性强的原型作品得5分)

https://modao.cc/app/design/pblmncofewr3gwxw

2.4 原型界面图片展示(6分)

(尽可能图文并茂地在此处介绍你们队伍设计的各功能模块,创新点也在此处展示说明)

  1. 起始页

    • 开始游戏的界面上,渲染着浓郁的水墨中国风画卷,两个人物矗立在中央,象征着狭路相逢勇者胜的斗志。然而,勇者并非仅凭勇气就能获得最后的胜利,谋略才是关键,也是。在每一轮中,你需要慎重地选择投掷出骰子的最优解,以便在最后关头胜天半子。

    • 当点击开始游戏的祥云图标时,我们特意加入了emit动画效果,为这个水墨风画面增添了一抹亮色。这不仅使画面更加生动有趣,也提高了用户体验的愉悦度。

    • 右下角古书性状的按钮用于跳转到用户的个人信息界面,古书的形状符合古代记录信息的载体,也和页面比较融合协调

    • 这个小程序采用了旁门正道粗书体,这种字体既蕴含着洪荒历史的底蕴,又拥有时尚现代的特色。它以独特华丽的纹理完美融合了古代经典和时尚新潮,展现了古今文化艺术的精髓,令人叹为观止。这种字体与小程序的主题相得益彰,更加凸显了古今文化的交融。

    • 在这个小程序中,你将有机会体验到古老与现代的完美结合,感受到中国水墨画的独特魅力和智慧。让我们一起投身于这个充满挑战与机遇的胜天半子游戏中,体验智慧与勇气的较量,探索天人合一的境界!

在这里插入图片描述

  1. 选择页
    • 在选择页面的设计中,我们依然采用了水墨风格作为背景,以崇山峻岭为底图,传递出山外有山、人外有人的道理,提醒玩家切勿骄傲自满。在页面下方,我们添加了一艘小舟,为页面增添了一抹江南水乡的韵味,使整体设计更具水墨特色。
    • 在选择页面中,我们划分了四个选项:本地对战、人机对战、双人对战和游戏规则。每个选项都以祥云图案进行点缀,寓意着骰子游戏在谋略的同时也带有一定的随机性。我们希望玩家在游戏过程中不仅能体验到游戏的乐趣,还能在游戏过程中放松身心,享受轻松愉快的氛围。
    • 在右上角,我们采用了古代桌案的图案,这一设计灵感源自古代桌案的形象,它将成为玩家从其他页面返回选择页面的重要标志。通过点击这一图案,玩家可以轻松返回到选择页面,以便随时开始新的游戏挑战。

在这里插入图片描述

  1. 准备页(本地对战)

    • 在本地对战的页面中,我们选用了一幅侠客在半山腰吹笛子的背景图片,这幅画面的色彩和氛围充满了古风气息。我https://img-community.csdnimg.cn/images/6aec1ed2c2d84f159c9b085f930e9de9.png “#left”)
      们希望当玩家选择本地对战时,能感受到古代侠客的仙风道骨,那种会当凌绝顶、一览众山小的气概。即使前行的路上可能一个人踽踽前行,也不要忘记自己的初心。

    • 在游戏中,每个玩家都有机会成为胜者,每个人都有可能成为那个笑到最后的人。在这个过程中,玩家们需要勇气、智慧,还有坚持。希望每个玩家都能在这个小程序中找到乐趣,找到挑战,找到自我。

在这里插入图片描述

  1. 本地对战

    • 在本地对战界面设计中,我们以山峦为背景,将玩家的头像放置在群山之巅,以此呼应“胜天半子”小程序的主题。
    • 在页面的上方显示玩家的信息,当前投掷的玩家会被显示在轮播图的第一个,同时显示玩家的姓名,积分和和筹码数。
    • 投掷区由公共投掷区和选定区两部分组成。当玩家点击投掷按钮,公共投掷区会随机生成五个1至6的骰子。如果玩家点击某个骰子,该骰子就会按照玩家点击的顺序依次显示在选定区中。同时,在点击的骰子下方会显示一个锁定标志,表示该骰子已被选定。
    • 当某个玩家的选定区的五个"?"骰子都被填充为具体的骰子后,在页面的左下方会显示"计算"图标,当用户点击这个图标,后台就会调用函数计算出此玩家的点数和牌型,显示在选定区的地下
    • 在“投掷”文字的后面我们增加了一个浪花的图标,为页面增添了更多的趣味性,同时提升了用户体验。

在这里插入图片描述

  1. 准备页(双人对战&人机对战)

    • 页面与本地对战类似,删去了输入人数的文本输入框

在这里插入图片描述

  1. 人机对战

    • 在人机对战页面设计中,我们保持了与本地对战页面类似的布局,但增加了敌方选定区和AI头像,突出了人工智能元素。具体要点如下:

    • 敌方选定区:在页面右上方,设立了一个敌方选定区。这个区域会显示AI选择的五个骰子。

    • 公共投掷区:在页面中央,设立了一个公共投掷区,此区域会随机生成五个1-6的骰子,供所有人(包括AI)选择。

    • 我方选定区:在页面左上方,设立了我方选定区。这个区域会显示我方玩家已选择的五个骰子。

    • 筹码数:在页面左下角,会显示我方玩家的筹码数。

    • 在人机对战中,默认的AI头像是一个机器人站在芯片上,以此突出当今芯片技术对人工智能发展的重要性。这种设计不仅增添了人机对战的趣味性,也使小程序的主题更加鲜明。

在这里插入图片描述

  1. 房间号

    • 房间号这个元素是用来实现联机对战的标识,是一个唯一的标识符,用于识别特定的游戏或比赛房间。

    • 页面的背景图片是一个玫红色点缀的亭子,也呼应了房间号的页面主题,是一种彩色元素,它的引入打破了水墨风格的单调,为页面设计增加了活泼的元素,使整体视觉效果更为丰富。

    • 进入房间按钮使用流云加以点缀,增添了视觉效果。

在这里插入图片描述

  1. 双人对战

    • 与人机对战类似,将敌方选定区的头像设置为对方玩家的头像

在这里插入图片描述

  1. 游戏规则

    • 游戏规则页面详细说明了这个小程序的规则

在这里插入图片描述

  1. 结算页

    • 当游戏一轮结束时,屏幕上会展示一个精美的结算页面。
    • 在传统的“结算”二字之间,巧妙地插入了一个古代钱币的图案,使得原本单调的文字立刻变得生动而引人注目。
    • 不仅传达出游戏与古代文化的紧密联系,还为玩家带来了丰富的视觉享受,进一步提升了游戏的趣味性。

在这里插入图片描述

  1. 对战积分排行榜

    • 在标题的上方,采用了古代卷轴的形状,使整个界面充满了古典的气息。

    • 背景图像则选用了险峻的山峰,寓意着在这个积分排行榜上,能够取得一席之地的都是出类拔萃的玩家,他们不仅具备勇气和谋略,还需时刻保持警惕,不可大意轻敌。因为一旦疏忽,便可能一失足成千古恨。

    • 因此,这个排行榜上的竞争愈发激烈,每一座山峰都代表着更高层次的挑战。但同时,这并不意味着没有永恒的第一,因为只有不断追求进步,方能在激烈竞争中立足。

在这里插入图片描述

  1. 选择角色

    • 提供了12个系统角色,用户可以根据自己的喜好选择相应的角色
  • 当用户选定了相应的角色,个人信息页就会显示相应的头像和名字

在这里插入图片描述

三、编程实现(14分)

3.1 网络接口的使用(2分)
在微信开发中工具中使用了云开发

updateRanking(){
    wx.showLoading({
      title: '正在更新',
      mask:true,
    })
    db.collection("ranking").orderBy("score","desc").get().then(res=>{
      console.log(res)
      this.setData({
        rankingList:res.data
      })
      wx.hideLoading()
    })
  },

  //点击发布按钮去
  onSubmit(){
    let value = this.data.iptValue
    db.collection("comment").add({
      data:{
        comment:value
      }
    }).then(res=>{
      wx.showToast({
        title: '发布成功',
        icon:"none"
      })
      db.collection("comment").get().then(res=>{
        console.log(res)
        this.setData({
          comment:res.data,
        })
      })
    })
    this.setData({
      iptValue: ''
    })
  },

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

在整个游戏的后端,我们主要运
用三个函数来实现整个游戏的主要功能,运用clickthrow()函数实现投掷功能,clickdice()函数实现对公共投掷区骰子的选定功能,clickReset()函数实现每一次对对局完成以后对筹码的结算 以及,公共投掷区、选定区的数据清楚工作并开启下一局的对局。

在这里插入图片描述

3.3 说明算法的关键与关键实现部分流程图(2分)

在每次公共投掷区投掷了投掷以后我们通过绑定点击触发事件clickdice()函数,将公共投掷区的骰子数据传到选定区区,同时将维护一个bool变量将已经选定的选定区的骰子以及公共投掷区的骰子进行锁定。再维护一个bool变量触发倍率选择事件。

在这里插入图片描述

  clickThrow(){
    const dice_pic = this.data.dice_pic
    const player_num = this.data.player_num
    const pubdice = this.data.pubdice
    const dice = this.data.dice
    const isSelect = this.data.isSelect
    const isConfirm = this.data.isConfirm
    let throwTimes = this.data.throwTimes
    const isLock = this.data.isLock
    const mydice = this.data.mydice
    let selectNum = this.data.selectNum
    let myDiceNum = this.data.myDiceNum
    let isAddTime = this.data.isAddTime
    let current_player = this.data.current_player
    let current_num = this.data.current_num
    let turn_num = this.data.turn_num

    if(isConfirm == true) {
      throwTimes[current_player] += 1;
    }

    
    // // 每按一次投掷和确认玩家的索引就加1,当索引值为6说明一轮投掷结束则进行下一轮
    if(isConfirm == true) {
      if(throwTimes[current_player] != 3) {
        current_player += 1
      }
      if(current_player == player_num) {
        current_player %= player_num
        turn_num += 1
      }
    }

    // 如果公共投掷区的骰子还有没有被锁定的,则随机生成未被锁定的骰子(在按钮的状态为投掷的情况下)
    for(let i = 0; i < 5; i++) {
      if(isSelect[current_player][i] == false && isConfirm == false) {
        // 随机生成未被锁定的骰子
        dice[current_player][i] = parseInt(Math.random()*6+1);
        // 设置公共投掷区骰子的图片
        // pubdice[current_player][i] = `../../static/images/dice${dice[current_player][i]}.png`;
        pubdice[current_player][i] = dice_pic[dice[current_player][i]-1];
      }
    }

    // 如果当前按钮的状态为确认
    if(isConfirm == true) {
      // throwTimes[current_player] += 1;
      // 如果某个玩家的投掷次数为3,则自动将其锁定剩下未锁定的骰子
      if(throwTimes[current_player] == 3) {
        for(var i = 0; i < 5; i++) {
          if(isLock[current_player][i] == false) {
            isLock[current_player][i] = true;
            // mydice[current_player][i] = `../../static/images/dice${dice[current_player][i]}.png`;
            mydice[current_player][i] = dice_pic[dice[current_player][i]-1];
            myDiceNum[current_player][i] = dice[current_player][i]
            selectNum[current_player] = selectNum[current_player] + 1;
            // setTimeout(function() {  
            // }, 1000);  
          }
        }
        throwTimes[current_player] %= 3
      }
      // isAddTime = false
    }

    // console.log("投掷次数:");
    console.log(throwTimes);


    this.setData({
      pubdice:pubdice,
      dice:dice,
      isSelect:isSelect,
      isConfirm:!isConfirm,
      throwTimes:throwTimes,
      isLock:isLock,
      mydice:mydice,
      selectNum:selectNum,
      myDiceNum:myDiceNum,
      isAddTime:isAddTime,
      current_player:current_player,
      current_num:current_num,
      turn_num:turn_num
    })

  },

  clickReset(){
    const dice_pic = this.data.dice_pic
    const pubdice = this.data.pubdice
    const isLock = this.data.isLock
    const isSelect = this.data.isSelect
    const mydice = this.data.mydice
    const myDiceNum = this.data.myDiceNum
    let current_num = this.data.current_num
    let points = this.data.points
    let lastPoint = this.data.lastPoint
    const player_num = this.data.player_num
    let totalTime = this.data.totalTime
    let maxPoint = this.data.maxPoint
    let maxIndex = this.data.maxIndex
    let money = this.data.money
    let throwTimes = this.data.throwTimes
    let current_player = this.data.current_player
    let selectNum = this.data.selectNum
    let brandTypes = this.data.brandTypes
    let turn_num = this.data.turn_num
    let isCalculate = this.data.isCalculate
    let total_num = this.data.total_num
    let win_num = this.data.win_num

    if(isCalculate[current_player] == false) {
      // 计算上一个玩家的积分和牌型
      lastPoint = brandPoint(myDiceNum[current_player])
      let point = 0;
      for(let i = 0; i < 5; i++) {
        point += myDiceNum[current_player][i]
      }
      points[current_player] += point

      var lastType = brandType(myDiceNum[current_player])
      brandTypes[current_player] = lastType

      // 将当前玩家的是否计算过属性设置为true
      isCalculate[current_player] = true
    }




    // 如果是某一局的第三轮,则进行结算
    if(turn_num == 2 && current_player == player_num - 1) {
      for(let i = 0; i < player_num; i++){
        if(points[i] > maxPoint) {
          maxPoint = points[i];
          maxIndex = i
        }
      }
      for(let i = 0; i < player_num; i++) {
        if(i != maxIndex) {
          money[i] -= totalTime * (maxPoint - points[i])
        }else {
          for(let j = 0; j < player_num; j++) {
            if(j != maxIndex) {
              money[i] += totalTime * (maxPoint - points[j])
            }
          }
        }
      }
      win_num[maxIndex] + 1;

      totalTime=1
      turn_num=0
      current_num+=1

      // 当一个玩家锁定的骰子个数为5时,将公共投掷区和选定区初始化
      for(var i = 0; i < player_num; i++) {
        for(var j = 0;j < 5; j++) {
          // pubdice[i][j] = `../../static/images/dice7.png`;
          pubdice[i][j] = dice_pic[6];
          // mydice[i][j] = `../../static/images/dice7.png`;
          mydice[i][j] = dice_pic[6];
          isSelect[i][j] = false;
          isLock[i][j] = false;
        }
        selectNum[i] = 0
        throwTimes[i] = 0
        points[i] = 0;
        brandTypes[i] = "暂无"
      }
      
      wx.showToast({
        title: '本轮对战结束!',
        icon:'success',
        duration:2000,
        mask:true
      })
    }


    this.setData({
      pubdice:pubdice,
      selectNum:selectNum,
      isLock:isLock,
      isSelect:isSelect,
      isConfirm:false,
      mydice:mydice,
      current_num:current_num,
      points:points,
      money:money,
      maxPoint:maxPoint,
      maxIndex:maxIndex,
      totalTime:totalTime,
      throwTimes:throwTimes,
      current_player:(current_player + 1)%player_num,
      brandTypes:brandTypes,
      turn_num:turn_num,
      win_num:win_num
    })
  },

  clickDice(e){
    const dice_pic = this.data.dice_pic
    const isSelect = this.data.isSelect
    const mydice = this.data.mydice
    const dice = this.data.dice
    let selectNum = this.data.selectNum
    const isLock = this.data.isLock
    const isConfirm = this.data.isConfirm
    const myDiceNum = this.data.myDiceNum
    const current_player = this.data.current_player

    // console.log(e);
    var index = e.currentTarget.dataset.index; //获取当前点击的索引  
    console.log(index); 

    if(isLock[current_player][index] == false && isConfirm == true) {
      isSelect[current_player][index] = true;
      // mydice[current_player][selectNum[current_player]] = `../../static/images/dice${dice[current_player][index]}.png`
      mydice[current_player][selectNum[current_player]] = dice_pic[dice[current_player][index]-1]
      myDiceNum[current_player][selectNum[current_player]] = dice[current_player][index]
      isLock[current_player][index] = true 
      selectNum[current_player] = selectNum[current_player] + 1
    }
    this.setData({
      isSelect:isSelect,
      mydice:mydice,
      selectNum:selectNum,
      isLock:isLock,
      myDiceNum:myDiceNum,
    })
    // console.log(selectNum);
  },

3.4 贴出重要的/有价值的代码片段并解释(2分)

brandPoint函数用于将输入的五个数字的数组,返回这五个骰子获得的点数

function brandPoint(arr) {    
  var counts = {}; // 用于存储元素及其出现的次数    
  var duplicates = []; // 用于存储重复的数字    
  var maxTimes = 0;
  var lastPoint = 0
  for (var i = 0; i < arr.length; i++) {    
    if (counts[arr[i]]) {    
      if(counts[arr[i]] == 1) {
        duplicates.push(arr[i]); 
      }  
      counts[arr[i]]++; 
    } else {    
      counts[arr[i]] = 1;    
    }    
  }    
  
  for(var i = 0; i < duplicates.length; i++) {
    if(counts[duplicates[i]] > maxTimes) {
      maxTimes = counts[duplicates[i]];
    }
  }
  if(maxTimes == 2 && duplicates.length == 2) {
    lastPoint = 10
  }else if(maxTimes == 3 && duplicates.length == 2) {
    lastPoint = 20
  }else if(maxTimes == 3 && duplicates.length == 1) {
    lastPoint = 10
  }else if(maxTimes == 4 && duplicates.length == 1) {
    lastPoint = 40
  }else if(maxTimes == 5 && duplicates.length == 1) {
    lastPoint = 100
  }else if(maxTimes == 0 && isConsecutive(arr) == false) {
    lastPoint = 30
  }else if(maxTimes == 0 && isConsecutive(arr) == true) {
    lastPoint = 60
  } 
  console.log(maxTimes)
  return lastPoint;    
}    
function isConsecutive(arr) {  
  // 对数组进行排序  
  arr.sort((a, b) => a - b);  
  // 检查数组中的每个元素是否比前一个元素大1  
  for(let i = 1; i < arr.length; i++) {  
      if(arr[i] !== arr[i-1] + 1) {  
          return false;  
      }  
  }  
  return true;  
} 

当用户点击了计算按钮后,根据不同场景做出不同的判断

clickReset(){
    const dice_pic = this.data.dice_pic
    const pubdice = this.data.pubdice
    const isLock = this.data.isLock
    const isSelect = this.data.isSelect
    const mydice = this.data.mydice
    const myDiceNum = this.data.myDiceNum
    let current_num = this.data.current_num
    let points = this.data.points
    const player_num = this.data.player_num
    let totalTime = this.data.totalTime
    let maxPoint = this.data.maxPoint
    let maxIndex = this.data.maxIndex
    let money = this.data.money
    let throwTimes = this.data.throwTimes
    let current_player = this.data.current_player
    let selectNum = this.data.selectNum
    let brandTypes = this.data.brandTypes
    let turn_num = this.data.turn_num
    let isCalculate = this.data.isCalculate

    if(isCalculate[current_player] == false) {
      // 计算上一个玩家的积分和牌型
      lastPoint = brandPoint(myDiceNum[current_player])
      let point = 0;
      for(let i = 0; i < 5; i++) {
        point += myDiceNum[current_player][i]
      }
      points[current_player] += point

      var lastType = brandType(myDiceNum[current_player])
      brandTypes[current_player] = lastType

      // 将当前玩家的是否计算过属性设置为true
      isCalculate[current_player] = true
    }

    // 如果是某一局的第三轮,则进行结算
    if(turn_num == 2 && current_player == 5) {
      for(let i = 0; i < 6; i++){
        if(points[i] > maxPoint) {
          maxPoint = points[i];
          maxIndex = i
        }
      }
      for(let i = 0; i < 6; i++) {
        if(i != maxIndex) {
          money[i] -= totalTime * (maxPoint - points[i])
        }else {
          for(let j = 0; j < 6; j++) {
            if(j != maxIndex) {
              money[i] += totalTime * (maxPoint - points[j])
            }
          }
        }
      }

      totalTime=1
      turn_num=0
      current_num+=1

      // 当一个玩家锁定的骰子个数为5时,将公共投掷区和选定区初始化
      for(var i = 0; i < player_num; i++) {
        for(var j = 0;j < 5; j++) {
          // pubdice[i][j] = `../../static/images/dice7.png`;
          pubdice[i][j] = dice_pic[6];
          // mydice[i][j] = `../../static/images/dice7.png`;
          mydice[i][j] = dice_pic[6];
          isSelect[i][j] = false;
          isLock[i][j] = false;
        }
        selectNum[i] = 0
        throwTimes[i] = 0
        points[i] = 0;
        brandTypes[i] = "暂无"
      }
    }
    this.setData({
      pubdice:pubdice,
      selectNum:selectNum,
      isLock:isLock,
      isSelect:isSelect,
      isConfirm:false,
      mydice:mydice,
      current_num:current_num,
      points:points,
      money:money,
      maxPoint:maxPoint,
      maxIndex:maxIndex,
      totalTime:totalTime,
      throwTimes:throwTimes,
      current_player:(current_player + 1)%6,
      brandTypes:brandTypes,
      turn_num:turn_num
    })
  }
//倍率选择函数
  select_Magnification: function (my_integral, enemy_integral) {
    let val = enemy_integral - my_integral;
    if (val < 0) {
      return 0;
    } else if (val >= 1 && val <= 5) {
      return 1;
    } else if (5 < val && val <= 10) {
      return 2;
    } else {
      return 3;
    }
  },
  count_same: function (enemy_selectNum, newcam, special, newdice) {
    var count = 0;
    for (let i = 0; i < 5; i++) {
      for (let j = 0; j < 5; j++) {
        if (special[i] == newcam[j]) {
          if (j >= enemy_selectNum) {
            newdice[count] = j;
          }
          count++;
          newcam[j] = -1;
          break;
        }
      }
    }
    return count;
  },

  match_special: function (dice) {
    let sum = 0;
    for (let i = 0; i < 5; i++) {
      sum += dice[i];
    }
    for (let i = 0; i < 7; i++) {
      var newcam = [0, 0, 0, 0, 0];
      for (let i = 0; i < 5; i++) {
        newcam[i] = dice[i];
      }
      var index = [-1, -1, -1, -1, -1];
      var count = this.count_same(0, newcam, this.data.special[i], index);
      if (count == 5) {
        return this.data.integral[i] - sum;
      }
    }
    return 0;
  },

  robot_decision: function (enemy_selectNum, dice, pubdice) {
    // var enemy_selectNum=4
    //  var dice=[2,3,4,6,0];
    //  var pubdice=[0,0,0,0,1];
    var cam = [0, 0, 0, 0, 0];
    for (let i = 0; i < 5; i++) {
      if (dice[i] != 0) {
        cam[i] = dice[i];
      } else {
        cam[i] = pubdice[i];
      }
    }
    var count = 0;
    var integral1 = 0;
    for (let i = 0; i < 7; i++) {
      var newcam = [0, 0, 0, 0, 0];
      for (let i = 0; i < 5; i++) {
        newcam[i] = cam[i];
      }
      var newdice = [-1, -1, -1, -1, -1];
      var newcount = this.count_same(enemy_selectNum, newcam, this.data.special[i], newdice);
      if (newcount >= count) {
        count = newcount;
        if (this.data.integral[i] > integral1) {
          dice = newdice;
        }
      }
    }
    return dice;
  },

 **3.5 性能分析与改进**(2分)

 (描述你改进的思路,展示性能分析图和程序中消耗最大的函数)
brandPoint()这个函数的主要逻辑是检查数组中的重复元素数量以及最大的重复次数,并根据这些信息来决定最后的得分。不过,这个函数有一些可以改进的地方。

首先,这个函数在处理数组中的重复元素时,只关注了它们的数量,而没有考虑到它们的相对位置。例如,对于数组 [1, 2, 2, 3, 3, 3],虽然有两个数字 2 和三个数字 3,但是它们并不在连续的位置上。因此,我们可能需要更细致地处理数组中的元素,以判断哪些元素是真正连续的。

其次,这个函数对于最大重复次数的处理,只有0、2、3、4、5几种情况,这似乎过少。实际上,我们可能需要处理更多的情况。

```javascript
function brandPoint(arr) {    
  var counts = {}; // 用于存储元素及其出现的次数    
  var duplicates = []; // 用于存储重复的数字    
  var maxTimes = 0;
  var lastPoint = 0
    
  for (var i = 0; i < arr.length; i++) {    
    if (counts[arr[i]]) {    
      if(counts[arr[i]] == 1) {
        duplicates.push(arr[i]); 
      }  
      counts[arr[i]]++; 
    } else {    
      counts[arr[i]] = 1;    
    }    
  }    
  
  for(var i = 0; i < duplicates.length; i++) {
    if(counts[duplicates[i]] > maxTimes) {
      maxTimes = counts[duplicates[i]];
    }
  }
  if(maxTimes == 2 && duplicates.length == 2) {
    lastPoint = 10
  }else if(maxTimes == 3 && duplicates.length == 2) {
    lastPoint = 20
  }else if(maxTimes == 3 && duplicates.length == 1) {
    lastPoint = 10
  }else if(maxTimes == 4 && duplicates.length == 1) {
    lastPoint = 40
  }else if(maxTimes == 5 && duplicates.length == 1) {
    lastPoint = 100
  }else if(maxTimes == 0 && isConsecutive(arr) == false) {
    lastPoint = 30
  }else if(maxTimes == 0 && isConsecutive(arr) == true) {
    lastPoint = 60


  } 


  console.log(maxTimes)
  return lastPoint;    
}    


function isConsecutive(arr) {  
  // 对数组进行排序  
  arr.sort((a, b) => a - b);  

  // 检查数组中的每个元素是否比前一个元素大1  
  for(let i = 1; i < arr.length; i++) {  
      if(arr[i] !== arr[i-1] + 1) {  
          return false;  
      }  
  }  

  return true;  
} 

3.6 单元测试(2分)

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

  1. 展示出项目部分单元测试代码
describe('brandPoint function', () => {  
  it('returns 10 when given [1, 1, 2, 2, 3]', () => {  
    expect(brandPoint([1, 1, 2, 2, 3])).toBe(10);  
  });  
  
  it('returns 20 when given [2, 2, 2, 3, 3]', () => {  
    expect(brandPoint([2, 2, 2, 3, 3])).toBe(20);  
  });  
  
  it('returns 30 when given [5, 5, 5, 5, 5]', () => {  
    expect(brandPoint([5, 5, 5, 5, 5])).toBe(100);  
  });  
  
  it('returns 60 when given [1, 2, 3, 4, 5]', () => {  
    expect(brandPoint([1, 2, 3, 4, 5])).toBe(60);  
  });  
  
  it('returns 100 when given [1, 2, 3, 5, 6]', () => {  
    expect(brandPoint([1, 2, 3, 5, 6])).toBe(30);  
  });  
  
  it('returns 0 when given []', () => {  
    expect(brandPoint([])).toBe(0);  
  });  
});

// 测试的函数如下
function brandPoint(arr) {    
  var counts = {}; // 用于存储元素及其出现的次数    
  var duplicates = []; // 用于存储重复的数字    
  var maxTimes = 0;
  var lastPoint = 0
    
  for (var i = 0; i < arr.length; i++) {    
    if (counts[arr[i]]) {    
      if(counts[arr[i]] == 1) {
        duplicates.push(arr[i]); 
      }  
      counts[arr[i]]++; 
    } else {    
      counts[arr[i]] = 1;    
    }    
  }    
  
  for(var i = 0; i < duplicates.length; i++) {
    if(counts[duplicates[i]] > maxTimes) {
      maxTimes = counts[duplicates[i]];
    }
  }
  if(maxTimes == 2 && duplicates.length == 2) {
    lastPoint = 10
  }else if(maxTimes == 3 && duplicates.length == 2) {
    lastPoint = 20
  }else if(maxTimes == 3 && duplicates.length == 1) {
    lastPoint = 10
  }else if(maxTimes == 4 && duplicates.length == 1) {
    lastPoint = 40
  }else if(maxTimes == 5 && duplicates.length == 1) {
    lastPoint = 100
  }else if(maxTimes == 0 && isConsecutive(arr) == false) {
    lastPoint = 30
  }else if(maxTimes == 0 && isConsecutive(arr) == true) {
    lastPoint = 60

  } 


  console.log(maxTimes)
  return lastPoint;    
}    


function isConsecutive(arr) {  
  // 对数组进行排序  
  arr.sort((a, b) => a - b);  

  // 检查数组中的每个元素是否比前一个元素大1  
  for(let i = 1; i < arr.length; i++) {  
      if(arr[i] !== arr[i-1] + 1) {  
          return false;  
      }  
  }  

  return true;  
} 

构造测试数据的思路:以上的测试用例用到了 Jest 这个 JavaScript 的测试框架。在每个 it 块中,我们首先对 brandPoint 函数的预期行为进行描述,然后在该块中执行测试以确认实际结果是否与预期相符。expect 是 Jest 提供的一个函数,它接受一个值作为参数,如果这个值等于预期值,测试就会通过。如果不等于预期值,测试就会失败。

3.7 贴出GitHub的代码签入记录,合理记录commit信息(2分)
在这里插入图片描述
在这里插入图片描述

四、总结反思(11分)

4.1 本次任务的PSP表格(2分)

PSP2.1Personal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划3030
· Estimate· 估计这个任务需要多少时间1515
Development开发24003000
· Analysis· 需求分析 (包括学习新技术)20002300
· Design Spec· 生成设计文档6060
· Design Review· 设计复审3030
· Coding Standard· 代码规范 (为目前的开发制定合适的规范)5070
· Design· 具体设计200300
· Coding· 具体编码30003200
· Code Review· 代码复审100100
· Test· 测试(自我测试,修改代码,提交修改)100120
Reporting报告200300
· Test Report· 测试报告4530
· Size Measurement· 计算工作量3045
· Postmortem & Process Improvement Plan· 事后总结, 并提出过程改进计划200100
· 合计84609700

4.2 学习进度条(每周追加)(2分)

  • 林宏宇
N周新增代码(行)累计代码(行)本周学习耗时(小时)累计学习耗时(小时)重要成长
19009001010了解墨刀使用方法 使用墨刀进行原型设计
2150024002535熟悉Web知识,复习CSS、HTML、JS使用方法,学习新知识,通过前端设计游戏界面。学习后端语言,掌握相关函数用法,编写了游戏模型框架
3300054001045设计相关界面,辅助后端开发,测试游戏,完善功能。学习了PS等用于制作素材的软件,学习了如何上传微信小程序
  • 韦星星
N周新增代码(行)累计代码(行)本周学习耗时(小时)累计学习耗时(小时)重要成长
18008001010了解墨刀使用方法 使用墨刀进行原型设计,熟悉前端语言,设计相关界面.
2100018002535熟悉Web知识,复习CSS、HTML、JS使用方法,学习新知识,通过前端设计游戏界面,熟练使用HTML、CSS、JS语言
3300048001247设计相关界面,辅助后端开发,测试游戏,完善功能。

4.3 最初想象中的产品形态、原型设计作品、软件开发成果三者的差距如何?(2分)

(也就是谈一谈本次任务中**“理想与现实的差距”**,是哪些因素造成了这些差距?)

  1. 想象与实际的需求:最初想象中的产品形态往往基于理想化的需求和预期,而分析用户需求的过程中,可能会发现一些实际的需求与之前的想象大相径庭,比如选择角色页面,后期也添加了使用
    来获取用户的头像,使用来让用户自定义昵称。
  2. 技术限制:原型设计作品通常不会考虑到实际的技术限制,例如软件开发的工具、硬件的能力、数据的处理能力等。在软件开发阶段,这些问题就会显现出来,使得一些原本设想的功能无法实现,比如原本想实现骰子模拟现实的投掷效果,最后只是利用random()函数实现生成1~6的随机数,然后显示这些数字对应的点数的骰子的图片。
  3. 设计和用户体验:理想的产品形态和原型设计可能没有充分考虑到真实用户的需求、习惯和反馈,导致在实际使用过程中,用户体验达不到预期,比如投掷和确认做得还不够人性化,后期会考虑将页面交互设计得更加人性化,以此来提高用户的游戏体验和感官体验。
  4. 时间和资源:软件开发成果往往受时间和资源的影响。在开发过程中,可能会因为时间紧迫或资源不足,使得一些原本计划的功能无法完成,或者质量无法达到预期。

4.4 评价你的队友(2分)

(分别评价队友值得学习的地方需要改进的地方
(本部分需要包含队伍内所有成员的心得体会,若缺少一人,则队伍总分减少2分,减满4分为止)

  • 102101431 林宏宇

    • 我认为我的队友非常nice,当我们都在入门微信小程序开发的时候,他学写了几天,就在微信开发者工具里面把几乎全部页面的框架都搭建出来,也正是他搭建的这个页面、奠定了我们之后开发的基础,同时也减轻了我很大的负担。我认为他值得学习的敌方是为人踏实肯干,和他结对编程是一件愉快的事情,每次交流讨论都能有很好的效果,相互分配的任务也能得到很好的完成。我认为他需要改进的地方是能够加深对后端知识的学习,争取早日成为编程大师。
  • 102101414 韦星星

    • 我认为我的队友非常有创意、高效,在UI的原型设计过程中,我也对其进行了设计但是怎么也打不到心中想要的效果,有点苦恼。但是他一晚上就把UI的原型设计给弄出来了,而且达到了我们对这款小游戏效果的心理预期,比如说,一些菜单按键之类的在我这里可能就只是一个按键,但是他却能非常有创意地进行装饰……这也不得不让我感叹他的兵贵神速。同时在后端的实现过程中,他也体现出了非常强的个人编程能力。当时在我们讨论完前端通过点击公共投掷区的骰子进行选定,把选定数据传送到选定区这样一个功能以后,我也一时没有很好的编程逻辑,但是一两天以后他就把功能实现得八九不离十。此外还有在服务器的搭建问题上也是他一手解决的。不得不说他是一个非常优秀的中国好队友。

4.5 结对编程作业心得体会(3分)

(可包含但不限于评价作业难度、完成后的感受、遇到的代码模块异常或结对困难及解决方法、对之后学习或软件开发的启发)
(本部分需要包含队伍内所有成员的心得体会,若缺少一人,则队伍总分减少3分,减满6分为止)
102101431林宏宇

  • 作业难度我认为还是有的,在课业繁重的情况下进行快速编程也是锻炼我们的抗压能力,同时也解除了微信开发者工具这个软件,因为是第一次使用,所以刚开始使用的时候也找了很多的视频资料和文档资料,我觉得微信开发的文档还算是比较全面,从入门到更复杂的开发都有很详细的说明。
  • 完成后的感受就是终于可以好好休息一下了,也为这个微信小程序的开发花了很多的事件,希望能得到一个比较高的成绩,同时也感谢老师和出题者的良苦用心,通过这次软工实践,也学到了很多的编程相关的知识,如javascript、css、html以及微信官方的wxss和wxml,同时在编写游戏逻辑的同时,也复习了算法相关的知识,不得不说,算法还是很重要的,作为开发者要注重算法的实现。
  • 遇到的代码模块异常,input输入框输入的内容默认是字符串类型的,如果要输入数字,要将inputValue转换为数字,因为这个小问题也卡了挺久的。以后软件开发要好好利用官方文档,读好了很多时候会起到事半功倍的效果。

10101414韦星星

  • 不得不说通过这次的结对编程对我的帮助还是挺大的。在此之前,我也完全没有接触过UI设计,前端功能是如何实现的以及如何去实现玩家用户的数据通信等等,这些问题也只是在别人或者网上听说过,当时觉得自己就是个小白,什么也不懂。而通过这次的结对编程,我学会了一些新知识,比如说微信小程序客户端与服务器的数据通信不支持http协议但可以采用websocket进行实现,一些js的基本语法,小程序开发的基本流程。
  • 此外,在小游戏开发的过程中我也遇到了一些困难,比如:对前端的知识一无所知,然后通过百度、B站等途径学习相关的东西进行解决。这也锻炼了我在遇到问题时,通过查询来解决问题的能力。
  • 最后,我认为最最重要的是在此次作业中,让我意识到了团队的重要性。有一些问题一个人去解决是比较困难的,但是两个人相互帮助,利用双方的优势弥补各自的不足,也许问题就迎刃而解了。而事实证明:拥有一个好队友真的是一件很幸福的事情。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值