跳一跳 python脚本 改进版
2018-02-26 11:12
274 查看
原版本github地址:https://github.com/wangshub/wechat_jump_game
当时版本我用时感觉性能不佳,为能霸榜装逼,针对自己的手机进行了改进。
主要是对检测棋子,棋格部分进行了改进,仍有许多bug和未解决的问题之处,若有兴趣也可以再次进行改进,提升性能。
源码地址:http://download.csdn.net/download/wz2671/10259178
具体的环境配置等,可以参考原作者的github。
jump.py
游戏效果图如下:
![](https://img-blog.csdn.net/20180226110723442)
然而,,,
![](https://img-blog.csdn.net/20180226110959953)
不过低调些应该还是不会被检测出的。
当时版本我用时感觉性能不佳,为能霸榜装逼,针对自己的手机进行了改进。
主要是对检测棋子,棋格部分进行了改进,仍有许多bug和未解决的问题之处,若有兴趣也可以再次进行改进,提升性能。
源码地址:http://download.csdn.net/download/wz2671/10259178
具体的环境配置等,可以参考原作者的github。
jump.py
# -*- coding: utf-8 -*- """ === 思路 === 核心:每次落稳之后截图,根据截图算出棋子的坐标和下一个块顶面的中点坐标, 根据两个点的距离乘以一个时间系数获得长按的时间 识别棋子:靠棋子的颜色来识别位置,通过截图发现最下面一行大概是一条 直线,就从上往下一行一行遍历,比较颜色(颜色用了一个区间来比较) 找到最上面的那一行的所有点,然后求个中点,求好之后再让 Y 轴坐标 减小一定高度从而得到中心点的坐标 识别棋盘:靠底色和方块的色差来做,从分数之下的位置开始,一行一行扫描, 由于圆形的块最顶上是一条线,方形的上面大概是一个点,所以就 用类似识别棋子的做法多识别了几个点求中点,这时候得到了块中点的 X 轴坐标,利用链码思想求得右边界的X轴坐标,乘以一定系数得到中心点坐标 最后:根据两点的坐标算距离乘以系数来获取长按时间 """ from __future__ import print_function, division import os import sys import time import math import random from PIL import Image from six.moves import input try: from common import debug, config, screenshot except Exception as ex: print(ex) print('请将脚本放在项目根目录中运行') print('请检查项目根目录中的 common 文件夹是否存在') exit(-1) VERSION = "1.1.2" # DEBUG 开关,需要调试的时候请改为 True,不需要调试的时候为 False DEBUG_SWITCH = False #1.392 # Magic Number,不设置可能无法正常执行,请根据具体截图从上到下按需 # 设置,设置保存在 config 文件夹中 config = config.open_accordant_config() under_game_score_y = config['under_game_score_y'] # 长按的时间系数,请自己根据实际情况调节 press_coefficient = config['press_coefficient'] # 二分之一的棋子底座高度,可能要调节 piece_base_height_1_2 = config['piece_base_height_1_2'] # 棋子的宽度,比截图中量到的稍微大一点比较安全,可能要调节 piece_body_width = config['piece_body_width'] def set_button_position(im): """ 将 swipe 设置为 `再来一局` 按钮的位置 """ global swipe_x1, swipe_y1, swipe_x2, swipe_y2 w, h = im.size left = int(w / 2) top = int(1584 * (h / 1920.0)) left = int(random.uniform(left-50, left+50)) top = int(random.uniform(top-10, top+10)) # 随机防 ban swipe_x1, swipe_y1, swipe_x2, swipe_y2 = left, top, left, top def jump(distance): """ 跳跃一定的距离 """ press_time = distance * press_coefficient # press_time = max(press_time, 200) # 设置 200ms 是最小的按压时间 # 离近了补一点,离远了减一点 press_time = int(press_time) if press_time < 500: press_time += 100 - 2*(press_time//10) elif press_time > 1000: press_time -= press_time//50 cmd = 'adb shell input swipe {x1} {y1} {x2} {y2} {duration}'.format( x1=swipe_x1, y1=swipe_y1, x2=swipe_x2, y2=swipe_y2, duration=press_time ) print(cmd) os.system(cmd) return press_time def find_piece_and_board(im): """ 寻找关键坐标 """ w, h = im.size scan_x_border = int(w / 8) # 扫描棋子时的左右边界 scan_end_y = 0 # 扫描的起始 y 坐标 im_pixel = im.load() # 以 50px 步长,尝试探测 scan_start_y for i in range(int(h / 3), int(h*2 / 3), 50): last_pixel = im_pixel[0, i] for j in range(1, w): pixel = im_pixel[j, i] # 不是纯色的线,则记录 scan_start_y 的值,准备跳出循环 if sum(list(map(lambda x: abs(x[0]-x[1]), zip(pixel, last_pixel)))) > 3: scan_end_y = i break if scan_end_y: break # 记录下y,对该行扫描,确定终点的横坐标 # 由于圆左右不对称,回退寻找最顶端的那条线 pure = False for i in range(scan_end_y, scan_end_y-55, -1): if pure: scan_end_y = i+2 # 要加2,上一条已经是纯白线,但又减了一次 break last_pixel = im_pixel[0, i] for j in range(1, w): pixel = im_pixel[j, i] if sum(list(map(lambda x: abs(x[0]-x[1]), zip(pixel, last_pixel)))) > 3: break if j == w-1: pure = True # 从 scan_end_y 开始往下扫描,棋子应位于屏幕下半部分,这里暂定不超过 2/3 scan_start_y = 0 for i in range(scan_end_y, int(h * 2 / 3)): # 横坐标方面也减少了一部分扫描开销 for j in range(scan_x_border, w - scan_x_border): pixel = im_pixel[j, i] # 根据棋子的颜色判断 if (51 < pixel[0] < 54) \ and (51 < pixel[1] < 63) \ and (58 < pixel[2] < 64): scan_start_y = i break if scan_start_y != 0: break # 计算棋子的横坐标 start_x = 0 piece_x_c = piece_x_sum = 0 for i in range(scan_x_border, w - scan_x_border): pixel = im_pixel[i, scan_start_y] if (51 < pixel[0] < 54) \ and (51 < pixel[1] < 63) \ and (58 < pixel[2] < 64): piece_x_sum += i piece_x_c += 1 start_x = piece_x_sum//piece_x_c # 计算棋格的最顶端坐标,考虑棋子比棋格高的情况 # 因为棋子和棋格在中线两侧,所以从另外的一边找棋格顶端 st = ed = 0 dir = 0 # 鉴别方向,-1朝左跳, 1朝右跳 if start_x < w/2: st = w//2+1 ed = w dir = 1 else: st = 1 ed = w//2 dir = -1 pure = True if scan_end_y == scan_start_y: # 当棋子比棋格低,继续往下找 for i in range(scan_end_y, int(h * 2 / 3)): last_pixel = im_pixel[0, i] for j in range(st, ed): pixel = im_pixel[j, i] # 不是纯色的线,则记录 scan_end_y 的值,准备跳出循环 if sum(list(map(lambda x: abs(x[0]-x[1]), zip(pixel, last_pixel)))) > 3: pure = False scan_end_y = i break if pure != True: break end_x_c = end_x_sum = 0 pixel = im_pixel[st-1, scan_end_y] for i in range(st, ed): last_pixel = im_pixel[i, scan_end_y] if sum(list(map(lambda x: abs(x[0]-x[1]), zip(pixel, last_pixel)))) > 3: end_x_sum += i end_x_c += 1 end_x = end_x_sum//end_x_c if not all((piece_x_sum, piece_x_c)): return 0, 0, 0, 0 # scan_end_y 棋盘最上方的高度, scan_start_y 棋子最上方的高度 # 棋子最终坐标 start_x(已求得), start_y # 棋盘最终坐标 end_x(已求得), end_y # 棋子纵坐标可以通过顶端坐标减去到中心的距离求得 start_y = scan_start_y + 191 # 191是我量出来的,只针对本手机的分辨率情况下 # 求棋盘的纵坐标end_y # 根据棋子跳跃方向决定检测边界的方向,借鉴链码的思想 # 连续向下超过5即为边界 down_time = 0 bac_pixel = im_pixel[end_x, scan_end_y-1] # 以向右跳为例,分别代表右,右下,下, 左下, 左; 这儿原先想根据跳跃方向向对应方向检测,但是左边会受阴影影响 # 向右检测暂时未出现被遮挡不能检测的情况,只出现过棋子跳出边界的情况,这种情况应该很少见,不管了 step = [[1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0], [-1, -1]] dx = end_x; dy = scan_end_y back = False # 考虑到带耳朵的方块出现的一些特殊情况,加了向左下,左方向的判断 while(down_time < 5): for i in range(6): if (back and i == 0) or (back and i == 1): continue next_pixel = im_pixel[dx+step[i][0], dy+step[i][1]] if sum(list(map(lambda x: abs(x[0]-x[1]), zip(next_pixel, bac_pixel)))) > 20: dx += step[i][0] dy += step[i][1] if i == 2: down_time += 1 elif down_time != 0: down_time = 0 if i == 4 or i == 5: back = True elif back: back = False break # 这个0.57是指中心点到上边界和右边界的距离比,圆和正方形的比值不同,圆的更小些,正方形更大些, # 暂未想出合适的区分方法,可以通过上面求出的链码求面积或周长进行判断,不过略麻烦 end_y = scan_end_y + abs(int(0.57*(dx-end_x))) # 0.57以实际机型为准 return end_x, end_y, start_x, start_y def yes_or_no(prompt, true_value='y', false_value='n', default=True): """ 检查是否已经为启动程序做好了准备 """ default_value = true_value if default else false_value prompt = '{} {}/{} [{}]: '.format(prompt, true_value,\ false_value, default_value) i = input(prompt) if not i: return default while True: if i == true_value: return True elif i == false_value: return False prompt = 'Please input {} or {}: '.format(true_value, false_value) i = input(prompt) def main(): """ 主函数 """ # debug.dump_device_info() screenshot.check_scr adab eenshot() while True: screenshot.pull_screenshot() im = Image.open('./autojump.png') # 获取棋子和 board 的位置 end_x, end_y, start_x, start_y = find_piece_and_board(im) # print(start_x, start_y, end_x, end_y) set_button_position(im) jump(math.sqrt((end_x-start_x)**2+(end_y-start_y)**2)) # if DEBUG_SWITCH: # debug.save_debug_screenshot(ts, im, piece_x, # piece_y, board_x, board_y) # debug.backup_screenshot(ts) im.close() # 为了保证截图的时候应落稳了,多延迟一会儿,随机值防 ban time.sleep(random.uniform(1.0, 1.2)) if __name__ == '__main__': main()
游戏效果图如下:
然而,,,
不过低调些应该还是不会被检测出的。
相关文章推荐
- windows下python判断脚本唯一运行改进
- 写个python脚本,处理bitmap.fnt文件,将信息存放入.csv文件中
- Python脚本报错AttributeError: ‘module’ object has no attribute’xxx’解决方法
- Python脚本传參和Python中调用mysqldump
- 如何在Windows环境下运行Python脚本
- 【Python运维脚本】Python监控系统负载
- 【Python运维脚本】Python监控网卡流量
- python 备份mysql脚本
- 改进版本的压缩和解压的shell脚本
- Python脚本控制的WebDriver 常用操作 <十三> 处理button group层的定位
- Python版Mssql爆破小脚本
- 用python编写ios工程自动编译、打包ipa等脚本
- Python 自动化脚本支持 Firefox 浏览器 官方Webdriver -- Geckodriver
- 简明 Python 教程中的第一个备份脚本
- python写的自动签到脚本。
- Python 3.5 HTTP服务器端重定向测试脚本
- Python 发送带 附件 邮件 脚本
- 微信跳一跳游戏python脚本
- python更新tomcat脚本
- python脚本 用sqoop把mysql数据导入hive