a38758720 发表于 2021-3-19 15:15

今天不抓猫,看源码改源码,我保证不作弊了!!!真不作弊!!

本帖最后由 a38758720 于 2021-3-20 23:48 编辑

主要是昨天的帖子https://www.52pojie.cn/thread-1395407-1-1.html有朋友有点兴趣我就再详细的过一遍整个流程,而且还有朋友想逗猫 @蓦留 @yagiza(重新试试怎么艾特)
就改一下源码,让猫彻底没路可走的时候胜利
老样子,随便输入一个url让52走404页面 https://www.52pojie.cn/hxxx

说了,今天不作弊,就不作弊,今天逗逗猫。
主要看注释啊朋友们

https://static.52pojie.cn/static/image/hrline/1.gif

进入今天的正题。

今天不走控制台了,为了方便直接override js文件,也方便加注释啥的,参考https://www.52pojie.cn/thread-1394509-1-1.html这个老哥的做法,我不再写一遍了。

搜索“你赢了”发现有两个地方出现了这个字眼,一个是switch case,只是为了统一页面显示的字样而已,这个不重要,重要的以下这个

var n = this.getBlock(t, e);
            return n ? n.isWall ? (this.setStatusText(f.default("点击位置已经是墙了,禁止点击")),
            !1) : this.cat.i === t && this.cat.j === e ? (this.setStatusText(f.default("点击位置是猫当前位置,禁止点击")),
            !1) : (n.isWall = !0,
            this.cat.isCaught() ? (this.setStatusText(f.default("猫已经无路可走,你赢了")),
            this.state = i.WIN,
            !1) : (this.setStatusText(f.default("您点击了 ") + "(" + t + ", " + e + ")"),
            this.cat.step() || (this.setStatusText(f.default("猫认输,你赢了!")),
            this.state = i.WIN),
            !0)) : (this.setStatusText(f.default("代码错误,当前位置不存在")),
            !1)
昨天是通过直接重写isCaught方法实现作弊直接胜利。我们今天分析一下这个方法干了啥。
isCaught = function() {
            var t = this;
            //获取当前点所有的邻居,并判断所有邻居是否都是墙,如果都是墙返回true,有一个不是墙则返回false
            //昨天相当于直接绕开了这层判断,不管邻居是不是墙,都是true
            return !this.getCurrentNeighbours().some(function(e, n) {
                var o = t.scene.getBlock(e.i, e.j); //
                return null !== o && !o.isWall
            })
      }


getBlock = function(t, e) {
            //这就没啥好说的,就是返回当前点的对象而已,如果坐标不合理直接返回null
            //正常情况下不可能返回null的,除非强行改代码了
            return t >= 0 && t < this.w && e >= 0 && e < this.h ? this.blocks : null
      }

发现这边的逻辑,其实就是老抓猫的逻辑,也就是得等猫周边全是墙,才胜利。这种逻辑可以逗猫。
但是实际上,我们只要把猫圈起来,就获得胜利了(我们今天就是要干掉这个逻辑,为了逗猫)
所以我们要看,这里的另一个方法cat.step
step = function() {
            //调了某个方法,这个方法在猫没地方走的情况下返回-1,其他情况下返回方向,这里是今天最关键的地方
            var t = this.solver.call(this, this.scene.blocksData, this.i, this.j);
            //这里的t指的是方向,上面这个方法返回的就是猫接下来要往哪个方向走,猫能走的方向有6个
            //0-5分边代表了6个方向,至于分别代表什么方向,有兴趣可以自己跟一下代码
            //return了一个三元表达式,和逗号表达式,学JavaScript可以去了解一下,
            //逗号表达式是指执行完逗号左边的,再执行右边,然后返回右边的值
            //也就是说这个方法,正常情况下的永远是!1,只有猫无路可走时,返回三元运算法冒号后面的表达式   !!this.stepDirection(t) || (this.caught(),!1)
            //这里涉及到js的强转技巧,!!指的是两层否,表示不改变逻辑,但是把返回值转成了bool类型了
            // ||是或运算法, A || B ,A为true返回A ,A不满足的情况,执行B,返回B
            return t < 0 || t > 6 ? (this.caught(),
            !1) : !!this.stepDirection(t) || (this.caught(),
            !1)
      }
我们先分析stepDirection和caught方法吧.
e.prototype.stepDirection = function(t) {
            //设置方向
            return this.direction = t,
            //行动
            this.stepForward()
      }
      ,
      e.prototype.stepForward = function() {
            var t = this
            , e = this.getCurrentNeighbours()//其实就是猫下一步要走的位置了
            , n = this.scene.getBlock(e.i, e.j);
            //行动
            return null !== n && (!n.isWall && (this.play(s.default.directions.name + "_step"),
            this.once("animationcomplete", function() {
                t.moveForward(),
                t.resetTextureToStop()
            }),
            !0))
      }
e.prototype.caught = function() {
            //就是set了一串位移的字符串进去而已,上面某个地方会做解析
            this.setTexture(s.default.cannotEscapeTextures.name])
      }

接下来就是今天重点的方法了,我们用断点来看吧,比较直接

首先三个入参,分别是地图数据和猫的坐标,然后new一个i对象,其实就是地图对象
执行地图对象的calcAllDistances方法


跟进来发现,这里遍历blocks,就是所有的地图数据,isWall是是否被点击过。isEdge是否边缘,猫到了边缘我们就输了
t.prototype.calcAllDistances = function() {
            var t = [];
            this.blocks.forEach(function(e) {
                e.forEach(function(e) {
                  //这里是多重判断,&&操作是前一个表达式必须是true才执行下一个表达式
                  //如果e是边缘,不执行后面操作,如果e不是边缘,判断是否是墙,不是墙的情况下,执行最后一句话   (e.distance = 0,t.push(e)) 进行赋值和塞e到t
                  //也就是说t里面的元素,是所有的边缘不是墙的点
                  e.isEdge && !e.isWall && (e.distance = 0,t.push(e))
                })
            });

            //这里是一个for循环,结束条件是t里面的所有数据都清空
            for (var e = function() {
                //从t数组取一个点出来,从上面我们知道,t里面的元素都是边缘数据,且不是墙
                var e = t.shift();
                e.neighbours.forEach(function(n) {
                  //又是多重判断的写法,||操作是前一个表达式必须是false才执行下一个表达式
                  //首先null不为空,n不是边缘,n不是墙,n.distance > e.distance + 1为true的情况下,才执行括号里的内容
                  //括号内,把邻居的距离+1,当这个邻居不存在于t时,把这个邻居加到t里,后面遍历会遍历到这个邻居
                  //这样把所有邻居都遍历一遍,直到所有的邻居都不在t里面为止,最终结果是计算出所有点到边缘最近的距离
                  //猫当然是要往最近的方向走
                  null === n || n.isEdge || n.isWall || n.distance > e.distance + 1 && (n.distance = e.distance + 1,t.indexOf(n) < 0 && t.push(n))
                })
            }; t.length > 0; )
                e()
      }
执行完这一段。节点的dirctions,dirction等值突然发生了变化,但是上述代码没有对这几个属性做操作,所以必定有监听器,下个代码块是监听器代码
return Object.defineProperty(t.prototype, "routesCount", {
            get: function() {
                var t = this;
                if (void 0 === this._routesCount)
                  if (this.isEdge)
                        this._routesCount = 1;
                  else {
                        var e = 0;
                        this.neighbours.forEach(function(n) {
                            //n不为空,n不为墙,n的距离比当前的距离小,_routesCount+1能走的路径数量+1
                            null === n || n.isWall || n.distance < t.distance && (e += n.routesCount)
                        }),
                        this._routesCount = e
                  }
                return this._routesCount
            },
            enumerable: !0,
            configurable: !0
      }),
      Object.defineProperty(t.prototype, "neighbours", {
            get: function() {
                var t = this;
                if (void 0 === this._neighbours) {
                  var e = o.default.getNeighbours(this.i, this.j);
                  this._neighbours = e.map(function(e) {
                        return t.parent.getBlock(e.i, e.j)
                  })
                }
                return this._neighbours
            },
            enumerable: !0,
            configurable: !0
      }),
      Object.defineProperty(t.prototype, "directions", {
            //监控所有的方向
            get: function() {
                var t = this
                  , e = [];
                return this.neighbours.forEach(function(n, o) {
                  //n不为空,且n不是墙,且n.distance < t.distance,取出
                  null === n || n.isWall || n.distance < t.distance && e.push(o)
                }),
                //所有比 当前位置到边缘距离小的节点 的方向(比当前位置还远,我干嘛要往那个方向跑)
                e
            },
            enumerable: !0,
            configurable: !0
      }),
      Object.defineProperty(t.prototype, "direction", {
            get: function() {
                var t = this
                  , e = 0
                  , n = -1;
                //遍历所有能走的方向,找到下一步可能性最大的方向
                return this.directions.forEach(function(o) {
                  var r = t.neighbours;
                  r.routesCount > e && (e = r.routesCount, n = o)
                }),
                n
            },
            enumerable: !0,
            configurable: !0
      }),
      t
    }()
监听器其实就是做了路径数的计算,以及规划猫猫接下来要走的路,这一段应该是猫猫逃脱所用到的算法,具体看看注释吧

https://static.52pojie.cn/static/image/hrline/1.gif


好了回归正题
看了上面的代码,我们发现,如果想让猫猫,完全没路走才获胜的话,我们就需要猫猫只通过cat.isCaught()方法来判断胜负
也就是说要让cat.step的返回值永远为true,否则就判断胜利了,
所以,将step最后返回值做一下修改
e.prototype.step = function() {
            var t = this.solver.call(this, this.scene.blocksData, this.i, this.j);
             t < 0 || t > 6 ? (this.caught(),!1) : !!this.stepDirection(t) || (this.caught(),!1)
             return 1;
      }

这个时候发现猫被围住之后完全不动了,因为猫的方向永远是-1,所以他不走,所以,我们得在监听器里,修改方向的逻辑
Object.defineProperty(t.prototype, "direction", {
            get: function() {
                var t = this
                  , e = 0
                  , n = -1;
               
                this.directions.forEach(function(o) {
                  var r = t.neighbours;
                  r.routesCount > e && (e = r.routesCount, n = o)
                })
                //遍历所有能走的方向,找到下一步可能性最大的方向
                //加一条,当n==-1的时候随机往一个能走的方向走
                if(n==-1){
                  this.neighbours.forEach(function(nn, o) {
                      if(!nn.isWall){
                        n = o;
                      }
                  });
                }
                return n;
            },
            enumerable: !0,
            configurable: !0
      }),
      t
搞定啦。我们试试结果



修改后的js   txt和js都发不上来。无奈了



https://static.52pojie.cn/static/image/hrline/2.gif
今天研究了一个晚上,本来想找出一个算法来自动玩的
但是这游戏本身不是稳赢的游戏
现在没啥思路
在控制台输入this.window.game.mainScene.playerClick(1,2)可以实现点击1,2这个格子
this.window.game.mainScene.blocksData这个属性是地图数据
有思路朋友的可以去试一波,发帖记得艾特我呀
坐等算法大佬来玩


a38758720 发表于 2021-3-19 16:16

searchjack 发表于 2021-3-19 16:11
大佬能来个AI 抓猫不

这有点难了,我研究一段时间{:1_925:}

a38758720 发表于 2021-3-20 23:44

searchjack 发表于 2021-3-19 16:11
大佬能来个AI 抓猫不

{:1_923:}
今天研究了一个晚上,本来想找出一个算法来自动玩的
但是这游戏本身不是稳赢的游戏
现在没啥思路
在控制台输入this.window.game.mainScene.playerClick(1,2)可以实现点击1,2这个格子
this.window.game.mainScene.blocksData这个属性是地图数据
有思路的可以去试一波

fub8 发表于 2021-3-19 15:18

高手高手高高手

hzlei 发表于 2021-3-19 15:24

我觉得你这不算作弊{:301_998:}

a38758720 发表于 2021-3-19 15:25

hzlei 发表于 2021-3-19 15:24
我觉得你这不算作弊

{:1_907:}昨天已经作弊过了。

伈随风飞 发表于 2021-3-19 15:26

,手工玩猫,拒绝作弊

mj2013ly 发表于 2021-3-19 15:28

论坛的猫已经被玩得没脾气了

tritan 发表于 2021-3-19 15:29

伙计 这这昨天的帖子还没抓猫呢,这又开始了{:301_1005:}

a38758720 发表于 2021-3-19 15:30

tritan 发表于 2021-3-19 15:29
伙计 这这昨天的帖子还没抓猫呢,这又开始了
今天分析了并修改了一下源码。不作弊了。

asld331 发表于 2021-3-19 15:34

天天撸一次还是可以的。。。!

mmcc1984 发表于 2021-3-19 15:36

猫:我信你个鬼 你个糟老头子坏得很
页: [1] 2 3 4 5 6 7 8 9
查看完整版本: 今天不抓猫,看源码改源码,我保证不作弊了!!!真不作弊!!