谷动谷力

 找回密码
 立即注册
查看: 2478|回复: 0
打印 上一主题 下一主题
收起左侧

会算法的神经猫你能抓住吗?

[复制链接]
跳转到指定楼层
楼主
发表于 2022-4-22 08:41:20 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
            会算法的神经猫你能抓住吗?

1
前言
<<抓住神经猫>>游戏相信不少朋友都玩过,最近不是ARKUI挺火热的么,一直搞嵌入式的也想尝尝鲜,想找个小玩意入门,想起来5、6年前看过的一篇文章,分析神经猫的寻路算法,号称是最难抓住的神经猫,回去一看,这项目不正好练手吗,说干就干。

2
效果
目前已完成整个游戏的UI(当然图是网上找的),游戏逻辑(启动、移动、胜负判定),可以学到的知识:ets方式的UI布局,ets组件化开发思想,自定义弹出框,ets语言构造多叉树,广度优先算法,最小路径算法,设置图片动画等等,整体开发下来UI地方还算顺畅,难到不难,只是这种声明式UI和以前的命令式UI的编程方式需要一个思路转变,最费时间的地方是那个猫跑路的算法,算法本来是薄弱项,这下正中软肋了,不过好在翻了好几本书,找了些资料,再看了点视频,就搞定了,废话少说,来个动图感受一下。

先来个失败的:


再来个成功的:


实际体验下来也是输多赢少,因为这是一只会算法的猫。

3
关键部分解读
玩法
游戏的地图是一个9*9交错排列的一些灰色小圆点,初始情况下游戏生成地图的时候会随机选一些点变成橙色做为墙,然后玩家每次点击一个灰色圆点,圆点变成橙色,同时猫移动一步,关于胜负的判定是猫被圈进一个圈子里面就为赢,当猫跑到地图边边上就为输,玩法还是挺简单的。

部分代码
代码结构长这样,因为时间关系,代码的结构还没有优化,有些地方看起来很是很混乱,包括文件名,变量名那些,后面有时间再调整吧,目前就将就看一下吧。


再贴个"猫"类吧:

@Observedexport class catData{  pos_x:number  pos_y:number
  location:number  step:number = 0
  inWall:boolean=false
  constructor(loc:number = defaultLocation){    this.setLocation(loc)  }
  reset(){    this.inWall = false    this.step = 0    this.setLocation(defaultLocation)  }
  setLocation(loc:number){    console.log(&amp;quot;set Loction:&amp;quot;+loc)    this.location=loc    this.setPosition()  }
  setPosition(){    let col:number = Math.floor(this.location/9)    let row:number = this.location%9
    this.pos_x = (col%2 ? row*38+17:row*38)    this.pos_y = col*38
//    console.log(&amp;quot;x:&amp;quot;+this.pos_x+&amp;quot; y:&amp;quot;+this.pos_y)  }
  moveTo(location:number) {
    this.setLocation(location)    this.step++
  }
  catInWall(yes:boolean=true){    this.inWall = yes  }}
(左右移动查看全部内容)

猫类的主要功能就是记录移动步数,然后移动位置,当游戏重新开始的时候某些属性复位。

主要逻辑
游戏的主要逻辑就是靠玩家点击圆点发生,当点击圆点的时候,先将该点置为墙,然后先要找出猫能逃跑的路线,再让猫选择一条路线进行逃生,主要逻辑的代码如下:

export function onItemClick(index : number){  console.log(&amp;quot;onItemClick &amp;quot;+index)  if(myCircLEDataArray[index].clicked ){    console.log(&amp;quot;不能点击&amp;quot;)    return;
  }  myCircleDataArray[index].setClick()
  let catLocation = myCat.location
  myCircleDataArray.forEach(item=&amp;gt;{    item.path = -100    item.depth = 100  })
  myCircleDataArray[catLocation].depth=0
  let neighbors = getNeighbors(catLocation,myCircleDataArray[catLocation].depth)
  neighbors.forEach(item=&amp;gt; {
    myCircleDataArray[item.location].depth=item.depth
  })  let neighborList:Array&amp;lt;Neighbor&amp;gt; =neighbors
  while(neighborList.length &amp;gt; 0){    let neighborsArrayList:Array&amp;lt;Neighbor&amp;gt; = []
    neighborList.forEach(item=&amp;gt;{      let neighborsTemp = buildNeighborChild(item)      neighborsTemp.forEach(item=&amp;gt;{        neighborsArrayList.push(item)      })    })
    neighborList = neighborsArrayList  }  neighbors.forEach(item=&amp;gt;{
    calcCirclePath(item)
  })
  let best = getBestNeighbor(neighbors)
  console.log(&amp;quot;the best neighbor is:&amp;quot;+best.location+&amp;quot; path=&amp;quot;+best.path);  if(best.path == 100){    console.log(&amp;quot;cat is in wall&amp;quot;);    myCat.catInWall()    myGame.setState(gameState.gameVictory)  }
  myCat.moveTo(best.location)
  if(catCheckLocation() == true){    console.log(&amp;quot;cat escaped&amp;quot;)    myGame.setState(gameState.gameFailed)  }
  neighbors.length = 0}
(左右移动查看全部内容)

关于寻路算法这里说一下,目前采用的是广度优先遍历,在找到几条最短路径,当有两条以上的最短路径的时候,就看一下哪条路径下的子路径比较多(防止走入玩家设定的陷阱)
function getBestNeighbor(neighbors:Neighbor[]):Neighbor{
  let neighbor:Neighbor = neighbors[0]
  //already get the shortest path  for(var i=1;i &amp;lt; neighbors.length;i++){    if(neighbor.path &amp;gt; neighbors.path){      neighbor = neighbors    }  }  console.log(&amp;quot;the shortest nei:&amp;quot;+neighbor.location)
  //select the child more than other  for(var j=0;j &amp;lt; neighbors.length;j++){    if(neighbor.path == neighbors[j].path){      console.log(&amp;quot;find same path:&amp;quot;+neighbors[j].location)     if(neighbor.child.length &amp;lt; neighbors[j].child.length){
       neighbor = neighbors[j]       console.log(&amp;quot;changed neighbor:&amp;quot;+neighbor.location)     }    }  }
  return neighbor}
(左右移动查看全部内容)

开发的时候设置一个调试小技巧效率高很多(然而一开始的时候我也是个铁憨憨,在草纸上记,弱爆了):


当把这个置true的时候可以清晰的看到点的位置和到达边界需要的步数,神经猫正是通过这个来跑路的,看一下打开的效果:


4
后续需要做的事情主要是以下几件:

  • 当前可以看到3个难度图标,目前还没做功能,后续会加上,难度的调节目前认为有几个地方:初始墙的数量,逃跑算法的强度,或者优化初始墙的位置(简单的话就相对集中,困难的话就相对分散),以我非数学专业的功力感觉第一种靠谱一些,如果有数学大神也可以探讨一下后面两种怎么做;
  • 可以看到猫逃跑的时候,从当前位置移动到下一位置,会出现短暂的消失,这有可能是模拟器在渲染动图的时候有什么延时导致的,后期准备研究一下动画效果,让猫的走动更顺滑;
  • 由于目前还没有OpenHarmony能玩起来的开发板,所以只能是模拟器演示,后续如果有真正的开发板的话,相信很快看就能移植上去。


5
关于代码

目前代码托管在Gitee上,感兴趣的小伙伴可以下载过来试一下,如果有什么建议或者改动也可以提提PR,提一下,这个游戏别看简单,拿来入门练手还是非常合适的,如果一开始就搞什么复杂的界面或者交互很可能会打击信心的哈。

+10
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|深圳市光明谷科技有限公司|光明谷商城|Sunshine Silicon Corpporation ( 粤ICP备14060730号|Sitemap

GMT+8, 2024-11-18 06:27 , Processed in 1.204561 second(s), 40 queries .

Powered by Discuz! X3.2 Licensed

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表