From 270939859fc2495f638328a45f30ca8973191b59 Mon Sep 17 00:00:00 2001 From: sunwoo1524 Date: Mon, 9 Oct 2023 15:41:46 +0900 Subject: [PATCH] add maze generator module --- modules/Maze.py | 22 +++++++ modules/MazeGenerator.py | 135 +++++++++++++++++++++++++++++++++++++++ modules/maze/maze.png | Bin 0 -> 308218 bytes requirements.txt | 2 + 4 files changed, 159 insertions(+) create mode 100644 modules/Maze.py create mode 100644 modules/MazeGenerator.py create mode 100644 modules/maze/maze.png diff --git a/modules/Maze.py b/modules/Maze.py new file mode 100644 index 0000000..4f9ce19 --- /dev/null +++ b/modules/Maze.py @@ -0,0 +1,22 @@ +import os + +from module_interface import ModuleInterface +from mipac.models import Note + + +class MyModule(ModuleInterface): + def __init__(self): + super().__init__() + self.name = "Maze" + self.regex_pattern = r".*미로|Maze|maze.*" + + print("[Maze] Maze Module loaded.") + + async def execute_module(self, ctx: Note): + print(f"[Maze] {self.name} 실행: {ctx.content}") + + await self.manager.require("MazeGenerator").get_func("generate_maze")() + + file = await self.manager.bot.client.drive.file.action.upload_file(file=os.path.dirname(os.path.abspath(__file__)) + "/maze/maze.png") + + await ctx.api.action.reply("미로를 생성했어요!", files=[file]) diff --git a/modules/MazeGenerator.py b/modules/MazeGenerator.py new file mode 100644 index 0000000..e589bc6 --- /dev/null +++ b/modules/MazeGenerator.py @@ -0,0 +1,135 @@ +import cv2 +import numpy +import random +import os + +from module_interface import ModuleInterface + + +class MazeGenerator(ModuleInterface): + def __init__(self): + super().__init__() + + self.name = "MazeGenerator" + self.funcs["generate_maze"] = self.generateMaze + + print("[MazeGenerator] MazeGenerator Module loaded.") + + # generate maze image + async def generateMaze(self): + width = 3280 + height = 3280 + img = numpy.zeros((width, height, 3), dtype = "uint8") + + LEFT = 1 + RIGHT = 2 + UP = 3 + DOWN = 4 + + maze_x = 50 + maze_y = 50 + maze_width = width - maze_x * 2 + maze_height = height - maze_y * 2 + maze_col = 30 + maze_row = 30 + + wall_size = 8 + + cell_x = 0 + cell_y = 0 + + cell_stack = [[0, 0]] # [[x, y]] + cells_visited = [[0, 0]] # [[x, y]] + + # fill image + cv2.rectangle(img, (0, 0), (width, height), (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)), -1) + + # draw border + border_color = (0, 0, 0) + cv2.rectangle(img, (int(maze_x - wall_size / 2), int(maze_y - wall_size / 2)), (int(width - maze_x + wall_size / 2), int(height - maze_y + wall_size / 2)), border_color, -1) + + ## draw maze ## + size = int(maze_width / maze_col) + + cv2.rectangle( + img, + (cell_x * size + wall_size + maze_x, cell_y * size + wall_size + maze_y), + (cell_x * size + size - wall_size + maze_x, cell_y * size + size - wall_size + maze_y), + (255, 255, 255), + -1 + ) + + while len(cell_stack) > 0: + # log pos + if not [cell_x, cell_y] in cells_visited: + cells_visited.append([cell_x, cell_y]) + + # get around_cells + around_cells = [] + around_cells.append([cell_x + 1, cell_y, LEFT]) + around_cells.append([cell_x - 1, cell_y, RIGHT]) + around_cells.append([cell_x, cell_y - 1, UP]) + around_cells.append([cell_x, cell_y + 1, DOWN]) + + temp = around_cells.copy() + + for around_cell in temp: + if [around_cell[0], around_cell[1]] in cells_visited or around_cell[0] < 0 or around_cell[1] < 0 or around_cell[0] >= maze_col or around_cell[1] >= maze_row: + around_cells.pop(around_cells.index(around_cell)) + + if len(around_cells) > 0: + # draw cell + next_pos = random.choice(around_cells) + cell_stack.append([next_pos[0], next_pos[1]]) + + cv2.rectangle( + img, + (next_pos[0] * size + wall_size + maze_x, next_pos[1] * size + wall_size + maze_y), + (next_pos[0] * size + size - wall_size + maze_x, next_pos[1] * size + size - wall_size + maze_y), + (255, 255, 255), + -1 + ) + + wall_x = next_pos[0] * size + wall_y = next_pos[1] * size + + if next_pos[2] == LEFT: + wall_x -= size / 2 + elif next_pos[2] == RIGHT: + wall_x += size / 2 + elif next_pos[2] == UP: + wall_y += size / 2 + elif next_pos[2] == DOWN: + wall_y -= size / 2 + + cv2.rectangle( + img, + (int(wall_x + wall_size + maze_x), int(wall_y + wall_size + maze_y)), + (int(wall_x + size - wall_size + maze_x), int(wall_y + size - wall_size + maze_y)), + (255, 255, 255), + -1 + ) + + cell_x = next_pos[0] + cell_y = next_pos[1] + cell_stack.append([cell_x, cell_y]) + else: + if cell_x == 0 and cell_y == 0: + break + + # go back + cell_x = cell_stack[-1][0] + cell_y = cell_stack[-1][1] + cell_stack.pop() + ## + + # draw start point + cv2.circle(img, (int(size - size / 2 + maze_x), int(size - size / 2 + maze_y)), 15, (0, 0, 0), -1) + + # draw goal point + cv2.circle(img, (int(maze_width - size / 2 + maze_x), int(maze_height - size / 2 + maze_y)), 15, (22, 183, 65), -1) + + # download image + cv2.imwrite(os.path.dirname(os.path.abspath(__file__)) + "/maze/maze.png", img) + + print("[MazeGenerator] Maze was generated") diff --git a/modules/maze/maze.png b/modules/maze/maze.png new file mode 100644 index 0000000000000000000000000000000000000000..75a04204d4c9d94e9dd3a58656aff5702f89e9c2 GIT binary patch literal 308218 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£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 Q{NrxC<%ad&x%0vQ4=0~UuK)l5 literal 0 HcmV?d00001 diff --git a/requirements.txt b/requirements.txt index 0b64110..0b83c5f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,5 @@ mipa~=0.3.0 mipac~=0.5.0 pyfiglet~=0.8.post1 python-dotenv~=1.0.0 +opencv-python==4.8.1.78 +numpy==1.26.0 \ No newline at end of file