tetrys/tetris.py

269 lines
7.6 KiB
Python
Raw Normal View History

2014-05-16 00:07:48 +00:00
#!/usr/bin/env python
import pygame
import random
2014-05-16 00:07:48 +00:00
2014-05-16 06:08:33 +00:00
#
# Tetrad
#
class Tetrad:
block_rotations = 4
block_configs = [
2014-05-16 06:37:53 +00:00
(1, [[(1, 0), (1, 1), (1, 2), (1, 3)], [(0, 1), (1, 1), (2, 1), (3, 1)], [(1, 0), (1, 1), (1, 2), (1, 3)], [(0, 1), (1, 1), (2, 1), (3, 1)]]), # Shape_I
(2, [[(0, 1), (1, 1), (2, 1), (1, 2)], [(1, 0), (1, 1), (2, 1), (1, 2)], [(1, 0), (0, 1), (1, 1), (2, 1)], [(1, 0), (0, 1), (1, 1), (1, 2)]]), # Shape T
(3, [[(0, 0), (0, 1), (1, 0), (1, 1)], [(0, 0), (0, 1), (1, 0), (1, 1)], [(0, 0), (0, 1), (1, 0), (1, 1)], [(0, 0), (0, 1), (1, 0), (1, 1)]]), # Shape O
(4, [[(1, 0), (1, 1), (1, 2), (2, 2)], [(2, 0), (2, 1), (1, 1), (0, 1)], [(0, 0), (1, 0), (1, 1), (1, 2)], [(0, 1), (1, 1), (2, 1), (0, 2)]]), # Shape L
(5, [[(1, 0), (1, 1), (1, 2), (0, 2)], [(2, 1), (2, 2), (1, 1), (0, 1)], [(1, 0), (2, 0), (1, 1), (1, 2)], [(0, 0), (1, 1), (2, 1), (0, 1)]]), # Shape J
(6, [[(1, 1), (2, 1), (0, 2), (1, 2)], [(1, 0), (1, 1), (2, 1), (2, 2)], [(1, 1), (2, 1), (0, 2), (1, 2)], [(1, 0), (1, 1), (2, 1), (2, 2)]]), # Shape S
(7, [[(0, 1), (1, 1), (1, 2), (2, 2)], [(1, 1), (1, 2), (2, 0), (2, 1)], [(0, 1), (1, 1), (1, 2), (2, 2)], [(1, 1), (1, 2), (2, 0), (2, 1)]]) # Shape Z
2014-05-16 06:08:33 +00:00
]
def __init__(self, position, config, rotation):
2014-05-16 06:08:33 +00:00
self.position = position
self.config = config
2014-05-16 06:08:33 +00:00
self.rotation = rotation
2014-05-16 06:34:53 +00:00
def color(self):
return self.block_configs[self.config][0]
2014-05-16 06:44:50 +00:00
2014-05-16 06:08:33 +00:00
def layout(self):
2014-05-16 06:34:53 +00:00
layout = self.block_configs[self.config][1][self.rotation]
2014-05-16 06:29:12 +00:00
return map(lambda p: (self.position[0]+p[0], self.position[1]+p[1]), layout)
def moved_left(self):
return Tetrad((self.position[0]-1, self.position[1]), self.config, self.rotation)
2014-05-16 06:29:12 +00:00
def moved_right(self):
return Tetrad((self.position[0]+1, self.position[1]), self.config, self.rotation)
2014-05-16 06:29:12 +00:00
def moved_down(self):
return Tetrad((self.position[0], self.position[1]+1), self.config, self.rotation)
2014-05-16 06:29:12 +00:00
def rotated(self):
return Tetrad(self.position, self.config, (self.rotation + 1) % self.block_rotations)
@staticmethod
def random(position=(0, 0)):
config = random.randrange(len(Tetrad.block_configs))
rotation = random.randrange(Tetrad.block_rotations)
return Tetrad(position, config, rotation)
2014-05-16 06:08:33 +00:00
#
# Board
#
2014-05-16 04:58:16 +00:00
class Board:
2014-05-16 06:08:33 +00:00
grid_color = pygame.Color(0xff, 0xff, 0xff, 0xff)
block_colors = [
2014-05-16 06:29:12 +00:00
pygame.Color(0x00, 0x00, 0x00, 0xff), # Black
2014-05-16 06:08:33 +00:00
pygame.Color(0x00, 0xff, 0xff, 0xff), # Cyan
pygame.Color(0x00, 0x00, 0xff, 0xff), # Blue
pygame.Color(0xff, 0x80, 0x00, 0xff), # Orange
pygame.Color(0xff, 0xff, 0x00, 0xff), # Yellow
pygame.Color(0x00, 0xff, 0x00, 0xff), # Green
pygame.Color(0x80, 0x00, 0x80, 0xff), # Purple
pygame.Color(0xff, 0x00, 0x00, 0xff) # Red
]
2014-05-16 05:18:06 +00:00
def __init__(self, grid_position, grid_dims, grid_border_width, block_dims):
self.grid_dims = grid_dims
self.grid_border_width = grid_border_width
2014-05-16 04:58:16 +00:00
self.block_dims = block_dims
2014-05-16 05:18:06 +00:00
2014-05-16 06:29:12 +00:00
grid_screen_dims = grid_border_width*2+grid_dims[0]*block_dims[0], grid_border_width*2+grid_dims[1]*block_dims[1]
2014-05-16 05:18:06 +00:00
self.grid_rect = pygame.Rect(grid_position, grid_screen_dims)
2014-05-16 05:37:15 +00:00
self.blocks = [[0]*grid_dims[1] for i in range(grid_dims[0])]
2014-05-16 04:58:16 +00:00
2014-05-16 06:08:33 +00:00
2014-05-16 06:29:12 +00:00
def render(self, surface, tetrad):
2014-05-16 04:58:16 +00:00
self.render_frame(surface)
2014-05-16 05:18:06 +00:00
self.render_blocks(surface)
2014-05-16 06:29:12 +00:00
self.render_tetrad(surface, tetrad)
2014-05-16 04:58:16 +00:00
def render_frame(self, surface):
pygame.draw.rect(surface, self.grid_color, self.grid_rect, 1)
2014-05-16 05:18:06 +00:00
def render_blocks(self, surface):
for y in xrange(self.grid_dims[1]):
for x in xrange(self.grid_dims[0]):
2014-05-16 05:37:15 +00:00
self.render_block(surface, self.blocks[x][y], (x, y))
2014-05-16 05:18:06 +00:00
2014-05-16 06:29:12 +00:00
def render_tetrad(self, surface, tetrad):
color = tetrad.color()
2014-05-16 06:29:12 +00:00
for point in tetrad.layout():
self.render_block(surface, color, point)
2014-05-16 06:29:12 +00:00
2014-05-16 05:37:15 +00:00
def render_block(self, surface, color, position):
2014-05-16 05:18:06 +00:00
block_rect = self.block_screen_rect(position)
2014-05-16 06:29:12 +00:00
pygame.draw.rect(surface, self.block_colors[color], block_rect)
2014-05-16 05:18:06 +00:00
def block_screen_rect(self, position):
2014-05-16 06:29:12 +00:00
top_left = (
self.grid_border_width+self.grid_rect.x+self.block_dims[0]*position[0],
self.grid_border_width+self.grid_rect.y+self.block_dims[1]*position[1]
)
2014-05-16 05:18:06 +00:00
return pygame.Rect(top_left, self.block_dims)
2014-05-16 04:58:16 +00:00
2014-05-16 06:44:50 +00:00
def can_place_tetrad(self, tetrad):
for point in tetrad.layout():
if point[0] < 0 or point[1] < 0:
return False
if point[0] >= self.grid_dims[0] or point[1] >= self.grid_dims[1]:
return False
if self.blocks[point[0]][point[1]] != 0:
return False
return True
def place_tetrad(self, tetrad):
color = tetrad.color()
for point in tetrad.layout():
self.blocks[point[0]][point[1]] = color
2014-05-16 06:08:33 +00:00
#
# Game
#
class Game:
2014-05-16 04:58:16 +00:00
def __init__(self):
2014-05-16 05:18:06 +00:00
self.board = Board((10, 10), (10, 20), 1, (20, 20))
self.tetrad = Tetrad.random()
2014-05-16 06:08:33 +00:00
def render(self, surface):
2014-05-16 06:29:12 +00:00
self.board.render(surface, self.tetrad)
2014-05-16 06:08:33 +00:00
def advance(self):
pass
def try_action(self, tetrad):
2014-05-16 06:44:50 +00:00
if self.board.can_place_tetrad(tetrad):
self.tetrad = tetrad
return True
return False
2014-05-16 06:44:50 +00:00
2014-05-16 06:08:33 +00:00
def move_left(self):
self.try_action(self.tetrad.moved_left())
2014-05-16 06:08:33 +00:00
def move_right(self):
self.try_action(self.tetrad.moved_right())
2014-05-16 06:08:33 +00:00
def move_down(self):
if not self.try_action(self.tetrad.moved_down()):
self.board.place_tetrad(self.tetrad)
self.tetrad = Tetrad.random()
2014-05-16 06:08:33 +00:00
def rotate(self):
self.try_action(self.tetrad.rotated())
2014-05-16 06:08:33 +00:00
#
# Engine
#
class Engine:
def __init__(self):
2014-05-16 04:58:16 +00:00
self.surface = None
2014-05-16 06:08:33 +00:00
self.game = Game()
2014-05-16 04:58:16 +00:00
2014-05-16 00:07:48 +00:00
def create(self, resolution):
pygame.init()
2014-05-16 04:58:16 +00:00
self.surface = pygame.display.set_mode(resolution, pygame.DOUBLEBUF)
2014-05-16 00:07:48 +00:00
if pygame.joystick.get_count() > 0:
self.joystick = pygame.joystick.Joystick(0)
self.joystick.init()
else:
self.joystick = None
def update(self):
2014-05-16 06:08:33 +00:00
self.game.advance()
self.game.render(self.surface)
2014-05-16 04:58:16 +00:00
2014-05-16 00:07:48 +00:00
pygame.display.flip()
pygame.time.delay(1)
2014-05-16 04:58:16 +00:00
2014-05-16 00:07:48 +00:00
event = pygame.event.poll()
return self.handle_event(event)
def destroy(self):
2014-05-16 04:58:16 +00:00
self.surface = None
2014-05-16 00:07:48 +00:00
if self.joystick is not None:
self.joystick.quit()
pygame.quit()
def handle_event(self, event):
if event.type == pygame.QUIT:
return False
if event.type == pygame.KEYDOWN:
2014-05-16 04:43:20 +00:00
if event.key == pygame.K_LEFT:
2014-05-16 06:08:33 +00:00
self.game.move_left()
2014-05-16 04:43:20 +00:00
elif event.key == pygame.K_RIGHT:
2014-05-16 06:08:33 +00:00
self.game.move_right()
2014-05-16 04:43:20 +00:00
elif event.key == pygame.K_DOWN:
2014-05-16 06:08:33 +00:00
self.game.move_down()
2014-05-16 04:43:20 +00:00
elif event.key == pygame.K_UP:
2014-05-16 06:08:33 +00:00
self.game.rotate()
2014-05-16 04:43:20 +00:00
elif event.key == pygame.K_ESCAPE:
return False
2014-05-16 00:07:48 +00:00
elif event.type == pygame.JOYAXISMOTION:
if event.axis == 0:
2014-05-16 06:08:33 +00:00
if event.value > 0: self.game.move_right()
elif event.value < 0: self.game.move_left()
2014-05-16 00:07:48 +00:00
elif event.axis == 1:
2014-05-16 06:08:33 +00:00
if event.value > 0: self.game.move_down()
elif event.value < 0: self.game.rotate()
2014-05-16 00:07:48 +00:00
return True
2014-05-16 06:08:33 +00:00
#
# Entry
#
2014-05-16 00:07:48 +00:00
def main():
engine = Engine()
engine.create((800, 600))
while engine.update():
pass
engine.destroy()
if __name__ == '__main__':
main()