import os from subprocess import Popen, PIPE import numpy as np import cv2 import threading as th import time as t import hyprpy as hypr from evdev import UInput, ecodes as e import math # Function to create and initialize a virtual keyboard def create_virtual_keyboard(): capabilities = { e.EV_KEY: [e.KEY_W, e.KEY_A, e.KEY_D, e.KEY_S] } return UInput(capabilities) virtual_keyboard = create_virtual_keyboard() print(virtual_keyboard) # Function to send a keystroke def send_keystroke(virtual_keyboard, key): virtual_keyboard.write(e.EV_KEY, key, 1) # Key down t.sleep(0.01) virtual_keyboard.write(e.EV_KEY, key, 0) # Key up virtual_keyboard.syn() instance = hypr.Hyprland() print("please select the game area") stream = os.popen('slurp') capture_area = stream.read() size = list(map(int, capture_area.split(' ')[1].split('x'))) boxPos = list(map(int, capture_area.split(' ')[0].split(','))) print(capture_area, size) height = 0 width = 0 def colorCodeToColorArary(target: str): return np.array([int(target[4:6], 16), int(target[2:4], 16), int(target[0:2], 16)]) green_1 = colorCodeToColorArary("AAD751") green_2 = colorCodeToColorArary("A2D149") fruit_color_1 = colorCodeToColorArary("D8B81C") fruit_color_2 = colorCodeToColorArary("CCAD1E") def get_img(): global height, width stream = Popen(['grim', '-g', capture_area.strip(), '-'], stdout=PIPE) img = cv2.imdecode(np.frombuffer(stream.stdout.read(), dtype='uint8'), cv2.IMREAD_COLOR) height, width, _ = img.shape return img def get_start(img): start = None for i in range(height): for j in range(width): if start is None: if (img[i, j] == green_1).all(): print("found target at start", i, j) start = [i, j] else: if (img[i, j] == green_2).all(): print("found end at", i, j) return [*start, j - start[1]] if start is not None: print("Something is wrong found start but not end at the same line") exit(1) img = get_img() cv2.imshow('image', img) cv2.waitKey(1) start = get_start(img) targets = [] # 0 - empty # 1 - fruit # 2 - snake # 3 - head targets_v = {} head = None food = None snake_part = [] for i in range(15): for j in range(17): i2 = i * start[2] + int(start[2] / 2) + start[0] j2 = j * start[2] + int(start[2] / 2) + start[1] targets.append([i2, j2, i, j]) targets_v[f"{i}-{j}"] = None def draw_square(img, pos, color): i, j = pos i2 = int(i * start[2] + int(start[2] / 2) + start[0]) j2 = int(j * start[2] + int(start[2] / 2) + start[1]) img[i2-5:i2+5, j2-5:j2+5] = color def draw_dots_from_data(img): global food, head for target in targets: i2, j2, i, j = target v = targets_v[f"{i}-{j}"] if v == 0: # img[i2-5:i2+5, j2-5:j2+5] = [0, 255, 0] pass elif v == 1: img[i2-5:i2+5, j2-5:j2+5] = [0, 0, 255] elif v == 2: img[i2-5:i2+5, j2-5:j2+5] = [255, 0, 0] elif v == 3: img[i2-5:i2+5, j2-5:j2+5] = [255, 255, 255] else: img[i2-5:i2+5, j2-5:j2+5] = [255, 0, 255] def draw_dots(img): global food, head, snake_part, head_p snake_part = [] for target in targets: i2, j2, i, j = target color = img[i2, j2] # body samples bs_1 = img[i2 - 7, j2] bs_2 = img[i2 + 7, j2] bs_3 = img[i2, j2 - 7] bs_4 = img[i2, j2 + 7] all_the_same = (bs_1 == bs_2).all() and (bs_1 == bs_3).all() and (bs_1 == bs_4).all() bs_list = np.array([bs_1, bs_2, bs_3, bs_4]) if (color == green_1).all() or (color == green_2).all() and all_the_same: # img[i2-5:i2+5, j2-5:j2+5] = [0, 255, 0] targets_v[f"{i}-{j}"] = 0 elif (color == fruit_color_1).all() or (color == fruit_color_2).all(): img[i2-5:i2+5, j2-5:j2+5] = [0, 0, 255] targets_v[f"{i}-{j}"] = 1 food = [i, j] elif color[0] > 150: img[i2-5:i2+5, j2-5:j2+5] = [255, 0, 0] targets_v[f"{i}-{j}"] = 2 snake_part.append([i, j]) else: greens_1 = np.sum(bs_list == green_1, axis=1) greens_2 = np.sum(bs_list == green_2, axis=1) if np.sum(greens_1) == 9 and bs_list[np.argmin(greens_1)][0] > 150: targets_v[f"{i}-{j}"] = 3 img[i2-5:i2+5, j2-5:j2+5] = [255, 255, 255] head = np.array([i, j]) if np.sum(greens_2) == 9 and bs_list[np.argmin(greens_2)][0] > 150: targets_v[f"{i}-{j}"] = 3 img[i2-5:i2+5, j2-5:j2+5] = [255, 255, 255] head = np.array([i, j]) else: img[i2, j2] = [255, 0, 255] img[i2 - 7, j2] = [255, 0, 255] img[i2 + 7, j2] = [255, 0, 255] img[i2, j2 - 7] = [255, 0, 255] img[i2, j2 + 7] = [255, 0, 255] targets_v[f"{i}-{j}"] = None def pt_dist(a, b): return math.sqrt((a[0] - b[0])**2 + (a[1] - b[1])**2) def get_all_adj(a): return [ [a[0] + 1, a[1]], [a[0] - 1, a[1]], [a[0], a[1] + 1], [a[0], a[1] - 1], ] def draw_path(img, ps, final=False): for p in ps: i, j = p i2 = i * start[2] + int(start[2] / 2) + start[0] j2 = j * start[2] + int(start[2] / 2) + start[1] if final: img[i2-3:i2+3, j2-3:j2+3] = [255, 255, 0] else: img[i2-3:i2+3, j2-3:j2+3] = [0, 255, 255] def calculate_path(pos, visited, img=None): # if img is not None and visited is not None: # draw_dots_from_data(img) # draw_path(img, visited) # cv2.imshow('image-thread', img) # cv2.waitKey(1) n_visited = visited.copy() n_visited.append(pos) queue = get_all_adj(pos) queue.sort(key=lambda p: pt_dist(food, p), reverse=False) for i in queue: if i in n_visited: # print("already visisted", i) continue v = targets_v.get(f'{i[0]}-{i[1]}') if v == 1: # print("is food", i) return [pos, i] if v != 0: # print("is ocupied", i) continue maybe_path = calculate_path(i, n_visited, img=img) if maybe_path is not None: maybe_path.insert(0, pos) return maybe_path return None draw_dots(img) cv2.imshow('image', img) cv2.waitKey(1) # Good for testing # cv2.waitKey(0) # exit(1) last = t.time_ns() g_img = img def img_collection_and_path_analisis(data): print("start img col") path = None while True: img = get_img() data['img'] = img draw_dots(img) if path is not None: draw_path(img, path, final=True) if data['path'] is None: if head is None: print("could not find head skiping") t.sleep(0.001) continue if food is None: print("could not find food skiping") t.sleep(0.001) continue # print("calculate path") maybe_path = calculate_path(list(head), [], img) if maybe_path is None: # print("No path found") pass draw_dots_from_data(img) if maybe_path is not None: draw_path(img, maybe_path, True) # print("got_path") path = maybe_path data['path'] = maybe_path data = {'path': None, 'img': None} img_col = th.Thread(target=img_collection_and_path_analisis, args=(data, )) img_col.start() last = t.time_ns() head_pred = None time_to_pred = None start_time_to_pred = None last_time_to_pred = 0 lp_avg = 0 lp_count = 0 while True: # sleep mode if the mouse is outside the area pos = instance.get_cursor_pos() if not ((pos[0] > boxPos[0]) and (pos[0] < boxPos[0] + size[0]) and (pos[1] > boxPos[1]) and (pos[1] < boxPos[1] + size[1])): t.sleep(0.5) cv2.waitKey(1) continue now = t.time_ns() lp_count += 1 lp_time = (now - last)/1000000 lp_avg += lp_time time_since_last_move = (now - start_time_to_pred)/1000000 if start_time_to_pred is not None else 0 lp_time_next = (last_time_to_pred - time_since_last_move) / (lp_avg/lp_count) print( f'\r lp time {lp_time:.4f}ms lp avg {lp_avg/lp_count:.4f}ms', "pred: ", last_time_to_pred, f"loops til next: {lp_time_next:.2f}", f"loops time since last move {time_since_last_move:.2f}", " ms ", end="") last = t.time_ns() path = data['path'] img = data['img'].copy() if img is not None: cv2.imshow('image', img) cv2.waitKey(1) l_head = list(head) if l_head == head_pred and time_to_pred is None: time_to_pred = t.time_ns() - start_time_to_pred last_time_to_pred = (t.time_ns() - start_time_to_pred)/1000000 print("pred hit in ", time_to_pred / 1000000, "ms!", end=" ") if head is not None and path is not None: if l_head in path: index = path.index(l_head) if index < len(path) - 1: diff = np.array(l_head) - np.array(path[index + 1]) if diff[1] == 1: # print('turn Left', end="") send_keystroke(virtual_keyboard, e.KEY_A) elif diff[1] == -1: # print('turn Right', end="") send_keystroke(virtual_keyboard, e.KEY_D) elif diff[0] == 1: # print('turn Up', end="") send_keystroke(virtual_keyboard, e.KEY_W) elif diff[0] == -1: # print('turn Down', end="") send_keystroke(virtual_keyboard, e.KEY_S) else: print("not sure what to do", diff, end="") exit(1) if head_pred != path[index + 1]: head_pred = path[index + 1] start_time_to_pred = t.time_ns() time_to_pred = None else: print('head not in path', end="") data['path'] = None else: # print("head", head, "path", path) pass print(" ", end="") cv2.waitKey(0) # import pygame # scrn = pygame.display.set_mode(size) # running = True # while (running): # for i in pygame.event.get(): # if i.type == pygame.QUIT: # running = False # # stream = Popen(['grim', '-g', capture_area.strip(), '-'], stdout=PIPE) # # print(stream.stdout.read()) # # # img = pygame.image.load(stream.stdout, "test.png") # # print(len(stream.stdout.read())) # # # img = pygame.image.frombuffer(stream.stdout.read(), size, "RGB") # # # scrn.blit(img, (0, 0)) # # # pygame.display.flip() # # pygame.quit()