用 Python 玩微信跳一跳

杰哥的IT之旅

共 2082字,需浏览 5分钟

 · 2021-10-12

在下方公众号后台回复:面试手册,可获取杰哥汇总的 3 份面试 PDF 手册。

使用指南

测试PC安装ADB调试工具,用于和Android设备交互,主要完成截图,截图下载,进行按压屏幕模拟。

下载后放到合适的位置解压,不要安装。在Win10中,系统目录和之前有所不同,所以旧的安装方法是无效的。

Android设备通过USB连接到测试PC,Android 设备开启调试模式,需要保证ADB能正常和Android连接。

在命令行中进入解压后的目录,输入Adb devices如果看到CMD显示一串字符,后面还有一个“device”的字样,那就说明安卓机已经成功以USB调试的形式连接到了Win10中。

Android 进入微信跳一跳小程序并开始游戏。

在PC上运行脚本程序,脚本程序正常运行,输入y,开始自动游戏。

主要代码

def _get_screen_size():
    """
    获取手机屏幕分辨率
    :return:
    """

    size_str = os.popen('adb shell wm size').read()
    print(size_str)
    if not size_str:
        print('请安装 ADB 及驱动并配置环境变量')
        sys.exit()
    m = re.search(r'(\d+)x(\d+)', size_str)
    if m:
        return "{height}x{width}".format(height=m.group(2), width=m.group(1))


def init():
    """
    初始化
    :return:
    """

    # 获取屏幕分辨率
    screen_size = _get_screen_size()
    config_file_path = 'config/{0}/config.json'.format(screen_size)
    print(config_file_path)
    if os.path.exists(config_file_path):
        with open(config_file_path, 'r'as f:
            print("Load config file from {}".format(config_file_path))
            return json.load(f)
    else:
        with open('config/default.json''r'as f:
            print("Load default config")
            return json.load(f)


def get_screenshot():
    global SCREENSHOT_WAY
    if SCREENSHOT_WAY == 2 or SCREENSHOT_WAY == 1:
        process = subprocess.Popen('adb shell screencap -p', shell=True, stdout=subprocess.PIPE)
        screenshot = process.stdout.read()
        if SCREENSHOT_WAY == 2:
            binary_screenshot = screenshot.replace(b'\r\n'b'\n')
        else:
            binary_screenshot = screenshot.replace(b'\r\r\n'b'\n')
        with open('autojump.png''wb'as f:
            f.write(binary_screenshot)

    elif SCREENSHOT_WAY == 0:
        os.system('adb shell s  creencap -p /sdcard/autojump.png')
        os.system('adb pull /sdcard/autojump.png .')


def check_screenshot():
    global SCREENSHOT_WAY
    if os.path.isfile('autojump.png'):
        os.remove('autojump.png')

    if SCREENSHOT_WAY < 0:
        print('暂不支持当前设备')
        sys.exit()
    get_screenshot()
    try:
        Image.open('autojump.png').load()
    except Exception as e:
        print(e)
        SCREENSHOT_WAY -= 1
        check_screenshot()


def find_piece_and_board(img, con):
    w, h = img.size
    # 棋子的底边界
    piece_y_max = 0
    scan_x_side = int(w / 8)  # 扫描棋子的左右边界减少开销
    scan_start_y = 0  # 扫描起始y坐标
    # 图片像素矩阵
    img_pixel = img.load()
    if not LOOP:  # 是否循环游戏
        if sum(img_pixel[55][:-1]) < 150:  # 根据屏幕黑色
            exit('游戏结束!')
    # 以50px 步长,尝试探测 scan_start_y
    for i in range(int(h / 3), int(h * 2 / 3), 50):
        first_pixel = img_pixel[0, i]
        for j in range(1, w):
            # 如果不是纯色,说明碰到了新的棋盘,跳出
            pixel = img_pixel[j, i]
            if pixel[0] != first_pixel[0or pixel[1] != first_pixel[1or pixel[2] != first_pixel[2]:
                scan_start_y = i - 50
                break
        if scan_start_y:
            break

    # 从上往下开始扫描棋子,棋子位于屏幕上半部分
    left = 0
    right = 0
    for i in range(scan_start_y, int(h * 2 / 3)):
        flag = True

        for j in range(scan_x_side, w - scan_x_side):
            pixel = img_pixel[j, i]
            # 根据棋子的最低行的颜色判断,找最后一行那些点的平均值
            if (50 < pixel[0] < 60and (53 < pixel[1] < 63and (95 < pixel[2] < 110):
                if flag:
                    left = j
                    flag = False
                right = j
                piece_y_max = max(i, piece_y_max)
    if not all((left, right)):
        return 0000
    piece_x = (left + right) // 2
    piece_y = piece_y_max - con['piece_base_height_1_2']  # 上调高度,根据分辨率自行 调节

    # 限制棋盘扫描横坐标
    if piece_x < w / 2:  # 棋子在左边
        board_x_start = piece_x + con["piece_body_width"]//2
        board_x_end = w
    else:
        board_x_start = 0
        board_x_end = piece_x - con["piece_body_width"]//2

    # 从上往下扫描找到棋盘的顶点
    left = 0
    right = 0
    num = 0
    for i in range(int(h / 3), int(h * 2 / 3)):
        flag = True
        first_pixel = img_pixel[0, i]
        for j in range(board_x_start, board_x_end):
            pixel = img_pixel[j, i]
            # 20是色差阈值可以调节
            if abs(pixel[0] - first_pixel[0]) + abs(pixel[1] - first_pixel[1]) + abs(pixel[2] - first_pixel[2]) > 10:
                if flag:
                    left = j
                    right = j
                    flag = False
                else:
                    right = j
                num += 1
                # print(left, right)
        if not flag:
            break

    board_x = (left + right) // 2
    top_point = img_pixel[board_x, i+1]  # i+1去掉上面一条白线的bug
    # 从上顶点往下 + con['hight'] 的位置开始向上找颜色与上顶点一样的点,为下顶点
    # if num < 5:
    #     # 说明是方形
    #     if abs(top_point[0] - 255) + abs(top_point[1] - 228) + abs(top_point[2] - 226) < 5:
    #         print('唱片图案')
    #         top = 0
    #         bottom = 0
    #         for k in range(i, i + con["hight"]):
    #             pixel = img_pixel[board_x, k]
    #             # 根据唱片中的红色部分判断
    #             # if (155 < pixel[0] < 180) and (141 < pixel[1] < 165) and (113 < pixel[2] < 116):
    #             # print(pixel[0], pixel[1], pixel[2])
    #             if (abs(pixel[0] - 239) < 3) and (abs(pixel[1] - 118) < 3) and (abs(pixel[2] - 119) < 3):
    #
    #                 if not top:
    #                     top = k
    #                 else:
    #                     bottom = k
    #                 # print(top, bottom)
    #         board_y = (top + bottom) // 2
    #         return piece_x, piece_y, board_x, board_y

    # 该方法对所有纯色平面和部分非纯色平面有效
    # print(top_point)
    for k in range(i + con["hight"], i, -1):
        pixel = img_pixel[board_x, k]
        # print(pixel)
        if abs(pixel[0] - top_point[0]) + abs(pixel[1] - top_point[1]) + abs(pixel[2] - top_point[2]) < 10:
            break
    board_y = (i + k) // 2

    if num < 5:
        # 去除有些颜色比较多的误差

        if k - i < 30:
            print('酱红色433----》》》')
            board_y += (k - i)

    # 去掉药瓶

    if top_point[:-1] == (255255255):
        print('药瓶图案')
        board_y = (i + board_y) // 2

    # 去掉唱片
    if num == 3:
        if top_point[:-1] == (219221229):
            print('唱片')
            top = 0
            bottom = 0
            for k in range(i, i + con["hight"]):
                pixel = img_pixel[board_x, k]
                # 根据唱片中的红色部分判断
                # if (155 < pixel[0] < 180) and (141 < pixel[1] < 165) and (113 < pixel[2] < 116):
                # print(pixel[0], pixel[1], pixel[2])
                if pixel[:-1] == (118118118):

                    if not top:
                        top = k
                    else:
                        bottom = k
                        # print(top, bottom)
            board_y = (top + bottom) // 2
            return piece_x, piece_y, board_x, board_y

    if not all((board_x, board_y)):
        return 0000

    return piece_x, piece_y, board_x, board_y


def jump(distance, point, ratio):
    press_time = distance * ratio
    press_time = max(press_time, 200)  # 最小按压时间
    press_time = int(press_time)
    cmd = 'adb shell input swipe {x1} {y1} {x2} {y2} {duration}'.format(
        x1=point[0],
        y1=point[1],
        x2=point[0] + random.randint(03),
        y2=point[1] + random.randint(03),
        duration=press_time
    )
    print(cmd)
    os.system(cmd)
    return press_time


def run():
    oper = input('请确保手机打开了 ADB 并连接了电脑,然后打开跳一跳并【开始游戏】后再用本程序,确定开始?y/n>>:')
    if oper != 'y':
        exit('退出')
    # 初始化,获取配置
    config = init()
    # 检测截图方式
    check_screenshot()
    while True:
        # 获取截图
        get_screenshot()
        # 获取棋子,棋盘位置
        img = Image.open('autojump.png')
        piece_x, piece_y, board_x, board_y = find_piece_and_board(img, config)
        ntime = time.time()
        print(piece_x, piece_y, board_x, board_y, '------->')
        distance = math.sqrt((board_x - piece_x) ** 2 + (board_y - piece_y) ** 2)
        # 生成一个随机按压点,防止被ban

        press_point = (random.randint(*config['swipe']['x']),
                       random.randint(*config['swipe']['y']))
        jump(distance, press_point, config['press_ratio'])
        if DEBUG:
            debug.save_debug_screenshot(ntime, img, piece_x, piece_y, board_x, board_y)
            debug.backup_screenshot(ntime)
        time.sleep(random.randrange(12))


def test_scrennshot():

    img = Image.open('autojump.png')
    con = init()
    res = find_piece_and_board(img, con)
    print(res)

# def test_time_ratio():
#     config = init()
#
#
#     get_screenshot()
#     img = Image.open('autojump.png')
#     piece_x, piece_y, board_x, board_y = find_piece_and_board(img)
#     print(piece_x, piece_y)
#     point = (random.randint(*config['swipe']['x']),
#                    random.randint(*config['swipe']['y']))
#     t = 600
#
#     cmd = 'adb shell input swipe {x1} {y1} {x2} {y2} {duration}'.format(
#         x1=point[0],
#         y1=point[1],
#         x2=point[0] + random.randint(0, 3),
#         y2=point[1] + random.randint(0, 3),
#         duration=t
#     )
#     print(cmd)
#     os.system(cmd)
#     time.sleep(2)
#     get_screenshot()
#     img = Image.open('autojump.png')
#     piece_2x, piece_2y, board_2x, board_2y = find_piece_and_board(img)
#
#     print(piece_2x, piece_2y)
#     print(t/math.sqrt((piece_x-piece_2x)**2+(piece_y-piece_2y)**2))

if __name__ == '__main__':
    run()
    # test_time_ratio()
    # test_scrennshot()
    # get_screenshot()
    # check_screenshot()

文章转载:Python编程学习圈 (版权归原作者所有,侵删)

推荐阅读

我用 Python 自制成语接龙小游戏,刺激!


我用 Python 写了一个疫苗管理系统!


斗地主老是输?一起用Python做个自动出牌器,欢乐豆蹭蹭涨!


Python 暴力破解附近局域网 WiFi 密码


我用 Python 写了一款炫酷音乐播放器,想听啥随便搜!

浏览 22
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报