Advertisement
Guest User

Untitled

a guest
Apr 5th, 2020
141
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.31 KB | None | 0 0
  1. from ipycanvas import Canvas, hold_canvas
  2. import numpy as np
  3.  
  4. # A maybe overkill class to store information about a square, its boundaries, and color index.
  5. class Square:
  6.     def __init__(self, U=False, L=False, D=False, R=False, row_seed=-1, col_seed=-1, color_index=0):
  7.         # Each square has Up, Left, Down, Right boundaries.
  8.         self.U, self.L, self.D, self.R = U, L, D, R
  9.         # Keep the row and col generating seed for debugging.
  10.         self.row_seed, self.col_seed = row_seed, col_seed
  11.         # A color value of consecutive squares found via BFS.
  12.         self.color_index = color_index
  13.    
  14.     def set_row_seed(self, row_seed):
  15.         self.row_seed = row_seed
  16.  
  17.     def set_col_seed(self, col_seed):
  18.         self.col_seed = col_seed
  19.  
  20.     def set_U(self, U):
  21.         self.U = 1 if U else 0
  22.        
  23.     def set_L(self, L):
  24.         self.L = 1 if L else 0
  25.  
  26.     def set_D(self, D):
  27.         self.D = 1 if D else 0
  28.        
  29.     def set_R(self, R):
  30.         self.R = 1 if R else 0
  31.  
  32.     def set_color_index(self, color_index):
  33.         self.color_index = color_index
  34.  
  35.     def get_row_seed(self):
  36.         return self.row_seed
  37.    
  38.     def get_col_seed(self):
  39.         return self.col_seed
  40.  
  41.     def get_U(self):
  42.         return 1 if self.U else 0
  43.  
  44.     def get_L(self):
  45.         return 1 if self.L else 0
  46.  
  47.     def get_D(self):
  48.         return 1 if self.D else 0
  49.  
  50.     def get_R(self):
  51.         return 1 if self.R else 0
  52.  
  53.     def get_color_index(self):
  54.         return self.color_index
  55.  
  56.     def draw_path(self, canvas, start, end):
  57.         canvas.begin_path()
  58.         canvas.move_to(*start)
  59.         canvas.line_to(*end)
  60.         canvas.stroke()
  61.         canvas.close_path()
  62.  
  63.     def draw_cell(self, canvas, row, col, fill_shapes, color_mode=""):
  64.         if fill_shapes:
  65.             # Random value [0, 256^3) that adjacent squares have after BFS runs.
  66.             c_index = self.get_color_index()
  67.  
  68.             if color_mode == "bw":
  69.                 r = c_index % 255
  70.                 g = c_index % 255
  71.                 b = c_index % 255
  72.             else:
  73.                 # By default use colors based on the random color_index value.
  74.                 r_mask = 0xFF
  75.                 g_mask = 0xFF00
  76.                 b_mask = 0xFF0000
  77.                 # color_index is a random value max 256^3~2^24 so we can safely apply RGB masks to it.
  78.                 r = c_index & r_mask
  79.                 g = (c_index & g_mask) >> 8
  80.                 b = (c_index & b_mask) >> 16
  81.  
  82.             canvas.fill_style = "rgb({}, {}, {})".format(r, g, b)
  83.             canvas.fill_rect(col * (W//N), row * (H//N), (W//N), (H//N))
  84.         else:
  85.             if self.get_U():
  86.                 start = [(col + 0) * (W//N), row * (H//N)]
  87.                 end   = [(col + 1) * (W//N), row * (H//N)]
  88.                 self.draw_path(canvas, start, end)
  89.             if self.get_L():
  90.                 start = [col * (W//N), (row + 0) * (H//N)]
  91.                 end   = [col * (W//N), (row + 1) * (H//N)]
  92.                 self.draw_path(canvas, start, end)
  93.             if self.get_D():
  94.                 start = [(col + 0) * (W//N), (row + 1) * (H//N)]
  95.                 end   = [(col + 1) * (W//N), (row + 1) * (H//N)]
  96.                 self.draw_path(canvas, start, end)
  97.             if self.get_R():
  98.                 start = [(col + 1) * (W//N), (row + 0) * (H//N)]
  99.                 end   = [(col + 1) * (W//N), (row + 1) * (H//N)]
  100.                 self.draw_path(canvas, start, end)
  101.  
  102.     def __repr__(self):
  103.         # Debug stuff hehe.
  104.         return "{}.{}.{}.{} ({})".format(self.get_U(), self.get_L(), self.get_D(), self.get_R(), self.get_color_index())
  105.  
  106. from collections import deque
  107.  
  108. def BFS(matrix, square, row, col):
  109.     queue = deque([[square, row, col]])
  110.     color_index = np.random.randint(256**3, size=1)[0]
  111.  
  112.     while len(queue) > 0:
  113.         cur_square, cur_row, cur_col = queue.popleft()
  114.         cur_square.set_color_index(color_index)
  115.         # Try to add neighbors of square to the queue unless a boundary exists between them.
  116.         neighbors = []
  117.         if cur_row > 0:
  118.             square_U = matrix[cur_row - 1][cur_col]
  119.             if square_U.get_color_index() == 0 and square_U.get_D() != 1:
  120.                 neighbors.append([square_U, cur_row - 1, cur_col])
  121.         if cur_row + 1 < len(matrix):
  122.             square_D = matrix[cur_row + 1][cur_col]
  123.             if square_D.get_color_index() == 0 and square_D.get_U() != 1:
  124.                 neighbors.append([square_D, cur_row + 1, cur_col])
  125.         if cur_col > 0:
  126.             square_L = matrix[cur_row][cur_col - 1]
  127.             if square_L.get_color_index() == 0 and square_L.get_R() != 1:
  128.                 neighbors.append([square_L, cur_row, cur_col - 1])
  129.         if cur_col + 1 < len(matrix[0]):
  130.             square_R = matrix[cur_row][cur_col + 1]
  131.             if square_R.get_color_index() == 0 and square_R.get_L() != 1:
  132.                 neighbors.append([square_R, cur_row, cur_col + 1])
  133.         queue = queue + deque(neighbors)
  134.        
  135. # Width and Height of the original quadrant.
  136. W, H = 600, 600
  137. # Number of desired cells in a quadrant. Because the first quadrant will be mirrored in 4
  138. # directions, then the real amount of cells per axis will be twice as much this.
  139. N = 60
  140.  
  141. # A matrix to store the original quadrant. The other ones will be generated by
  142. # mirroring this quadrant.
  143. matrix = [[Square() for _ in range(N)] for _ in range(N)]
  144.  
  145. # Canvas has twice the width and height of the original quadrant to be able to fit
  146. # 4 versions of this quadrant but flipped around.
  147. canvas = Canvas(width=W*2, height=H*2, sync_image_data=True)
  148. canvas.scale(1)
  149. canvas.line_width = 1
  150. canvas.stroke_style = 'black'
  151.  
  152.  
  153. # Rows iterator
  154. for i in range(N):
  155.     # For each row generate a random value 0 or 1.
  156.     row_seed = np.random.randint(2, size=1)[0]
  157.  
  158.     # Now for each cell, go horizontally and set the Down boundary to True either in
  159.     # odd or even positions.
  160.     for j in range(N):
  161.         square = matrix[i][j]
  162.  
  163.         square.set_row_seed(row_seed)
  164.         if j % 2 == 0:
  165.             square.set_D(row_seed == 0)
  166.         else:
  167.             square.set_D(row_seed == 1)
  168.  
  169.  
  170. # Columns iterator
  171. for j in range(N):
  172.     # For each col generate a random value 0 or 1.
  173.     col_seed = np.random.randint(2, size=1)[0]
  174.    
  175.     # Now for each cell, go vertically and set the Right boundary to True either in
  176.     # odd or even positions.
  177.     for i in range(N):
  178.         square = matrix[i][j]
  179.  
  180.         square.set_col_seed(col_seed)
  181.         if i % 2 == 0:
  182.             square.set_R(col_seed == 0)
  183.         else:
  184.             square.set_R(col_seed == 1)
  185.  
  186. for row in range(len(matrix)):
  187.     for col in range(len(matrix[0])):
  188.         square = matrix[row][col]
  189.         if row > 0:
  190.             square_U = matrix[row - 1][col]
  191.             square.set_U(any([square.get_U(), square_U.get_D()]))
  192.             square_U.set_D(any([square.get_U(), square_U.get_D()]))
  193.         if row + 1 < len(matrix):
  194.             square_D = matrix[row + 1][col]
  195.             square.set_D(any([square.get_D(), square_D.get_U()]))
  196.             square_D.set_U(any([square.get_D(), square_D.get_U()]))
  197.         if col > 0:
  198.             square_L = matrix[row][col - 1]
  199.             square.set_L(any([square.get_L(), square_L.get_R()]))
  200.             square_L.set_R(any([square.get_L(), square_L.get_R()]))
  201.         if col + 1 < len(matrix[0]):
  202.             square_R = matrix[row][col + 1]
  203.             square.set_R(any([square.get_R(), square_R.get_L()]))
  204.             square_R.set_L(any([square.get_R(), square_R.get_L()]))
  205.  
  206. for row in range(len(matrix)):
  207.     for col in range(len(matrix[0])):
  208.         square = matrix[row][col]
  209.         if square.get_color_index() == 0:
  210.             BFS(matrix, square, row, col)
  211.  
  212. # Now mirror horizontally the original matrix.
  213. new_matrix_1 = []
  214. for row in range(len(matrix)):
  215.     old_row = matrix[row]
  216.     new_row = []
  217.     for col in range(len(matrix[0])):
  218.         square = matrix[row][col]
  219.         new_square = Square(
  220.             # Flip the order of passing the L/R boundary values.
  221.             square.get_U(), square.get_R(), square.get_D(), square.get_L(),
  222.             square.get_row_seed(), square.get_col_seed(), square.get_color_index()
  223.         )
  224.         new_row.append(new_square)
  225.     new_matrix_1.append(old_row + new_row[::-1])
  226.  
  227. # Now mirror vertically the previous matrix.
  228. new_matrix_2 = []
  229. for row in range(len(new_matrix_1)):
  230.     new_row = []
  231.     for col in range(len(new_matrix_1[0])):
  232.         square = new_matrix_1[row][col]
  233.         new_square = Square(
  234.             # Flip the order of passing the U/D boundary values.
  235.             square.get_D(), square.get_L(), square.get_U(), square.get_R(),
  236.             square.get_row_seed(), square.get_col_seed(), square.get_color_index()
  237.         )
  238.         new_row.append(new_square)
  239.     new_matrix_2.append(new_row)
  240.  
  241. final_matrix = new_matrix_1 + new_matrix_2[::-1]
  242.  
  243.  
  244. # All this about boundaries and squares is so that we are able to do a BFS
  245. # to paint them with a given color :-)
  246. with hold_canvas(canvas):
  247.     # Change this before running to alternate between outlines drawing and filling shapes.
  248.     fill_shapes = True
  249.     for row in range(len(final_matrix)):
  250.         for col in range(len(final_matrix[0])):
  251.             item = final_matrix[row][col]
  252.             item.draw_cell(canvas, row, col, fill_shapes)
  253.  
  254. hold_canvas(canvas)
  255. canvas
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement