人人都能看懂的“跳一跳”平民算法

人人都能看懂的“跳一跳”平民算法

跨年夜的时候,在家里没事干,为了陪孩子玩,写了个 python 脚本,自动玩微信“跳一跳”。后来又完善了一下,目前未发现会跳不中的情况,且大约90%的几率跳到中心。

我今天在知乎上一搜,发现还挺多朋友写这类程序的。相比之下,我觉得我用的算法原理非常简单,我称之为平民算法,不需要什么计算机图形学知识,所以在这里写一下供大家娱乐!

代码发布在这儿:

liuben/weixinhopgithub.com图标

1 基本想法

电脑通过 adb 可以连上Android手机,然后截屏并拖回电脑以供电脑分析。然后电脑也可以通过 adb 控制触摸 Android 手机的时间。从而为写程序自动玩游戏提供了可能。

要自动玩游戏,无外乎3点:

  1. 算出目标点的坐标
  2. 算出起点的坐标
  3. 计算出跳跃距离,进而计算出触摸时间

2 目标点分析

首先背景色是比较固定的(从上到下有微小变化),和物体有较大色差,所以定义一个两点颜色差距的函数。这个在计算机图形学上有专门的公式,但我觉得没必要,直接写了个最简单的,就是将两个像素的 RGB 分别相减的绝对值再加起来,就够用了。如下所示:

r = start[0]-cur[0]
g = start[1]-cur[1]
b = start[2]-cur[2]
distance = abs(r) + abs(g) + abs(b)

目标点自然是目标物体顶面的中心。

注意到目标正方体顶面最上方的点和最右侧的点,分别对应目标点的x坐标和y坐标,所以如果能找出这两个点的坐标就好了。

先找顶点坐标:跳过记分牌之后,从上往下搜索第一个跟背景色差别较大的点即可。

关于顶点坐标有两个特殊情况:

第一,目标物体顶部为圆形。放大了看,会发现顶部有连续的若干个点。所以,实际算法中在从上往下,从右往左搜到第一个色差很大的点之后,会继续向左搜索连续的色差很大的点,最后取这一线段的中点,作为顶点。

第二,会有顶点低于棋子的情况,导致从上而下搜索时,先遇到了棋子的头部。为了规避这种情况的干扰,我从棋子头部取了一个特征点,然后在顶点检索时,在检测到一个和背景色色差较大的点之后,和棋子的特征点计算色差,如果色差很小,则认为进入了棋子头部,然后跳过这个点及其周围一定范围的像素。

搞定顶点,再来搞右侧点。

顺着顶点向右下方检索和背景色色差较大的点。什么时候时候找到一个点,它下方那一行没有比它更靠右的大色差点,就说明这个点是最右侧点了。

右侧点有一个特殊情况,也是圆形。在放大了看时,会发现圆形在边缘会出现垂直的至多5个像素,然后继续往外侧走。

为了涵盖这种情况,又避免和正方体这种右侧点下面有很长的垂直线的情况相区分。实际算法在从顶点搜索右侧点时,每次循环都将y坐标加1,然后x坐标同上一行,开始向右搜索大色差点。如果这一行的最右侧点,比上一行的最右侧点,更靠右,则这一行成为候选;如果这一行的最右侧点和上一行x坐标完全一样,则上一行仍然是候选,开始计数并进入下一行,如果这种情况连续超过5行(即计数超过5),则候选行即是最右侧点所在行。

有两种特殊情况,目前的算法会在计算最右侧点时出现误差:分别是杯子的情况,和最右侧点被棋子遮挡的情况。

这两种情况会跳不到中心,但也不至于掉下去。所以,我就没有再进一步处理了。


3 起点分析

注意到棋子的颜色在游戏中是唯一的,不过棋子在不同位置会有一点变化。所以,我先从棋子中根据其中心所在位置,截取了一幅特征图如下:

然后在画面中,搜索和这个区域色差最小的区域,即可算出起点的坐标。

两个区域的色差也很容易算,就是把源区域和特征区域的点挨个算色差(按上面定义的简单公式)再加起来就好了。

实际计算中为了减小计算量,会缩小检索区域,比如起点肯定在目标点的下方。再把屏幕分成左右两侧,那么起点肯定和目标点不在同一侧屏幕中。另外如果一点和特征图的色差很大,就没必要算整个区域的色差了。

目前看来,这种算法准确率很高。

4 触摸时间计算

首先要拿到一个标准距离下,能够跳到中心的完美时间。这需要做一下实验。

我的脚本开发了调试模式,可以从命令行控制进行截图、分析、跳跃之一。可用于实验获得这个参数。

注意到,每次游戏启动时,第一步的跳远距离是固定的。

所以,就在这一步反复实验跳跃时间就好了。

只要试出来一个就好,其他的距离程序都可以按照比例计算。

注意,一个距离要完美跳跃,触摸时间在一个区间内都是可以的,建议选择这个区间的中间值,以减少计算别的距离时的误差。


5 总结

至此,算法介绍完毕。不需要什么多的知识,基本上会写程序就能看懂吧,哈哈!整个算法的时间复杂度如果以图片的像素数量来衡量的话是 O(n),应该是相当可以了。

这个脚本用Python开发,使用了 Pillow 库。美中不足是计算时间较长,每一步需要计算6、7秒吧。我看 Pillow 库的文档里面写了按像素遍历图片的性能不佳,我程序也没有在提高性能上做太多工作,所以目前也就这样了。

以上纯属自娱自乐,做完后给小孩看了看,小孩表示很神奇,哈哈!

发布于 2018-01-05

文章被以下专栏收录