Toggle Navigation
Hatchery
Eggs
Tetris-CZ19
__init__.py
Users
Badges
Login
Register
MCH2022 badge?
go to mch2022.badge.team
__init__.py
raw
Content
import time import urandom import rgb # Basic implementation of tetris, adapted to CZ19 badge print("V0.5") class Tetris: def __init__(self): defs = Defs() rgb.clear() self.font = "fixed_10x20" self.board_height = 8 self.board_width = 32 self.board_rotated = True self.board_color_background = defs.gray self.game_default_step_time = 500 self.game_step_time = self.game_default_step_time self.game_step_speed_increase = 10 self.game_width = 8 self.game_height = self.board_width - 5 # self.game_height = 10 # self.game_color_piece = defs.white self.game_color_filledline = defs.blue self.game_color_background = defs.black self.game_color_piece = [ defs.white, defs.blue, defs.red, defs.yellow, defs.green, defs.purple, defs.cyan ] # self.game_linecolor = defs.white self.frame = [] for i in range(256): self.frame+=[0] # nr of unique rotations per piece self.piece_rotations = [1, 2, 2, 2, 4, 4, 4] # Piece data: [piece_nr * 32 + rot_nr * 8 + brick_nr * 2 + j] # with rot_nr between 0 and 4 # with the brick number between 0 and 4 # and j == 0 for X coord, j == 1 for Y coord self.piece_data = [ # pixel block 0, 0, -1, 0, -1, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # line block 0, 0, -2, 0, -1, 0, 1, 0, 0, 0, 0, 1, 0, -1, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # S-block 0, 0, -1, -1, 0, -1, 1, 0, 0, 0, 0, 1, 1, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # Z-block 0, 0, -1, 0, 0, -1, 1, -1, 0, 0, 1, 1, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # L-block 0, 0, -1, 0, -1, -1, 1, 0, 0, 0, 0, 1, 0, -1, 1, -1, 0, 0, -1, 0, 1, 0, 1, 1, 0, 0, -1, 1, 0, 1, 0, -1, # J-block 0, 0, -1, 0, 1, 0, 1, -1, 0, 0, 0, 1, 0, -1, 1, 1, 0, 0, -1, 1, -1, 0, 1, 0, 0, 0, 0, 1, 0, -1, -1, -1, # T-block 0, 0, -1, 0, 0, -1, 1, 0, 0, 0, 0, 1, 0, -1, 1, 0, 0, 0, -1, 0, 0, 1, 1, 0, 0, 0, -1, 0, 0, 1, 0, -1 ] self.draw_field_lines() import buttons, defines # Controls are rotated to the left # UP button = left # DOWN button = right # RIGHT button = down # LEFT button = up def btn_a(button_is_down): if button_is_down: self.rotate_piece() pass def btn_up(button_is_down): if button_is_down: if self.board_rotated: self.move_left() else: self.move_right() pass def btn_down(button_is_down): if button_is_down: if self.board_rotated: self.move_right() else: self.move_left() pass def btn_right(button_is_down): if button_is_down: if self.board_rotated: self.rotate_piece() else: self.lower_piece() pass def btn_left(button_is_down): if button_is_down: if self.board_rotated: self.lower_piece() else: self.rotate_piece() pass buttons.register(defines.BTN_A, btn_a) buttons.register(defines.BTN_UP, btn_up) buttons.register(defines.BTN_DOWN, btn_down) buttons.register(defines.BTN_LEFT, btn_left) buttons.register(defines.BTN_RIGHT, btn_right) self.game_init() self.draw_updated_score() while True: time.sleep(.01) self.game_update() # self.draw() def game_init(self): # Init game state self.game_step_time = self.game_default_step_time urandom.seed(time.ticks_ms()) self.piece_next = urandom.getrandbits(8) % 7 rgb.clear rgb.disablecomp() for i in range(256): self.frame[i]=0 self.spawn_new_piece() self.field = [[0 for i in range(self.game_width)] for j in range(self.game_height)] self.last_update = time.ticks_ms() self.score = 0 def spawn_new_piece(self): self.piece_current = self.piece_next urandom.seed(time.ticks_ms()) self.piece_next = urandom.getrandbits(8) % 7 # self.piece_current = 1 self.piece_x = 4 self.piece_y = 0 self.piece_rot = 0 # print("Piece:",self.piece_current) def game_update(self): cur_ticks = time.ticks_ms() if cur_ticks - self.last_update > self.game_step_time: # Move piece down self.lower_piece() self.last_update = cur_ticks def rotate_piece(self): self.piece_rot += 1 if self.piece_rot >= self.piece_rotations[self.piece_current]: self.piece_rot = 0 if self.is_right_collision(): self.piece_x -= 1 if self.is_left_collision(): self.piece_x += 1 # line piece needs additional step to the right: if (self.piece_current == 1) and (self.piece_x == 1): self.piece_x += 1 self.draw() def is_side_collision(self): for pixel in range(4): x_off = self.piece_data[self.piece_current * 32 + self.piece_rot * 8 + pixel * 2 + 0] y_off = self.piece_data[self.piece_current * 32 + self.piece_rot * 8 + pixel * 2 + 1] abs_x = self.piece_x + x_off abs_y = self.piece_y + y_off # collision with walls if abs_x < 0 or abs_x > self.game_width-1: return True # collision with field blocks if self.field[abs_y][abs_x]: return True return False def is_left_collision(self): for pixel in range(4): x_off = self.piece_data[self.piece_current * 32 + self.piece_rot * 8 + pixel * 2 + 0] y_off = self.piece_data[self.piece_current * 32 + self.piece_rot * 8 + pixel * 2 + 1] abs_x = self.piece_x + x_off abs_y = self.piece_y + y_off # collision with walls if abs_x < 0: return True # collision with field blocks if self.field[abs_y][abs_x]: return True return False def is_right_collision(self): for pixel in range(4): x_off = self.piece_data[self.piece_current * 32 + self.piece_rot * 8 + pixel * 2 + 0] y_off = self.piece_data[self.piece_current * 32 + self.piece_rot * 8 + pixel * 2 + 1] abs_x = self.piece_x + x_off abs_y = self.piece_y + y_off # collision with walls if abs_x > self.game_width-1: return True # collision with field blocks if self.field[abs_y][abs_x]: return True return False def move_left(self): self.piece_x -= 1 # check collision with walls if self.is_side_collision(): self.piece_x += 1 self.draw() def move_right(self): self.piece_x += 1 # check collision with walls if self.is_side_collision(): self.piece_x -= 1 self.draw() def lower_piece(self): self.piece_y += 1 # check for collisions collision = False for pixel in range(4): x_off = self.piece_data[self.piece_current * 32 + self.piece_rot * 8 + pixel * 2 + 0] y_off = self.piece_data[self.piece_current * 32 + self.piece_rot * 8 + pixel * 2 + 1] abs_x = self.piece_x + x_off abs_y = self.piece_y + y_off if abs_y > self.game_height-1 or self.field[abs_y][abs_x]: collision = True break if collision: # if at the top, game over if self.piece_y == 1: self.draw_game_over() time.sleep(10) self.game_init() return # add to field self.piece_y -= 1 for pixel in range(4): x_off = self.piece_data[self.piece_current * 32 + self.piece_rot * 8 + pixel * 2 + 0] y_off = self.piece_data[self.piece_current * 32 + self.piece_rot * 8 + pixel * 2 + 1] abs_x = self.piece_x + x_off abs_y = self.piece_y + y_off self.field[abs_y][abs_x] = True # check for line clears self.check_for_filled_lines() # Spawn new piece self.spawn_new_piece() self.draw() def check_for_filled_lines(self): for row in range(self.game_height): fill_count = 0 for column in range(self.game_width): fill_count += self.field[row][column] if fill_count == self.game_width: # Increase score self.score += 10 self.draw_updated_score() # Remove line self.remove_line(row) def remove_line(self,row): for col in range(self.game_width): self.draw_pixel(row,col,self.game_color_filledline) rgb.frame(self.frame) time.sleep(.5) for col in range(self.game_width): self.draw_pixel(row,col,self.game_color_background) rgb.frame(self.frame) time.sleep(.25) for row2 in range(row, 0, -1): for col in range(self.game_width): self.field[row2][col] = self.field[row2-1][col] if self.game_step_time > 50: self.game_step_time = self.game_step_time - self.game_step_speed_increase def draw(self): self.draw_field() self.draw_piece_current() self.draw_piece_next() rgb.frame(self.frame) def draw_updated_score(self): print("updated score") # draw box, draw score ##ugfx.area(10, 112, 102, 132, ugfx.WHITE) ##ugfx.string(10, 110, "Score: {:04d}".format(self.score), self.font, ugfx.BLACK) # TODO def draw_game_over(self): rgb.enablecomp() rgb.clear() rgb.scrolltext("game over") ##ugfx.clear(ugfx.WHITE) ##ugfx.string(70, 50, "GAME OVER :(", "PermanentMarker22", ugfx.BLACK) ##ugfx.flush() def draw_field_lines(self): print("field lines") #ugfx.box(10,10,200,100,ugfx.BLACK) # Draw grid #for column in range(10): # ugfx.line(10, 10 + 10 * column, 200, 10 + 10 * column, ugfx.BLACK) #for row in range(20): # ugfx.line(10 + 10 * row, 10, 10 + 10 * row, 100, ugfx.BLACK) # pass # Outline ##ugfx.box(9,9,202,102,ugfx.BLACK) def draw_field(self): for row in range(self.game_height): for column in range(self.game_width): color = self.game_color_piece[0] if self.field[row][column] else self.game_color_background self.draw_pixel(row, column, color) for row in range(self.game_height,self.board_width): for column in range(self.game_width): color = self.board_color_background self.draw_pixel(row, column, color) def draw_piece_current(self): for pixel in range(4): # [piece_nr * 32 + rot_nr * 8 + brick_nr * 2 + j] x_off = self.piece_data[self.piece_current * 32 + self.piece_rot * 8 + pixel * 2 + 0] y_off = self.piece_data[self.piece_current * 32 + self.piece_rot * 8 + pixel * 2 + 1] abs_x = self.piece_x + x_off abs_y = self.piece_y + y_off self.draw_pixel(abs_y, abs_x, self.game_color_piece[self.piece_current]) def draw_piece_next(self): for pixel in range(4): # [piece_nr * 32 + rot_nr * 8 + brick_nr * 2 + j] # skipping rotation, because is always 0 on next piece x_off = self.piece_data[self.piece_next * 32 + pixel * 2 + 0] y_off = self.piece_data[self.piece_next * 32 + pixel * 2 + 1] abs_x = 1 + x_off abs_y = 1 + y_off # line piece is special... if self.piece_next==1: abs_x += 1 abs_y -= 1 self.draw_pixel(abs_y, abs_x, self.game_color_piece[self.piece_next]) def draw_pixel(self, row, column, color): if row < 0 or column < 0 or row > self.board_width-1 or column > self.board_height-1: return raw_x = (self.board_height-1 - column) raw_y = row if self.board_rotated: raw_x = self.board_height - 1 - raw_x raw_y = self.board_width - 1 - raw_y self.frame[raw_x * self.board_width + raw_y] = color class Defs: def __init__(self): self.red = 0xFF000000 self.green = 0x00FF0000 self.blue = 0x0000FF00 self.purple = 0xFF00FF00 self.yellow = 0xFFFF0000 self.cyan = 0x00FFFF00 self.white = 0xFFFFFF00 self.black = 0x00000000 self.gray = 0x30303000 tetris = Tetris()