Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Codigo Tetris

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 4

1

#!/usr/bin/env python self.color = random.choice((


# -*- coding: utf-8 -*- (200, 200, 200),
(215, 133, 133),
""" (30, 145, 255),
The classic Tetris developed using PyGame. (0, 170, 0),
Copyright (C) 2018 Recursos Python - recursospython.com. (180, 0, 140),
""" (200, 200, 0)
))
from collections import OrderedDict self.current = True
import random self.struct = np.array(self.struct)
# Initial random rotation and flip.
from pygame import Rect if random.randint(0, 1):
import pygame self.struct = np.rot90(self.struct)
import numpy as np if random.randint(0, 1):
# Flip in the X axis.
self.struct = np.flip(self.struct, 0)
WINDOW_WIDTH, WINDOW_HEIGHT = 500, 601 self._draw()
GRID_WIDTH, GRID_HEIGHT = 300, 600
TILE_SIZE = 30 def _draw(self, x=4, y=0):
width = len(self.struct[0]) * TILE_SIZE
height = len(self.struct) * TILE_SIZE
def remove_empty_columns(arr, _x_offset=0, _keep_counting=True): self.image = pygame.surface.Surface([width, height])
""" self.image.set_colorkey((0, 0, 0))
Remove empty columns from arr (i.e. those filled with zeros). # Position and size
The return value is (new_arr, x_offset), where x_offset is how self.rect = Rect(0, 0, width, height)
much the x coordinate needs to be increased in order to maintain self.x = x
the block's original position. self.y = y
""" for y, row in enumerate(self.struct):
for colid, col in enumerate(arr.T): for x, col in enumerate(row):
if col.max() == 0: if col:
if _keep_counting: pygame.draw.rect(
_x_offset += 1 self.image,
# Remove the current column and try again. self.color,
arr, _x_offset = remove_empty_columns( Rect(x*TILE_SIZE + 1, y*TILE_SIZE + 1,
np.delete(arr, colid, 1), _x_offset, _keep_counting) TILE_SIZE - 2, TILE_SIZE - 2)
break )
else: self._create_mask()
_keep_counting = False
return arr, _x_offset def redraw(self):
self._draw(self.x, self.y)

class BottomReached(Exception): def _create_mask(self):


pass """
Create the mask attribute from the main surface.
The mask is required to check collisions. This should be called
class TopReached(Exception): after the surface is created or update.
pass """
self.mask = pygame.mask.from_surface(self.image)

class Block(pygame.sprite.Sprite): def initial_draw(self):


raise NotImplementedError
@staticmethod
def collide(block, group): @property
""" def group(self):
Check if the specified block collides with some other block return self.groups()[0]
in the group.
""" @property
for other_block in group: def x(self):
# Ignore the current block which will always collide with itself. return self._x
if block == other_block:
continue @x.setter
if pygame.sprite.collide_mask(block, other_block) is not None: def x(self, value):
return True self._x = value
return False self.rect.left = value*TILE_SIZE

def __init__(self): @property


super().__init__() def y(self):
# Get a random color. return self._y
2

@y.setter class LineBlock(Block):


def y(self, value): struct = (
self._y = value (1,),
self.rect.top = value*TILE_SIZE (1,),
(1,),
def move_left(self, group): (1,)
self.x -= 1 )
# Check if we reached the left margin.
if self.x < 0 or Block.collide(self, group):
self.x += 1 class LBlock(Block):
struct = (
def move_right(self, group): (1, 1),
self.x += 1 (1, 0),
# Check if we reached the right margin or collided with another (1, 0),
# block. )
if self.rect.right > GRID_WIDTH or Block.collide(self, group):
# Rollback.
self.x -= 1 class ZBlock(Block):
struct = (
def move_down(self, group): (0, 1),
self.y += 1 (1, 1),
# Check if the block reached the bottom or collided with (1, 0),
# another one. )
if self.rect.bottom > GRID_HEIGHT or Block.collide(self, group):
# Rollback to the previous position.
self.y -= 1 class BlocksGroup(pygame.sprite.OrderedUpdates):
self.current = False
raise BottomReached @staticmethod
def get_random_block():
def rotate(self, group): return random.choice(
self.image = pygame.transform.rotate(self.image, 90) (SquareBlock, TBlock, LineBlock, LBlock, ZBlock))()
# Once rotated we need to update the size and position.
self.rect.width = self.image.get_width() def __init__(self, *args, **kwargs):
self.rect.height = self.image.get_height() super().__init__(self, *args, **kwargs)
self._create_mask() self._reset_grid()
# Check the new position doesn't exceed the limits or collide self._ignore_next_stop = False
# with other blocks and adjust it if necessary. self.score = 0
while self.rect.right > GRID_WIDTH: self.next_block = None
self.x -= 1 # Not really moving, just to initialize the attribute.
while self.rect.left < 0: self.stop_moving_current_block()
self.x += 1 # The first block.
while self.rect.bottom > GRID_HEIGHT: self._create_new_block()
self.y -= 1
while True: def _check_line_completion(self):
if not Block.collide(self, group): """
break Check each line of the grid and remove the ones that
self.y -= 1 are complete.
self.struct = np.rot90(self.struct) """
# Start checking from the bottom.
def update(self): for i, row in enumerate(self.grid[::-1]):
if self.current: if all(row):
self.move_down() self.score += 5
# Get the blocks affected by the line deletion and
# remove duplicates.
class SquareBlock(Block): affected_blocks = list(
struct = ( OrderedDict.fromkeys(self.grid[-1 - i]))
(1, 1),
(1, 1) for block, y_offset in affected_blocks:
) # Remove the block tiles which belong to the
# completed line.
block.struct = np.delete(block.struct, y_offset, 0)
class TBlock(Block): if block.struct.any():
struct = ( # Once removed, check if we have empty columns
(1, 1, 1), # since they need to be dropped.
(0, 1, 0) block.struct, x_offset = \
) remove_empty_columns(block.struct)
# Compensate the space gone with the columns to
3

# keep the block's original position. def move_current_block(self):


block.x += x_offset # First check if there's something to move.
# Force update. if self._current_block_movement_heading is None:
block.redraw() return
else: action = {
# If the struct is empty then the block is gone. pygame.K_DOWN: self.current_block.move_down,
self.remove(block) pygame.K_LEFT: self.current_block.move_left,
pygame.K_RIGHT: self.current_block.move_right
# Instead of checking which blocks need to be moved }
# once a line was completed, just try to move all of try:
# them. # Each function requires the group as the first argument
for block in self: # to check any possible collision.
# Except the current block. action[self._current_block_movement_heading](self)
if block.current: except BottomReached:
continue self.stop_moving_current_block()
# Pull down each block until it reaches the self._create_new_block()
# bottom or collides with another block. else:
while True: self.update_grid()
try:
block.move_down(self) def start_moving_current_block(self, key):
except BottomReached: if self._current_block_movement_heading is not None:
break self._ignore_next_stop = True
self._current_block_movement_heading = key
self.update_grid()
# Since we've updated the grid, now the i counter def stop_moving_current_block(self):
# is no longer valid, so call the function again if self._ignore_next_stop:
# to check if there're other completed lines in the self._ignore_next_stop = False
# new grid. else:
self._check_line_completion() self._current_block_movement_heading = None
break
def rotate_current_block(self):
def _reset_grid(self): # Prevent SquareBlocks rotation.
self.grid = [[0 for _ in range(10)] for _ in range(20)] if not isinstance(self.current_block, SquareBlock):
self.current_block.rotate(self)
def _create_new_block(self): self.update_grid()
new_block = self.next_block or BlocksGroup.get_random_block()
if Block.collide(new_block, self):
raise TopReached def draw_grid(background):
self.add(new_block) """Draw the background grid."""
self.next_block = BlocksGroup.get_random_block() grid_color = 50, 50, 50
self.update_grid() # Vertical lines.
self._check_line_completion() for i in range(11):
x = TILE_SIZE * i
def update_grid(self): pygame.draw.line(
self._reset_grid() background, grid_color, (x, 0), (x, GRID_HEIGHT)
for block in self: )
for y_offset, row in enumerate(block.struct): # Horizontal liens.
for x_offset, digit in enumerate(row): for i in range(21):
# Prevent replacing previous blocks. y = TILE_SIZE * i
if digit == 0: pygame.draw.line(
continue background, grid_color, (0, y), (GRID_WIDTH, y)
rowid = block.y + y_offset )
colid = block.x + x_offset
self.grid[rowid][colid] = (block, y_offset)
def draw_centered_surface(screen, surface, y):
@property screen.blit(surface, (400 - surface.get_width()/2, y))
def current_block(self):
return self.sprites()[-1]
def main():
def update_current_block(self): pygame.init()
try: pygame.display.set_caption("Tetris con PyGame")
self.current_block.move_down(self) screen = pygame.display.set_mode((WINDOW_WIDTH,
except BottomReached: WINDOW_HEIGHT))
self.stop_moving_current_block() run = True
self._create_new_block() paused = False
else: game_over = False
self.update_grid() # Create background.
background = pygame.Surface(screen.get_size())
4

bgcolor = (0, 0, 0) draw_centered_surface(screen, score_text, 270)


background.fill(bgcolor) if game_over:
# Draw the grid on top of the background. draw_centered_surface(screen, game_over_text, 360)
draw_grid(background) # Update.
# This makes blitting faster. pygame.display.flip()
background = background.convert()
pygame.quit()
try:
font = pygame.font.Font("Roboto-Regular.ttf", 20)
except OSError: if __name__ == "__main__":
# If the font file is not available, the default will be used. main()
pass
next_block_text = font.render(
"Siguiente figura:", True, (255, 255, 255), bgcolor)
score_msg_text = font.render(
"Puntaje:", True, (255, 255, 255), bgcolor)
game_over_text = font.render(
"¡Juego terminado!", True, (255, 220, 0), bgcolor)

# Event constants.
MOVEMENT_KEYS = pygame.K_LEFT, pygame.K_RIGHT, pygame.K_DOWN
EVENT_UPDATE_CURRENT_BLOCK = pygame.USEREVENT + 1
CODIGO DE
TETRIS EN
EVENT_MOVE_CURRENT_BLOCK = pygame.USEREVENT + 2
pygame.time.set_timer(EVENT_UPDATE_CURRENT_BLOCK, 1000)
pygame.time.set_timer(EVENT_MOVE_CURRENT_BLOCK, 100)

blocks = BlocksGroup()

while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
PYTHON
run = False
break
elif event.type == pygame.KEYUP:
if not paused and not game_over:
if event.key in MOVEMENT_KEYS:
blocks.stop_moving_current_block()
elif event.key == pygame.K_UP:
blocks.rotate_current_block()
if event.key == pygame.K_p:
paused = not paused

# Stop moving blocks if the game is over or paused.


if game_over or paused:
continue

if event.type == pygame.KEYDOWN:
if event.key in MOVEMENT_KEYS:
blocks.start_moving_current_block(event.key)

try:
if event.type == EVENT_UPDATE_CURRENT_BLOCK:
blocks.update_current_block()
elif event.type == EVENT_MOVE_CURRENT_BLOCK:
blocks.move_current_block()
except TopReached:
game_over = True

# Draw background and grid.


screen.blit(background, (0, 0))
# Blocks.
blocks.draw(screen)
# Sidebar with misc. information.
draw_centered_surface(screen, next_block_text, 50)
draw_centered_surface(screen, blocks.next_block.image, 100)
draw_centered_surface(screen, score_msg_text, 240)
score_text = font.render(
str(blocks.score), True, (255, 255, 255), bgcolor)

You might also like