import cv2 as cv import numpy as np from utils import mse from game_base_class import GameBase import random GREEN = 1 YELLOW = 2 RED = 3 BLUE = 4 ORANGE = 5 class Sodoku(GameBase): def __init__(self, overlay): super().__init__(overlay) self.data_coordinates = np.zeros((9, 9), dtype=object) self.observation = np.zeros((9, 9), dtype=int) self.colors = [1, 2, 3, 4, 5, 6, 7, 8, 9] self.offset_left = 840 self.offset_down = 130 self.fill_data_coordinates() self.sd_reset_board = cv.imread("control_elements/sodoku_reset_button.jpg", cv.IMREAD_COLOR) self.needles = {1: cv.imread("sodoku/1.jpg", cv.IMREAD_COLOR), 2: cv.imread("sodoku/2.jpg", cv.IMREAD_COLOR), 3: cv.imread("sodoku/3.jpg", cv.IMREAD_COLOR), 4: cv.imread("sodoku/4.jpg", cv.IMREAD_COLOR), 5: cv.imread("sodoku/5.jpg", cv.IMREAD_COLOR), 6: cv.imread("sodoku/6.jpg", cv.IMREAD_COLOR), 7: cv.imread("sodoku/7.jpg", cv.IMREAD_COLOR), 8: cv.imread("sodoku/8.jpg", cv.IMREAD_COLOR), 9: cv.imread("sodoku/9.jpg", cv.IMREAD_COLOR) } def fill_data_coordinates(self): # 840 to 1720 = 880 - 40 / 9 = 93 # 130 to 1010 = 880 - 40 / 9 = 93 # spacing 2 * 20 dim = 93 e_spacing = 0 i_spacing = 0 for e in range(0, 9, 1): if e >= 4: e_spacing = 20 elif e >= 7: e_spacing = 20 for i in range(0, 9, 1): if i >= 4: i_spacing = 20 elif i >= 7: i_spacing = 20 self.data_coordinates[e][i] = [(i * dim) + i_spacing, (e * dim) + e_spacing, dim, dim] def assess_playfield_and_make_move(self): if self.check_for_button_and_execute(self.capture_window.get_screenshot(), self.sd_reset_board): cv.waitKey(2000) new_observation, new_screenshot = self.get_current_board_state() self.find_patterns_and_valid_moves(new_observation) self.observation = new_observation return new_observation def get_current_board_state(self): # get an updated image of the game #screenshot = self.capture_window.get_screenshot() #screenshot = screenshot[900:1030, 540:1870] #screenshot = cv.imread("sodoku/screen_shot.jpg") # gray = cv.cvtColor(screenshot, cv.COLOR_BGR2GRAY) # thresh = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)[1] #if self.check_for_button_and_execute(screenshot, self.ok_button): # cv.waitKey(500) screenshot = self.capture_window.get_screenshot() screenshot = screenshot[130:1010, 840:1720] #cv.imshow("screenshot", screenshot) #cv.waitKey(150) #continue data_coords = np.zeros((9, 9), dtype=object) # field = Pickaxe_Field() for needle_key in self.needles.keys(): # gray_needle = cv.cvtColor(self.needles[needle_key], cv.COLOR_BGR2GRAY) # thresh_needle = cv.threshold(gray_needle, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)[1] rectangles = self.vision_stun.find(screenshot, self.needles[needle_key], 0.85, 56) if len(rectangles) == 0: continue points = self.vision_stun.get_click_points(rectangles) for point in points: x, y = self.point_in_rect(point) if x is not None and y is not None: data_coords[x][y] = int(needle_key) # self.change_value(x, y, int(needle_key)) # print(field.data_value_grid) # cv.circle(screenshot, points[0], 7, (0, 255, 0), -1) #output_image = self.vision_stun.draw_rectangles(screenshot, rectangles) #cv.imshow("output_image", output_image) #cv.waitKey(150) return data_coords, screenshot def point_in_rect(self, point): for e in range(0, 9, 1): for i in range(0, 9, 1): x1, y1, w, h = self.data_coordinates[e][i] x2, y2 = x1 + w, y1 + h x, y = point if x1 < x and x < x2: if y1 < y and y < y2: return e, i return None, None # per pos # select from row,column and quadrant (1-9) # find missing pieces per row, column, quadrant def find_patterns_and_valid_moves(self, state): while self.is_empty_pieces_in_state(state): for e in range(0, 9, 1): for i in range(0, 9, 1): if state[e, i] not in self.colors: #color in self.colors: store = self.collect_existing_pieces(state, e, i) if len(store) == 8: for color in self.colors: if color not in store: state[e, i] = color self.deploy_finding_to_game(e, i, color) if self.overlay.run_mode == 'stopped' or self.overlay.run_mode == 'paused': return if self.overlay.run_mode == 'stopped' or self.overlay.run_mode == 'paused': return def deploy_finding_to_game(self, e, i, color): cv.waitKey(random.randint(3500, 5500)) click_pt = self.get_click_point(self.data_coordinates[e, i]) self.dig_point(click_pt[0] + self.offset_left, click_pt[1] + self.offset_down, 500) y = 1120 x = 850 + ((color - 1) * 110) # +100 self.dig_point(x, y, 100) def is_empty_pieces_in_state(self, state): for e in range(0, 9, 1): for i in range(0, 9, 1): if state[e, i] not in self.colors: return True return False def collect_existing_pieces(self, state, e, i): store = [] for ee in range(0, 9, 1): if state[ee, i] != 0: store.append(state[ee, i]) for ii in range(0, 9, 1): if state[e, ii] != 0: store.append(state[e, ii]) # quad 1 if e <= 2 and i <= 2: for eee in range(0, 3, 1): for iii in range(0, 3, 1): if state[eee, iii] != 0: store.append(state[eee, iii]) # quad 2 elif e <= 2 and i <= 5: for eee in range(0, 3, 1): for iii in range(3, 6, 1): if state[eee, iii] != 0: store.append(state[eee, iii]) # quad 3 elif e <= 2 and i <= 8: for eee in range(0, 3, 1): for iii in range(6, 9, 1): if state[eee, iii] != 0: store.append(state[eee, iii]) # quad 4 elif e <= 5 and i <= 2: for eee in range(3, 6, 1): for iii in range(0, 3, 1): if state[eee, iii] != 0: store.append(state[eee, iii]) # quad 5 elif e <= 5 and i <= 5: for eee in range(3, 6, 1): for iii in range(3, 6, 1): if state[eee, iii] != 0: store.append(state[eee, iii]) # quad 6 elif e <= 5 and i <= 8: for eee in range(3, 6, 1): for iii in range(6, 9, 1): if state[eee, iii] != 0: store.append(state[eee, iii]) # quad 7 elif e <= 8 and i <= 2: for eee in range(6, 9, 1): for iii in range(0, 3, 1): if state[eee, iii] != 0: store.append(state[eee, iii]) # quad 8 elif e <= 8 and i <= 5: for eee in range(6, 9, 1): for iii in range(3, 6, 1): if state[eee, iii] != 0: store.append(state[eee, iii]) # quad 9 elif e <= 8 and i <= 8: for eee in range(6, 9, 1): for iii in range(6, 9, 1): if state[eee, iii] != 0: store.append(state[eee, iii]) unique_numbers = list(set(store)) return unique_numbers