diff --git a/combined_bot_main.py b/combined_bot_main.py index c437d08..cf7d7e1 100644 --- a/combined_bot_main.py +++ b/combined_bot_main.py @@ -10,6 +10,7 @@ from mine import Mine from sodoku import Sodoku from fruit import Fruit from pickaxe import Pickaxe_Field +from litris import Litris def run(): @@ -65,6 +66,9 @@ def run(): elif overlay.rb_int.get() == 9: paxe = Pickaxe_Field(overlay) paxe.execute_main_loop() + elif overlay.rb_int.get() == 10: + ltris = Litris(overlay) + ltris.execute_main_loop() if __name__ == "__main__": run() diff --git a/combined_user_interface.py b/combined_user_interface.py index 5d52915..924b4a9 100644 --- a/combined_user_interface.py +++ b/combined_user_interface.py @@ -33,7 +33,7 @@ class PrimaryOverlay(threading.Thread): self.Emitter_Box = ttk.Combobox self.RadioButtons = dict - self.RadioButtonNames = ["Equip", "Crops", "Farm", "Magic", "Craft", "Mine", "Fruit", "Sodo", "PAxe"] + self.RadioButtonNames = ["Equip", "Crops", "Farm", "Magic", "Craft", "Mine", "Fruit", "Sodo", "PAxe", "Ltris"] self.RadioButton1 = tk.Radiobutton self.RadioButton2 = tk.Radiobutton self.RadioButton3 = tk.Radiobutton @@ -43,12 +43,13 @@ class PrimaryOverlay(threading.Thread): self.RadioButton7 = tk.Radiobutton self.RadioButton8 = tk.Radiobutton self.RadioButton9 = tk.Radiobutton + self.RadioButton10 = tk.Radiobutton self.StartButton = tk.Button self.StopButton = tk.Button self.PauseButton = tk.Button self.QuitButton = tk.Button - self.TkPosition = '133x379+60+600' + self.TkPosition = '133x404+60+600' self.setDaemon(True) self.StatusLabel = tk.Label @@ -76,7 +77,7 @@ class PrimaryOverlay(threading.Thread): self.rb_int = tk.IntVar(self.root, value=1) self.RadioButtons = dict() # var = tk.IntVar(value=1) - for i in range(1, 10): + for i in range(1, 11): self.RadioButtons[i] = tk.Radiobutton(self.rb_frame, text=self.RadioButtonNames[i - 1], variable=self.rb_int, value=i, command=self.radio_button_callback) @@ -313,6 +314,17 @@ class PrimaryOverlay(threading.Thread): self.SpawnLabel.configure(text="") self.EnergyLabel.configure(text="") self.hide_mining_overlay() + elif self.rb_int.get() == 10: + self.EnergyEntry.configure(state=tk.DISABLED) + self.energy_use.set('') + self.SpawnEntry.configure(state=tk.DISABLED) + self.spawn_use.set('') + self.Emitter_Box.configure(state=tk.DISABLED) + self.emitter_use.set('') + self.EmitterLabel.configure(text="") + self.SpawnLabel.configure(text="") + self.EnergyLabel.configure(text="") + self.hide_mining_overlay() def get_run_mode(self): return self.run_mode diff --git a/litris.py b/litris.py new file mode 100644 index 0000000..0c10a2b --- /dev/null +++ b/litris.py @@ -0,0 +1,213 @@ + + + +''' + +playfield: +box = 63*63 + 4 +20x20 boxes +2d array filled or not +shape class + +methods: +shift direction +is row full + + +actions: +mini frame to detect a new spawned piece in the middle of the board +direction decision +identify shape +find posititon to store on y axis and move n fields +drop piece down + + +extras: +pre run calc with next piece and bypass calc + + +''' + +import cv2 as cv +import keyboard +import numpy as np +from utils import mse +from game_base_class import GameBase +import random + +BLOCK_FULL = [[0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0]] +BLOCK_SMALL = [[1, 1], [1, 1]] +BLOCK_COL = 9 + +L1_FULL = [[0, 0, 0, 0], [0, 0, 1, 0], [1, 1, 1, 0], [0, 0, 0, 0]] +L1_SMALL = [[0, 0, 1], [1, 1, 1]] +L1_COL = 8 + +LINE_FULL = [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]] +LINE_SMALL = [[1, 1, 1, 1]] +LINE_COL = 8 + +DOT_FULL = [[0, 0, 0, 0], [0, 0, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]] +DOT_SMALL = [[1]] +DOT_COL = 10 + +class Litris(GameBase): + + def __init__(self, overlay): + super().__init__(overlay) + + 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] + + self.offset_left = 610 + self.offset_down = 40 + + self.fill_data_coordinates() + + #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_COLOR) + # 2: cv.imread("sodoku/2.jpg", cv.IMREAD_COLOR), + } + + def fill_data_coordinates(self): + # 610 to 1950 = 1340 - 76 / 20 = 63 + # 40 to 1380 = 1340 - 76 / 20 = 63 + # spacing 19 * 4 + dim = 63 + e_spacing = 4 + i_spacing = 4 + 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): + + #if self.check_for_button_and_execute(self.capture_window.get_screenshot(), self.sd_reset_board): + # cv.waitKey(2000) + current_stone = self.new_stone_detection_and_identification() + new_observation, new_screenshot = self.get_current_board_state() + col = self.find_place_for_stone(current_stone, new_screenshot) + self.move_stone(col) + + + 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 = 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 new_stone_detection_and_identification(self): + stone_coords = np.zeros((4, 4), dtype=object) + 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: + cv.waitKey(100) + 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) + return stone_coords + + def find_place_for_stone(self, stone, current_board): + # block + for e in range(18, 20, 1): + for i in range(0, 19, 1): + if current_board[e][i] == 0 and current_board[e - 1][i] == 0 and current_board[e][i + 1] == 0 and current_board[e - 1][i + 1] == 0: + return i - BLOCK_COL + + + + def move_stone(self, col_movement): + keyboard.press('down') + cv.waitKey(100) + if col_movement < 0: + for i in range(0, col_movement, - 1): + keyboard.press('left') + cv.waitKey(100) + else: + for i in range(0, col_movement, 1): + keyboard.press('right') + cv.waitKey(100) + + def point_in_rect(self, point): + for e in range(0, 20, 1): + for i in range(0, 20, 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 + + 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/litris/blue_needle.jpg b/litris/blue_needle.jpg new file mode 100644 index 0000000..87f3525 Binary files /dev/null and b/litris/blue_needle.jpg differ diff --git a/litris/main_playfield.jpg b/litris/main_playfield.jpg new file mode 100644 index 0000000..4753aea Binary files /dev/null and b/litris/main_playfield.jpg differ diff --git a/pickaxe.py b/pickaxe.py index 940856b..8a0b91f 100644 --- a/pickaxe.py +++ b/pickaxe.py @@ -162,7 +162,9 @@ class Pickaxe_Field(GameBase): #5 merge if secone row bottom matches #4 #6 rightest column has no empty spots (enable downwards movement) - + # phase 1 build up second, third, fourth etc + # phase 2 build up merge bottom right + # phase 3 merge points = 0 highest = np.max(shift_dir)