|
| 1 | +import pygame, math |
| 2 | +import my_maze |
| 3 | + |
| 4 | +pygame.init() |
| 5 | +pygame.display.set_caption("Demo => Path Finding") |
| 6 | +cell_font = pygame.font.SysFont(pygame.font.get_default_font(), 25) |
| 7 | + |
| 8 | +def trans_rect(r, offset): |
| 9 | + """ |
| 10 | +
|
| 11 | + This function takes rect( => x,y,w,h <= ) then adjusts the position of rectangle by applying an offset to it |
| 12 | + |
| 13 | + Parameters: |
| 14 | + ----------- |
| 15 | + r (list): This parameter represents rectangle. |
| 16 | +
|
| 17 | + offset (list): This parameter represents the offset by which you want to move the rectangle. |
| 18 | + |
| 19 | + Returns: |
| 20 | + -------- |
| 21 | + (list): |
| 22 | + - The new x-coordinate of the rectangle's top-left corner. |
| 23 | + - The new y-coordinate of the rectangle's top-left corner. |
| 24 | + - The original width of the rectangle. |
| 25 | + - The original height of the rectangle |
| 26 | + |
| 27 | + """ |
| 28 | + return [r[0]+offset[0], r[1]+offset[1], r[2], r[3]] |
| 29 | + |
| 30 | +def main_loop(ui): |
| 31 | + """ |
| 32 | + |
| 33 | + Run the main event loop of the application. |
| 34 | +
|
| 35 | + This function initializes the display, handles user input events, and updates the display based on the user interface (UI) object's draw method. The loop runs indefinitely until the user quits the application or presses the escape key. |
| 36 | +
|
| 37 | + Parameters |
| 38 | + ---------- |
| 39 | + ui : object |
| 40 | + An instance of a user interface class that has `step`, `reset`, and `draw` methods. |
| 41 | +
|
| 42 | + Returns |
| 43 | + ------- |
| 44 | + None |
| 45 | +
|
| 46 | + """ |
| 47 | + |
| 48 | + screen = pygame.display.set_mode((1000,800)) |
| 49 | + |
| 50 | + clock = pygame.time.Clock() |
| 51 | + clock.tick() |
| 52 | + while True: |
| 53 | + event = pygame.event.poll() |
| 54 | + if event.type == pygame.QUIT: |
| 55 | + break |
| 56 | + elif event.type == pygame.KEYDOWN: |
| 57 | + if event.key == pygame.K_ESCAPE: |
| 58 | + break |
| 59 | + if event.key == pygame.K_LEFT: |
| 60 | + ui.step(-1) |
| 61 | + if event.key == pygame.K_RIGHT: |
| 62 | + ui.step(1) |
| 63 | + if event.key == pygame.K_r: |
| 64 | + ui.reset() |
| 65 | + |
| 66 | + ui.draw(screen) |
| 67 | + |
| 68 | + pygame.display.update() |
| 69 | + clock.tick(60) |
| 70 | + |
| 71 | + pygame.quit() |
| 72 | + |
| 73 | + |
| 74 | +class Finder: |
| 75 | + def __init__(self): |
| 76 | + self.board = None |
| 77 | + self.path = None |
| 78 | + |
| 79 | + def set_board(self, board): |
| 80 | + """ |
| 81 | +
|
| 82 | + Set the board attribute of the instance. |
| 83 | +
|
| 84 | + Parameters |
| 85 | + ---------- |
| 86 | + self : object |
| 87 | + The instance of the class from which this method is called. |
| 88 | + |
| 89 | + board : Board |
| 90 | + The board object to be set for the instance. |
| 91 | +
|
| 92 | + Returns |
| 93 | + ------- |
| 94 | + None |
| 95 | +
|
| 96 | + """ |
| 97 | + self.board = board |
| 98 | + |
| 99 | + def set_path(self, path): |
| 100 | + """ |
| 101 | +
|
| 102 | + Set the path attribute of the instance. |
| 103 | +
|
| 104 | + Parameters |
| 105 | + ---------- |
| 106 | + self : object |
| 107 | + The instance of the class from which this method is called. |
| 108 | + |
| 109 | + path : list of tuples/lists |
| 110 | + The path to be set for the instance, typically a list of positions. |
| 111 | +
|
| 112 | + Returns |
| 113 | + ------- |
| 114 | + None |
| 115 | + |
| 116 | + """ |
| 117 | + self.path = path |
| 118 | + |
| 119 | + def run(self): |
| 120 | + """ |
| 121 | +
|
| 122 | + Start the main event loop of the application. |
| 123 | +
|
| 124 | + This method calls the main_loop function, passing the current instance as an argument. |
| 125 | +
|
| 126 | + Parameters |
| 127 | + ---------- |
| 128 | + self : object |
| 129 | + The instance of the class from which this method is called. |
| 130 | +
|
| 131 | + Returns |
| 132 | + ------- |
| 133 | + None |
| 134 | +
|
| 135 | + """ |
| 136 | + main_loop(self) |
| 137 | + |
| 138 | + def draw(self, surface): |
| 139 | + """ |
| 140 | + Draw the board and path on the given surface. |
| 141 | +
|
| 142 | + This method draws the board on the provided surface. If a path is set, it also draws the path. |
| 143 | + |
| 144 | + Parameters |
| 145 | + ---------- |
| 146 | + self : object |
| 147 | + The instance of the class from which this method is called. |
| 148 | + |
| 149 | + surface : pygame.Surface |
| 150 | + The Pygame surface on which the board and path will be drawn. |
| 151 | + |
| 152 | + Returns |
| 153 | + ------- |
| 154 | + None |
| 155 | + |
| 156 | + """ |
| 157 | + if self.board == None: |
| 158 | + return |
| 159 | + |
| 160 | + draw_board(surface, surface.get_rect(), self.board) |
| 161 | + if self.path != None: |
| 162 | + draw_path(surface, surface.get_rect(), self.board, self.path) |
| 163 | + |
| 164 | + |
| 165 | +class BoardMetrics: |
| 166 | + def __init__(self, area, board): |
| 167 | + self.area = area #area of the board which is surface.rect() object rect<x,y,w,h> board is what we created in my_maze.py |
| 168 | + self.spacing = 3 #spacing for cell's and board |
| 169 | + self.left = area[0] + self.spacing #left is starting position of cell 1 with spacing |
| 170 | + self.top = area[1] + self.spacing # same for left but for top side |
| 171 | + self.height = area[3] - area[1] - 2 * self.spacing #height of board - 2 spacing from each side |
| 172 | + self.width = area[2] - area[0] - 2 * self.spacing #width of board - 2 spacing from each side |
| 173 | + self.num_y = board.get_size()[1] #board height with number of rows[[][]---] |
| 174 | + self.num_x = board.get_size()[0] #board width with number of columns[[1,2,3,4...]] |
| 175 | + self.cx = self.width / self.num_x #cell's x found by dividing width of board to num of cell's |
| 176 | + self.cy = self.height / self.num_y #cell's y found by dividing height of board to num of cell's |
| 177 | + |
| 178 | + |
| 179 | + def cell_rect(self, pos): |
| 180 | + """ |
| 181 | +
|
| 182 | + This function takes position and returns rectangle object at that position as a list with its [x,y,w,h] |
| 183 | + |
| 184 | + Parameters: |
| 185 | + ----------- |
| 186 | + pos (list): This parameter represents the position of the cell. |
| 187 | +
|
| 188 | + Returns: |
| 189 | + -------- |
| 190 | + list: |
| 191 | + The new x-coordinate of the rectangle's top-left corner. |
| 192 | + The new y-coordinate of the rectangle's top-left corner. |
| 193 | + The original width of the rectangle. |
| 194 | + The original height of the rectangle. |
| 195 | +
|
| 196 | + """ |
| 197 | + return [self.left + pos[0]*self.cx, self.top + pos[1]*self.cy, self.cx - self.spacing, self.cy - self.spacing] |
| 198 | + |
| 199 | + def cell_center(self, pos): |
| 200 | + """ |
| 201 | +
|
| 202 | + This function takes position and returns position of cell's center as a list |
| 203 | + |
| 204 | + Parameters: |
| 205 | + ----------- |
| 206 | + pos (list): This parameter represents the position of the cell |
| 207 | +
|
| 208 | + Returns: |
| 209 | + -------- |
| 210 | + list: |
| 211 | + x-coordinate of rectangle's center |
| 212 | + y-coordinate of rectangle's center |
| 213 | +
|
| 214 | + """ |
| 215 | + rct = self.cell_rect(pos) |
| 216 | + return [rct[0]+rct[2]/2, rct[1] + rct[3]/2] |
| 217 | + |
| 218 | +def draw_board(surface, area, board): |
| 219 | + """ |
| 220 | +
|
| 221 | + This function takes board and draws it on surface. |
| 222 | + |
| 223 | + Parameters: |
| 224 | + ----------- |
| 225 | + surface (pygame.Surface): This parameter represents the surface on which the board will be drawn. |
| 226 | +
|
| 227 | + area (list): This parameter represents the area of the board. |
| 228 | +
|
| 229 | + board (my_maze.Board): This parameter represents the board. |
| 230 | +
|
| 231 | + Returns: |
| 232 | + -------- |
| 233 | + None |
| 234 | +
|
| 235 | + """ |
| 236 | + pygame.draw.rect(surface, (0, 0, 0), area) |
| 237 | + metrics = BoardMetrics(area, board) |
| 238 | + |
| 239 | + colors = { |
| 240 | + |
| 241 | + my_maze.CellType.Empty : (40, 40, 40), |
| 242 | + my_maze.CellType.Block : (128, 79, 179) |
| 243 | + } |
| 244 | + |
| 245 | + marks = { |
| 246 | + my_maze.CellMark.Start : (0, 204, 152), |
| 247 | + my_maze.CellMark.End : (153, 0, 102) |
| 248 | + } |
| 249 | + for iy in range(metrics.num_y): |
| 250 | + for ix in range(metrics.num_x): |
| 251 | + cell = board.at([ix, iy]) |
| 252 | + clr = colors.get(cell.type, (129, 100, 0)) |
| 253 | + cell_rect = metrics.cell_rect( [ix, iy] ) |
| 254 | + |
| 255 | + pygame.draw.rect(surface, clr, cell_rect) |
| 256 | + |
| 257 | + if cell.count != math.inf: |
| 258 | + number = cell_font.render( "{}".format(cell.count), True, (255,255,255)) |
| 259 | + surface.blit(number, trans_rect(number.get_rect(), |
| 260 | + [cell_rect[0] + (cell_rect[2] - number.get_rect()[2])/2, |
| 261 | + cell_rect[1] + (cell_rect[3] -number.get_rect()[3])/2] |
| 262 | + )) |
| 263 | + |
| 264 | + mark = marks.get(cell.mark, None) |
| 265 | + if mark != None: |
| 266 | + pygame.draw.rect(surface, mark, cell_rect, metrics.spacing) |
| 267 | + |
| 268 | + |
| 269 | +def draw_path(surface, area, board, path): |
| 270 | + """ |
| 271 | +
|
| 272 | + This function takes board and draws it on surface. |
| 273 | +
|
| 274 | + Parameters: |
| 275 | + ---------- |
| 276 | + surface (pygame.Surface): This parameter represents the surface on which the board will be drawn. |
| 277 | +
|
| 278 | + area (list): This parameter represents the area of the board. |
| 279 | +
|
| 280 | + board (my_maze.Board): This parameter represents the board. |
| 281 | +
|
| 282 | + path (list): This parameter represents the path. |
| 283 | +
|
| 284 | + Returns: |
| 285 | + -------- |
| 286 | + None |
| 287 | +
|
| 288 | + """ |
| 289 | + metrics = BoardMetrics(area, board) |
| 290 | + for i in range(len(path)-1): |
| 291 | + center_a = metrics.cell_center(path[i].pos) |
| 292 | + center_b = metrics.cell_center(path[i+1].pos) |
| 293 | + pygame.draw.line(surface, (1, 99, 148), center_a, center_b, metrics.spacing ) |
| 294 | + |
| 295 | + |
| 296 | + |
| 297 | + |
| 298 | + |
| 299 | + |
0 commit comments