Hay una característica crucial; si juegas en modo arcade, los botones caen con velocidad creciente. Eso hace que el juego sea difícil para un jugador humano. ¡Pero no es un problema para nuestro bot!
En la aplicación de código de la plantilla, la coincidencia se ve así
import cv2 template = cv2.imread('template.png') target = cv2.imread('target.png') result = cv2.matchTemplate(target, template, cv2.TM_CCOEFF_NORMED) _, max_val, _, max_loc = cv2.minMaxLoc(result)
Como resultado, tendremos max_val
igual a la similitud máxima en la imagen de destino y max_loc
es la esquina superior izquierda de la coincidencia encontrada.
Hay dos paquetes de Python que ayudan con las tareas anteriores: mss
y pyautogui
, los usamos para obtener las capturas de pantalla de una parte particular de la pantalla y enviar clics a la ventana del navegador correspondientemente. También uso la biblioteca del keyboard
, ya que es muy útil para establecer la "acción de ruptura" en alguna tecla en el caso de que el mouse esté controlado por un bot. La biblioteca del keyboard
(y probablemente pyautogui
) requiere derechos de sudo
, así que ejecute su secuencia de comandos de Python como un ejecutable con un encabezado shebang adecuado.
#!/hdd/anaconda2/envs/games_ai/bin/python # ^ change above to your python path ^ import keyboard import mss import pyautogui pyautogui.PAUSE = 0.0 print("Press 's' to start") print("Press 'q' to quit") keyboard.wait('s') # setup mss and get the full size of your monitor sct = mss.mss() mon = sct.monitors[0] while True: # decide on the part of the screen roi = { "left": 0, "top": int(mon["height"] * 0.2), "width": int(mon["width"] / 2), "height": int(mon["height"] * 0.23) } roi_crop = numpy.array(sct.grab(roi))[:,:,:3] # do something with `roi_crop` if keyboard.is_pressed('q'): break
Aquí también hay una cosa. Cuando usa pyautogui
en Linux, es posible que se enfrente a Xlib.error.DisplayConnectionError
que es posible superar con el comando xhost +
.
Basado en los dos últimos, he creado un algoritmo que supera el puntaje de juego humano anterior de 170 con un puntaje de 445.
Hay dos partes en un programa. Primero intenta hacer clic en los primeros tres botones disponibles en una pantalla cuando comienza el juego. El campo de juego no se mueve hasta que un jugador presiona el primer botón, por lo que podemos tratar un campo como estático cuando hacemos clic en los tres primeros. Para ello, inspeccionamos las tres líneas de la pantalla, buscando un pequeño patrón (ver la figura anterior), y luego pulsamos sobre ellas
#!/hdd/anaconda2/envs/games_ai/bin/python # if "Xlib.error.DisplayConnectionError" use "xhost +" on linux import shutil import os import keyboard import mss import cv2 import numpy from time import time, sleep import pyautogui from random import randint import math pyautogui.PAUSE = 0.0 print("Press 's' to start") print("Press 'q' to quit") keyboard.wait('s') try: shutil.rmtree("./screenshots") except FileNotFoundError: pass os.mkdir("./screenshots") # setup mss and get the full size of your monitor sct = mss.mss() mon = sct.monitors[0] frame_id = 0 # decide where is the region of interest for idx in range(3,0,-1): roi = { "left": 0, "top": int(mon["height"] * (idx * 0.2)), "width": int(mon["width"] / 2), "height": int(mon["height"] * 0.23) } green_button = cv2.imread('green_button.png') offset_x = int(green_button.shape[0] / 2) offset_y = int(green_button.shape[1] / 2) roi_crop = numpy.array(sct.grab(roi))[:,:,:3] result = cv2.matchTemplate(roi_crop, green_button, cv2.TM_CCOEFF_NORMED) _, max_val, _, max_loc = cv2.minMaxLoc(result) print(max_val, max_loc) button_center = (max_loc[0] + offset_y, max_loc[1] + offset_x) roi_crop = cv2.circle(roi_crop.astype(float), button_center, 20, (255, 0, 0), 2) cv2.imwrite(f"./screenshots/{frame_id:03}.jpg", roi_crop) abs_x_roi = roi["left"] + button_center[0] abs_y_roi = roi["top"] + button_center[1] pyautogui.click(x=abs_x_roi, y=abs_y_roi) frame_id += 1
second_roi = { "left": 0, "top": int(mon["height"] * 0.18), "width": int(mon["width"] / 2), "height": int(mon["height"] * 0.06) } btn = cv2.imread('center.png') offset_y = int(btn.shape[0]) offset_x = int(btn.shape[1] / 2) thresh = 0.9 frame_list = [] btn_cnt = 1 while True: frame_id += 1 second_roi_crop = numpy.array(sct.grab(second_roi))[:,:,:3] result = cv2.matchTemplate(second_roi_crop, btn, cv2.TM_CCOEFF_NORMED) _, max_val, _, max_loc = cv2.minMaxLoc(result) # define the speed of the screen speed = math.floor(math.log(frame_id)**2.5) print(frame_id, max_val, max_loc, speed) frame_list.append(max_loc[0]) if max_val > thresh: button_center = (max_loc[0] + offset_x, max_loc[1] + offset_y) second_roi_crop = cv2.circle(second_roi_crop.astype(float), button_center, 20, (255, 0, 0), 2) cv2.imwrite(f"./screenshots/{frame_id:03}.jpg", second_roi_crop) abs_x_sec = second_roi["left"] + button_center[0] abs_y_sec = second_roi["top"] + button_center[1] + speed pyautogui.click(x=abs_x_sec, y=abs_y_sec) btn_cnt += 1 if keyboard.is_pressed('q'): break
Como puede ver, la velocidad está parametrizada y, según la configuración de su PC, puede encontrar mejores parámetros que superen mi puntuación más alta. ¡Te animo a que lo hagas! Esto se debe a que el código depende mucho de la velocidad de procesamiento de la imagen y puede variar de un sistema a otro.
El código del proyecto está disponible en Github . Sería genial crear una biblioteca extensa de juegos adictivos pirateados y mantener todos estos algoritmos allí. ¡Así que está invitado a crear las solicitudes de extracción!