From 687218e29da0a345b003f2bee07974fd2e5286c4 Mon Sep 17 00:00:00 2001 From: Thaloria Date: Mon, 24 Jul 2023 13:22:44 +0200 Subject: [PATCH] added async stone detection thread --- field.py | 2 +- litris.py | 178 +++------------------------------------------------ tetromino.py | 71 ++++++++++++++++---- 3 files changed, 67 insertions(+), 184 deletions(-) diff --git a/field.py b/field.py index 1ca0874..cf1b273 100644 --- a/field.py +++ b/field.py @@ -13,7 +13,7 @@ class Field(): else: self.state = [[' ' for cols in range(Field.WIDTH)] for rows in range(Field.HEIGHT)] - self.rotate_90_degree_clckwise(self.state) + #self.rotate_90_degree_clckwise(self.state) self.cleared_rows = 1 def __str__(self): diff --git a/litris.py b/litris.py index 63ac5b1..54eebbd 100644 --- a/litris.py +++ b/litris.py @@ -7,18 +7,6 @@ from tetromino import Tetromino from optimizer import Optimizer from litris_stone_id_thread import NewStoneID -O_FULL = [[0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0]] -D_FULL = [[0, 0, 0, 0], [0, 1, 1, 0], [0, 0, 1, 0], [0, 0, 0, 0]] -L_FULL = [[0, 0, 0, 0], [0, 0, 1, 0], [1, 1, 1, 0], [0, 0, 0, 0]] -J_FULL = [[0, 0, 0, 0], [1, 1, 1, 0], [0, 0, 1, 0], [0, 0, 0, 0]] -I_FULL = [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]] -C_FULL = [[0, 0, 0, 0], [0, 0, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]] -B_FULL = [[0, 0, 0, 0], [0, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]] -A_FULL = [[0, 0, 0, 0], [0, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]] -S_FULL = [[0, 0, 0, 0], [0, 0, 1, 1], [0, 1, 1, 0], [0, 0, 0, 0]] -Z_FULL = [[0, 0, 0, 0], [0, 1, 1, 0], [0, 0, 1, 1], [0, 0, 0, 0]] -T_FULL = [[0, 0, 0, 0], [0, 1, 1, 1], [0, 0, 1, 0], [0, 0, 0, 0]] - class Litris(GameBase): def __init__(self, overlay): @@ -27,7 +15,6 @@ class Litris(GameBase): self.keyboard = Controller() self.data_coordinates = np.zeros((20, 20), dtype=object) - self.stone_coordinates = np.zeros((4, 4), dtype=object) self.observation = np.zeros((20, 20), dtype=int) self.colors = [1, 2, 3, 4, 5, 6, 7, 8, 9] @@ -41,8 +28,6 @@ class Litris(GameBase): #self.sd_reset_board = cv.imread("control_elements/sodoku_reset_button.jpg", cv.IMREAD_COLOR) - self.needles = {1: cv.imread("litris/blue_needle.jpg", cv.IMREAD_UNCHANGED)} - self.stone_id_thread = NewStoneID() self.move_mode = 1 @@ -62,9 +47,6 @@ class Litris(GameBase): for e in range(0, 20, 1): for i in range(0, 20, 1): self.data_coordinates[e][i] = [(i * dim) + (i * i_spacing), (e * dim) + (e * e_spacing), dim, dim] - for e in range(0, 4, 1): - for i in range(0, 4, 1): - self.stone_coordinates[e][i] = [(i * dim) + (i * i_spacing), (e * dim) + (e * e_spacing), dim, dim] def assess_playfield_and_make_move(self): @@ -86,13 +68,21 @@ class Litris(GameBase): # return current_tetromino = Tetromino.create(current_letter) + if self.move_mode == 2: + current_tetromino.rotate(1) + elif self.move_mode == 3: + current_tetromino.rotate(2) + elif self.move_mode == 4: + current_tetromino.rotate(3) + + opt = Optimizer.get_optimal_drop(self.field, current_tetromino) rotation = opt['tetromino_rotation'] column = opt['tetromino_column'] print("Rota:", rotation) print("column:", column) current_tetromino.rotate(rotation) - offset_col = current_tetromino.get_offset_column(rotation) + offset_col = current_tetromino.get_offset_column(rotation, self.move_mode) print("offset column:", offset_col) self.field.drop(current_tetromino, column) self.move_stone(column - offset_col, rotation) @@ -134,145 +124,6 @@ class Litris(GameBase): elif self.move_mode == 4: self.move_mode = 1 - def get_current_board_state(self): - # get an updated image of the game - screenshot = self.capture_window.get_screenshot() - #screenshot = cv.imread("litris/main_playfield.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[40:1380, 610:1950] - - #cv.imshow("screenshot", screenshot) - #cv.waitKey(150) - #continue - data_coords = np.zeros((20, 20), 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 stone_id(self): - fail_counter = 0 - while True: - screenshot = self.capture_window.get_screenshot() - #screenshot = cv.imread("litris/main_playfield.jpg") - # 1148 1412 580 845 - screenshot = screenshot[623:802, 1128:1432] - #cv.imshow("screenshot", screenshot) - #cv.waitKey(150) - for needle_key in self.needles.keys(): - #rectangles = self.vision_stun.find(screenshot, self.needles[needle_key], 0.85, 1) - rectangles = self.vision_stun.find(screenshot, self.needles[needle_key], 0.85, 1, False, self.needle_masks[needle_key]) - if len(rectangles) == 0: - if self.overlay.run_mode == 'stopped' or self.overlay.run_mode == 'paused': - return - continue - else: - return needle_key - if self.overlay.run_mode == 'stopped' or self.overlay.run_mode == 'paused': - return - if fail_counter >= 3: - self.keyboard.press(Key.down) - self.keyboard.release(Key.down) - print("direction pressed: drop down") - cv.waitKey(50) - fail_counter = fail_counter + 1 - cv.waitKey(50) - - - def new_stone_detection_and_identification(self): - stone_coords = np.zeros((4, 4), dtype=object) - fail_counter = 0 - while True: - screenshot = self.capture_window.get_screenshot() - #screenshot = cv.imread("litris/main_playfield.jpg") - # 1148 1412 580 845 - screenshot = screenshot[580:845, 1148:1412] - #cv.imshow("screenshot", screenshot) - #cv.waitKey(150) - - # 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[1], 0.85, 16) - if len(rectangles) == 0: - if self.overlay.run_mode == 'stopped' or self.overlay.run_mode == 'paused': - return - if fail_counter >= 5: - self.keyboard.press(Key.down) - self.keyboard.release(Key.down) - print("direction pressed: drop down") - cv.waitKey(50) - fail_counter = fail_counter + 1 - cv.waitKey(50) - continue - points = self.vision_stun.get_click_points(rectangles) - - for point in points: - x, y = self.point_in_smal_rect(point) - if x is not None and y is not None: - stone_coords[x][y] = 1 - # 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) - - current_letter = self.get_letter_for_stone(stone_coords) - if current_letter is None: - print("letter id failed for: ", stone_coords) - cv.waitKey(50) - continue - return current_letter - - def get_letter_for_stone(self, stone): - - if np.array_equal(stone, O_FULL): - return "O" - elif np.array_equal(stone, D_FULL): - return "D" - elif np.array_equal(stone, L_FULL): - return "L" - elif np.array_equal(stone, J_FULL): - return "J" - elif np.array_equal(stone, I_FULL): - return "I" - elif np.array_equal(stone, C_FULL): - return "C" - elif np.array_equal(stone, B_FULL): - return "B" - elif np.array_equal(stone, A_FULL): - return "A" - elif np.array_equal(stone, S_FULL): - return "S" - elif np.array_equal(stone, Z_FULL): - return "Z" - elif np.array_equal(stone, T_FULL): - return "T" - else: - return None - def move_stone(self, col_movement, rotation): if col_movement is None: return @@ -350,15 +201,4 @@ class Litris(GameBase): if x1 < x and x < x2: if y1 < y and y < y2: return e, i - return None, None - - def point_in_smal_rect(self, point): - for e in range(0, 4, 1): - for i in range(0, 4, 1): - x1, y1, w, h = self.stone_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 \ No newline at end of file diff --git a/tetromino.py b/tetromino.py index 00e57a3..677bf06 100644 --- a/tetromino.py +++ b/tetromino.py @@ -167,20 +167,63 @@ class Tetromino(): self.state = [row[::-1] for row in self.state[::-1]] return self - def get_offset_column(self, rotation): - offset_map= { - 'i': {0: 8, 1: 9, 2: 9, 3: 9}, - 'a': {0: 9, 1: 9, 2: 9, 3: 9}, - 'b': {0: 9, 1: 9, 2: 9, 3: 9}, - 'c': {0: 10, 1: 10, 2: 10, 3: 10}, - 'o': {0: 9, 1: 9, 2: 9, 3: 9}, - 'd': {0: 9, 1: 9, 2: 9, 3: 9}, - 't': {0: 9, 1: 9, 2: 8, 3: 9}, - 's': {0: 9, 1: 9, 2: 9, 3: 9}, - 'z': {0: 9, 1: 9, 2: 9, 3: 9}, - 'j': {0: 8, 1: 9, 2: 9, 3: 9}, - 'l': {0: 8, 1: 9, 2: 9, 3: 9} - } + def get_offset_column(self, rotation, mode): + if mode == 1: + offset_map= { + 'i': {0: 8, 1: 9, 2: 8, 3: 9}, + 'a': {0: 9, 1: 9, 2: 9, 3: 9}, + 'b': {0: 9, 1: 9, 2: 9, 3: 9}, + 'c': {0: 10, 1: 10, 2: 10, 3: 10}, + 'o': {0: 9, 1: 9, 2: 9, 3: 9}, + 'd': {0: 9, 1: 9, 2: 9, 3: 9}, + 't': {0: 9, 1: 9, 2: 8, 3: 9}, + 's': {0: 9, 1: 9, 2: 9, 3: 9}, + 'z': {0: 9, 1: 9, 2: 9, 3: 9}, + 'j': {0: 8, 1: 9, 2: 9, 3: 9}, + 'l': {0: 8, 1: 9, 2: 9, 3: 9} + } + elif mode == 2: + offset_map= { + 'i': {0: 9, 1: 8, 2: 9, 3: 8}, + 'a': {0: 9, 1: 9, 2: 9, 3: 9}, + 'b': {0: 9, 1: 9, 2: 9, 3: 9}, + 'c': {0: 10, 1: 10, 2: 10, 3: 10}, + 'o': {0: 9, 1: 9, 2: 9, 3: 9}, + 'd': {0: 9, 1: 9, 2: 9, 3: 9}, + 't': {0: 9, 1: 9, 2: 9, 3: 8}, + 's': {0: 9, 1: 9, 2: 9, 3: 9}, + 'z': {0: 9, 1: 9, 2: 9, 3: 9}, + 'j': {0: 9, 1: 8, 2: 9, 3: 9}, + 'l': {0: 9, 1: 8, 2: 9, 3: 9} + } + elif mode == 3: + offset_map= { + 'i': {0: 8, 1: 9, 2: 8, 3: 9}, + 'a': {0: 9, 1: 9, 2: 9, 3: 9}, + 'b': {0: 9, 1: 9, 2: 9, 3: 9}, + 'c': {0: 10, 1: 10, 2: 10, 3: 10}, + 'o': {0: 9, 1: 9, 2: 9, 3: 9}, + 'd': {0: 9, 1: 9, 2: 9, 3: 9}, + 't': {0: 9, 1: 9, 2: 8, 3: 9}, + 's': {0: 9, 1: 9, 2: 9, 3: 9}, + 'z': {0: 9, 1: 9, 2: 9, 3: 9}, + 'j': {0: 8, 1: 9, 2: 9, 3: 9}, + 'l': {0: 8, 1: 9, 2: 9, 3: 9} + } + else: #mode == 4: + offset_map = { + 'i': {0: 8, 1: 9, 2: 8, 3: 9}, + 'a': {0: 9, 1: 9, 2: 9, 3: 9}, + 'b': {0: 9, 1: 9, 2: 9, 3: 9}, + 'c': {0: 10, 1: 10, 2: 10, 3: 10}, + 'o': {0: 9, 1: 9, 2: 9, 3: 9}, + 'd': {0: 9, 1: 9, 2: 9, 3: 9}, + 't': {0: 9, 1: 9, 2: 8, 3: 9}, + 's': {0: 9, 1: 9, 2: 9, 3: 9}, + 'z': {0: 9, 1: 9, 2: 9, 3: 9}, + 'j': {0: 8, 1: 9, 2: 9, 3: 9}, + 'l': {0: 8, 1: 9, 2: 9, 3: 9} + } return offset_map.get(self.letter)[rotation]