def next_shape(self, shape=None): self.pressed_x_speed = config.block_size self.pressed_y_speed = 0 if shape is None: self.shape_key = random.choices(list(self.dict_shapes.keys()), weights=list( self.weights.values()))[0] self.n_positions = len(self.dict_shapes[self.shape_key]) self.position = random.randint(0, self.n_positions - 1) else: # Copy the shape key and position from input Shape instance self.shape_key = copy(shape.shape_key) self.n_positions = copy(shape.n_positions) self.position = copy(shape.position) # Initial (x, y) position self.x = config.game_boundaries[0] + (config.ncols // 2 - 1) * config.block_size self.y = -(len(self.dict_shapes[self.shape_key][self.position]) * config.block_size) # Color self.shape_color = ColorEffect(shape_colors[self.shape_key], interval=45, length=10) self.get_shape() self.move = True
def next_shape(self, shape=None): self.pressed_x_speed = config.block_size self.pressed_y_speed = 0 if shape is None: self.shape_key = random.choice(list(self.dict_shapes.keys())) self.n_positions = len(self.dict_shapes[self.shape_key]) self.position = random.randint(0, self.n_positions - 1) else: # Копіювання ключа форми та положення з екземпляра вхідної форми self.shape_key = copy(shape.shape_key) self.n_positions = copy(shape.n_positions) self.position = copy(shape.position) # Початкове (x, y) положення self.x = config.game_boundaries[0] + (config.ncols // 2 - 1) * config.block_size self.y = -(len(self.dict_shapes[self.shape_key][self.position]) * config.block_size) # Колір self.shape_color = ColorEffect(shape_colors[self.shape_key], interval=45, length=10) self.get_shape() self.move = True
class Shapes: # / ----------------------------------------------------------------------- \ def __init__(self): # Dropped blocks self.dropped = [] self.dropped_index = [] self.dropped_colors = [] # Eresed blocks self.eresed = [] self.eresed_colors = [] if config.big_shapes: self.dict_shapes = {**dict_shapes, **dict_big_shapes} self.weights = {**weights, **weights_big_shapes} else: self.dict_shapes = dict_shapes self.weights = weights # / ----------------------------------------------------------------------- \ def restart(self): self.dropped = [] self.dropped_index = [] self.dropped_colors = [] self.eresed = [] self.eresed_colors = [] if config.big_shapes: self.dict_shapes = {**dict_shapes, **dict_big_shapes} self.weights = {**weights, **weights_big_shapes} else: self.dict_shapes = dict_shapes self.weights = weights # / ----------------------------------------------------------------------- \ def next_shape(self, shape=None): self.pressed_x_speed = config.block_size self.pressed_y_speed = 0 if shape is None: self.shape_key = random.choices(list(self.dict_shapes.keys()), weights=list( self.weights.values()))[0] self.n_positions = len(self.dict_shapes[self.shape_key]) self.position = random.randint(0, self.n_positions - 1) else: # Copy the shape key and position from input Shape instance self.shape_key = copy(shape.shape_key) self.n_positions = copy(shape.n_positions) self.position = copy(shape.position) # Initial (x, y) position self.x = config.game_boundaries[0] + (config.ncols // 2 - 1) * config.block_size self.y = -(len(self.dict_shapes[self.shape_key][self.position]) * config.block_size) # Color self.shape_color = ColorEffect(shape_colors[self.shape_key], interval=45, length=10) self.get_shape() self.move = True # / ----------------------------------------------------------------------- \ def get_shape(self): # self.shape is a list of pg.Rect self.shape = [] for i, row in enumerate( self.dict_shapes[self.shape_key][self.position]): for j, column in enumerate(row): if column == '0': x = self.x + config.block_size * j y = self.y + config.block_size * i rect = pg.Rect(x, y, config.block_size, config.block_size) self.shape.append(rect) self.shape_corners = self.get_shape_corners() self.center = self.get_shape_center() # / ----------------------------------------------------------------------- \ def get_shape_corners(self): xs = [rect[0] for rect in self.shape] ys = [rect[1] for rect in self.shape] xmin = min(xs) ymin = min(ys) xmax = max(xs) + config.block_size ymax = max(ys) + config.block_size self.shape_corners = [xmin, ymin, xmax, ymax] return self.shape_corners # / ----------------------------------------------------------------------- \ def get_shape_center(self): cx = self.shape_corners[0] + (self.shape_corners[2] - self.shape_corners[0]) / 2 cy = self.shape_corners[1] + (self.shape_corners[3] - self.shape_corners[1]) / 2 self.center = [cx, cy] return self.center # / ----------------------------------------------------------------------- \ def get_index(self, x, y): # Get row and column index when shape can't move down' row = int((y - config.game_boundaries[1]) / config.block_size) col = int((x - config.game_boundaries[0]) / config.block_size) return row, col # / ----------------------------------------------------------------------- \ def difference(self, bound, current_shape_bound, direction='bottom'): diff = 0 if direction == 'left': if current_shape_bound < bound: diff = bound - current_shape_bound elif direction == 'right': if current_shape_bound > bound: diff = bound - current_shape_bound elif direction == 'bottom': if current_shape_bound > bound: diff = bound - current_shape_bound return diff # / ----------------------------------------------------------------------- \ def move_down(self, pressed_y=None): self.move = True if pressed_y is not None: if pressed_y: self.pressed_y_speed = 10 else: self.pressed_y_speed = 0 y_move = config.speed + self.pressed_y_speed self.move_shape(0, y_move) # See if next position is filled: if self.dropped and self.shape_key != 'DOT': for rect1 in self.dropped: for rect2 in self.shape: if rect1.colliderect(rect2): diff = self.difference(rect1.top, rect2.bottom, 'bottom') self.move_shape(0, diff) self.move = False return self.move # See if shape is out the bottom boundarie diff = self.difference(config.game_boundaries[3], self.shape_corners[3], 'bottom') if diff != 0: self.move_shape(0, diff) self.move = False return self.move return self.move # / ----------------------------------------------------------------------- \ def move_left(self): self.move_shape(-self.pressed_x_speed, 0) # See if shape is out of left boundarie diff = self.difference(config.game_boundaries[0], self.shape_corners[0], 'left') if diff != 0: self.move_shape(diff, 0) # See if next position is filled: if self.dropped and self.shape_key != 'DOT': for rect1 in self.dropped: for rect2 in self.shape: if rect1.colliderect(rect2): diff = self.difference(rect1.right, rect2.left, 'left') self.move_shape(diff, 0) return None # / ----------------------------------------------------------------------- \ def move_right(self): # See if shape is out of right boundarie self.move_shape(self.pressed_x_speed, 0) diff = self.difference(config.game_boundaries[2], self.shape_corners[2], 'right') if diff != 0: self.move_shape(diff, 0) # See if next position is filled: if self.dropped and self.shape_key != 'DOT': for rect1 in self.dropped: for rect2 in self.shape: if rect1.colliderect(rect2): diff = self.difference(rect1.left, rect2.right, 'right') self.move_shape(diff, 0) return None # / ----------------------------------------------------------------------- \ def move_shape(self, x, y): self.x += x self.y += y self.shape = [rect.move(x, y) for rect in self.shape] self.shape_corners = self.get_shape_corners() self.center = self.get_shape_center() # / ----------------------------------------------------------------------- \ def rotate(self): # Change position self.position += 1 if self.position >= self.n_positions: self.position = 0 # Update the shape to the new position self.get_shape() # If rotated shape is out of bounds diff_left = self.difference(config.game_boundaries[0], self.shape_corners[0], 'left') if diff_left != 0: self.move_shape(diff_left, 0) diff_right = self.difference(config.game_boundaries[2], self.shape_corners[2], 'right') if diff_right != 0: self.move_shape(diff_right, 0) # If rotated shape colaps with any block if self.dropped: if any( rect1.colliderect(rect2) for rect1 in self.shape for rect2 in self.dropped): self.position -= 1 if self.position < 0: self.position = self.n_positions - 1 self.get_shape() if diff_left != 0: self.move_shape(-diff_left, 0) if diff_right != 0: self.move_shape(-diff_right, 0) # / ----------------------------------------------------------------------- \ def update_filled_spaces(self): # Append current shape to the dropped shapes for rect in self.shape: row, col = self.get_index(rect.left, rect.top) self.dropped.append(rect) self.dropped_index.append([row, col]) self.dropped_colors.append(self.shape_color) # / ----------------------------------------------------------------------- \ def erese_blocks(self): n_eresed = 0 # Remove blocks when the row is fiilled if self.dropped and self.shape_key != 'DOT': # Get the IDs for the filled rows indexes_removed = [] removed_rows = [] for row in range(config.nrows)[::-1]: cols_filled = [ i for i, idx in enumerate(self.dropped_index) if idx[0] == row ] if len(cols_filled) == config.ncols: removed_rows.append(row) indexes_removed.extend(cols_filled) if removed_rows: # Get the blocks that most be removed self.eresed = [self.dropped[i] for i in indexes_removed] self.eresed_colors = [ self.dropped_colors[i] for i in indexes_removed ] # Remove the blocks indexes = [ i for i in range(len(self.dropped_index)) if i not in indexes_removed ] self.dropped = [self.dropped[i] for i in indexes] self.dropped_index = [self.dropped_index[i] for i in indexes] self.dropped_colors = [self.dropped_colors[i] for i in indexes] # See which blocks must be move down to_update = [] for i, row in enumerate(removed_rows): for j, rect in enumerate(self.dropped): if self.dropped_index[j][0] < row: to_update.append(j) # Move down the blocks for index in to_update: self.dropped[index] = self.dropped[index].move( 0, config.block_size) self.dropped_index[index][0] += 1 n_eresed = len(self.eresed) if self.shape_key == 'DOT' and not self.move: # Remove the blocks by column row, col = self.dropped_index[-1] rows_filled = [ i for i, idx in enumerate(self.dropped_index) if idx[1] == col ] indexes = [ i for i, idx in enumerate(self.dropped_index) if idx[1] != col ] self.eresed = [self.dropped[idx] for idx in rows_filled] self.eresed_colors = [ self.dropped_colors[idx] for idx in rows_filled ] self.dropped = [self.dropped[idx] for idx in indexes] self.dropped_index = [self.dropped_index[idx] for idx in indexes] self.dropped_colors = [self.dropped_colors[idx] for idx in indexes] n_eresed = len(self.eresed) return n_eresed # / ----------------------------------------------------------------------- \ def draw_eresed(self, screen): for i, rect, in enumerate(self.eresed): color = self.eresed_colors[i].change_color() color = self.eresed_colors[i].modify_color(color, l=-20) pg.draw.rect(screen, color, rect) pg.draw.rect(screen, colors['white'], rect, 1) self.eresed = [] self.eresed_colors = [] pg.display.update() pg.time.wait(350) # / ----------------------------------------------------------------------- \ def draw_shape(self, screen): color = self.shape_color.change_color() for rect in self.shape: if rect.bottom > config.game_boundaries[1]: pg.draw.rect(screen, color, rect) pg.draw.rect(screen, colors['white'], rect, 1) # / ----------------------------------------------------------------------- \ def draw_filled(self, screen): if self.dropped: for i, rect in enumerate(self.dropped): color = self.dropped_colors[i].change_color() pg.draw.rect(screen, color, rect) pg.draw.rect(screen, colors['white'], rect, 1) # / ----------------------------------------------------------------------- \ def draw_next_shape(self, x, y, screen): dx = x - self.center[0] dy = y - self.center[1] self.move_shape(dx, dy) color = self.shape_color.change_color() for rect in self.shape: pg.draw.rect(screen, color, rect) pg.draw.rect(screen, colors['white'], rect, 1) # / ----------------------------------------------------------------------- \ # / -------------------------------------------------------------------------- \ # / --------------------------------------------------- \ # / -------------------------------- \ # / ------------- \ # / END
import os import string import pygame as pg from shapes import Shapes from config import config from score import Score from color import colors, ColorEffect score = Score() shape = Shapes() next_shape = Shapes() color_effect = ColorEffect(length=15) class Relationship(): def Button(self): pass class Button: def __init__(self, key, function, draw_on): self.key = key # Положення та розміри кнопки self.x = config.buttons_size[self.key]['x'] self.y = config.buttons_size[self.key]['y'] self.w = config.buttons_size[self.key]['w'] self.h = config.buttons_size[self.key]['h']
class Shapes: # / ----------------------------------------------------------------------- \ def __init__(self): # блоки, які випали self.dropped = [] self.dropped_index = [] self.dropped_colors = [] # Стерті блоки self.eresed = [] self.eresed_colors = [] self.dict_shapes = dict_shapes self.weights = weights # / ----------------------------------------------------------------------- \ def restart(self): self.dropped = [] self.dropped_index = [] self.dropped_colors = [] self.eresed = [] self.eresed_colors = [] self.dict_shapes = dict_shapes self.weights = weights # / ----------------------------------------------------------------------- \ def next_shape(self, shape=None): self.pressed_x_speed = config.block_size self.pressed_y_speed = 0 if shape is None: self.shape_key = random.choice(list(self.dict_shapes.keys())) self.n_positions = len(self.dict_shapes[self.shape_key]) self.position = random.randint(0, self.n_positions - 1) else: # Копіювання ключа форми та положення з екземпляра вхідної форми self.shape_key = copy(shape.shape_key) self.n_positions = copy(shape.n_positions) self.position = copy(shape.position) # Початкове (x, y) положення self.x = config.game_boundaries[0] + (config.ncols // 2 - 1) * config.block_size self.y = -(len(self.dict_shapes[self.shape_key][self.position]) * config.block_size) # Колір self.shape_color = ColorEffect(shape_colors[self.shape_key], interval=45, length=10) self.get_shape() self.move = True # / ----------------------------------------------------------------------- \ def get_shape(self): # self.shape - це список pg.Rect self.shape = [] for i, row in enumerate( self.dict_shapes[self.shape_key][self.position]): for j, column in enumerate(row): if column == '0': x = self.x + config.block_size * j y = self.y + config.block_size * i rect = pg.Rect(x, y, config.block_size, config.block_size) self.shape.append(rect) self.shape_corners = self.get_shape_corners() self.center = self.get_shape_center() # / ----------------------------------------------------------------------- \ def get_shape_corners(self): xs = [rect[0] for rect in self.shape] ys = [rect[1] for rect in self.shape] xmin = min(xs) ymin = min(ys) xmax = max(xs) + config.block_size ymax = max(ys) + config.block_size self.shape_corners = [xmin, ymin, xmax, ymax] return self.shape_corners # / ----------------------------------------------------------------------- \ def get_shape_center(self): cx = self.shape_corners[0] + (self.shape_corners[2] - self.shape_corners[0]) / 2 cy = self.shape_corners[1] + (self.shape_corners[3] - self.shape_corners[1]) / 2 self.center = [cx, cy] return self.center # / ----------------------------------------------------------------------- \ def get_index(self, x, y): # Отримання індекса рядків і стовпців, коли форма не може рухатися вниз " row = int((y - config.game_boundaries[1]) / config.block_size) col = int((x - config.game_boundaries[0]) / config.block_size) return row, col # / ----------------------------------------------------------------------- \ def difference(self, bound, current_shape_bound, direction='bottom'): diff = 0 if direction == 'left': if current_shape_bound < bound: diff = bound - current_shape_bound elif direction == 'right': if current_shape_bound > bound: diff = bound - current_shape_bound elif direction == 'bottom': if current_shape_bound > bound: diff = bound - current_shape_bound return diff # / ----------------------------------------------------------------------- \ def move_down(self, pressed_y=None): self.move = True if pressed_y is not None: if pressed_y: self.pressed_y_speed = 10 else: self.pressed_y_speed = 0 y_move = config.speed + self.pressed_y_speed self.move_shape(0, y_move) # Перевірка на заповненість if self.dropped: for rect1 in self.dropped: for rect2 in self.shape: if rect1.colliderect(rect2): try: diff = self.difference(rect1.top, rect2.bottom, 'bottom') self.move_shape(0, diff) self.move = False return self.move except Exception as value: print("Щось пішло не так :(") # Перевірка, чи форма є поза нижньою межею diff = self.difference(config.game_boundaries[3], self.shape_corners[3], 'bottom') if diff != 0: try: self.move_shape(0, diff) self.move = False return self.move except Exception as value: print("Щось пішло не так :(") return self.move # / ----------------------------------------------------------------------- \ def move_left(self): self.move_shape(-self.pressed_x_speed, 0) # Перевірка, чи форма є поза лівою межею diff = self.difference(config.game_boundaries[0], self.shape_corners[0], 'left') if diff != 0: try: self.move_shape(diff, 0) except Exception as value: print("Щось пішло не так :(") # Перевірка на заповненість if self.dropped: for rect1 in self.dropped: for rect2 in self.shape: if rect1.colliderect(rect2): try: diff = self.difference(rect1.right, rect2.left, 'left') self.move_shape(diff, 0) return None except Exception as value: print("Щось пішло не так :(") # / ----------------------------------------------------------------------- \ def move_right(self): # Перевірка, чи форма є поза правою межею self.move_shape(self.pressed_x_speed, 0) diff = self.difference(config.game_boundaries[2], self.shape_corners[2], 'right') if diff != 0: try: self.move_shape(diff, 0) except Exception as value: print("Щось пішло не так :(") # Перевірка на заповненість if self.dropped: for rect1 in self.dropped: for rect2 in self.shape: if rect1.colliderect(rect2): try: diff = self.difference(rect1.left, rect2.right, 'right') self.move_shape(diff, 0) return None except Exception as value: print("Щось пішло не так :(") # / ----------------------------------------------------------------------- \ def move_shape(self, x, y): self.x += x self.y += y self.shape = [rect.move(x, y) for rect in self.shape] self.shape_corners = self.get_shape_corners() self.center = self.get_shape_center() # / ----------------------------------------------------------------------- \ def rotate(self): # Змінення позиції self.position += 1 if self.position >= self.n_positions: self.position = 0 # Оновлення фігури до нової позиції self.get_shape() # Перевірка, чи обернена форма є поза межею diff_left = self.difference(config.game_boundaries[0], self.shape_corners[0], 'left') if diff_left != 0: self.move_shape(diff_left, 0) diff_right = self.difference(config.game_boundaries[2], self.shape_corners[2], 'right') if diff_right != 0: self.move_shape(diff_right, 0) # Перевірка чи обернена фігура ні з чим не перетинається if self.dropped: if any( rect1.colliderect(rect2) for rect1 in self.shape for rect2 in self.dropped): self.position -= 1 if self.position < 0: self.position = self.n_positions - 1 self.get_shape() if diff_left != 0: self.move_shape(-diff_left, 0) if diff_right != 0: self.move_shape(-diff_right, 0) # / ----------------------------------------------------------------------- \ def update_filled_spaces(self): # Додавання поточної форми до викинутих фігур for rect in self.shape: row, col = self.get_index(rect.left, rect.top) self.dropped.append(rect) self.dropped_index.append([row, col]) self.dropped_colors.append(self.shape_color) # / ----------------------------------------------------------------------- \ def erese_blocks(self): n_eresed = 0 # Видалення блоків, коли рядок заповнений if self.dropped: # Отримання ід заповнених рядків indexes_removed = [] removed_rows = [] for row in range(config.nrows)[::-1]: cols_filled = [ i for i, idx in enumerate(self.dropped_index) if idx[0] == row ] if len(cols_filled) == config.ncols: removed_rows.append(row) indexes_removed.extend(cols_filled) if removed_rows: # Отримання блоків, які найбільше видаляються self.eresed = [self.dropped[i] for i in indexes_removed] self.eresed_colors = [ self.dropped_colors[i] for i in indexes_removed ] # Видалення блоків indexes = [ i for i in range(len(self.dropped_index)) if i not in indexes_removed ] self.dropped = [self.dropped[i] for i in indexes] self.dropped_index = [self.dropped_index[i] for i in indexes] self.dropped_colors = [self.dropped_colors[i] for i in indexes] # Перегляд, які блоки потрібно рухати вниз to_update = [] for i, row in enumerate(removed_rows): for j, rect in enumerate(self.dropped): if self.dropped_index[j][0] < row: to_update.append(j) # Рух блоків вниз for index in to_update: self.dropped[index] = self.dropped[index].move( 0, config.block_size) self.dropped_index[index][0] += 1 n_eresed = len(self.eresed) return n_eresed # / ----------------------------------------------------------------------- \ def draw_eresed(self, screen): for i, rect, in enumerate(self.eresed): color = self.eresed_colors[i].change_color() color = self.eresed_colors[i].modify_color(color, l=-20) pg.draw.rect(screen, color, rect) pg.draw.rect(screen, colors['white'], rect, 1) self.eresed = [] self.eresed_colors = [] pg.display.update() pg.time.wait(350) # / ----------------------------------------------------------------------- \ def draw_shape(self, screen): color = self.shape_color.change_color() for rect in self.shape: if rect.bottom > config.game_boundaries[1]: pg.draw.rect(screen, color, rect) pg.draw.rect(screen, colors['white'], rect, 1) # / ----------------------------------------------------------------------- \ def draw_filled(self, screen): if self.dropped: for i, rect in enumerate(self.dropped): color = self.dropped_colors[i].change_color() pg.draw.rect(screen, color, rect) pg.draw.rect(screen, colors['white'], rect, 1) def draw_next_shape(self, x, y, screen): dx = x - self.center[0] dy = y - self.center[1] self.move_shape(dx, dy) color = self.shape_color.change_color() for rect in self.shape: pg.draw.rect(screen, color, rect) pg.draw.rect(screen, colors['white'], rect, 1)