import
randomimport pygame
class
Block:
def
__init__(
self
, shape, color, x, y):
self
._shape
=
shape
self
._color
=
color
self
.x
=
x
self
.y
=
y
@property
def
shape(
self
):
return
self
._shape
@property
def
color(
self
):
return
self
._color
def
draw(
self
, surface):
rect
=
(
self
.x
*
25
+
1
,
self
.y
*
25
+
1
,
24
,
24
)
pygame.draw.rect(surface,
self
.color, rect)
class
Game:
def
__init__(
self
, width
=
10
, height
=
20
):
self
.width
=
width
self
.height
=
height
self
._board
=
[[
0
for
x
in
range
(
self
.width)]
for
y
in
range
(
self
.height)]
self
.score
=
0
self
.level
=
1
self
.falling_block
=
None
self
.next_block
=
None
self
.game_over
=
False
@property
def
board(
self
):
return
self
._board
def
new_block(
self
):
shapes
=
[
[[[
1
,
1
,
1
,
1
]], (
255
,
0
,
0
)],
[[[
1
,
1
], [
1
,
1
]], (
0
,
255
,
0
)],
[[[
1
,
1
,
0
], [
0
,
1
,
1
]], (
0
,
0
,
255
)],
[[[
0
,
1
,
1
], [
1
,
1
,
0
]], (
255
,
255
,
0
)],
[[[
1
,
1
,
1
], [
0
,
1
,
0
]], (
0
,
255
,
255
)],
[[[
1
,
1
,
0
], [
0
,
1
,
1
]], (
255
,
0
,
255
)],
[[[
0
,
1
,
0
], [
1
,
1
,
1
]], (
128
,
0
,
128
)]
]
shape, color
=
random.choice(shapes)
self
.falling_block
=
Block(shape, color,
self
.width
/
/
2
-
2
,
0
)
shape, color
=
random.choice(shapes)
self
.next_block
=
Block(shape, color,
0
,
0
)
def
draw_board(
self
, surface):
rect
=
pygame.Rect(
0
,
0
,
25
,
25
)
for
y
in
range
(
self
.height):
for
x
in
range
(
self
.width):
rect.topleft
=
(x
*
25
, y
*
25
)
pygame.draw.rect(surface, (
255
,
255
,
255
), rect,
1
)
if
self
.board[y][x]:
rect.topleft
=
(x
*
25
+
1
, y
*
25
+
1
)
pygame.draw.rect(surface,
self
.board[y][x], rect)
def
draw_falling_block(
self
, surface):
if
self
.falling_block:
for
y, row
in
enumerate
(
self
.falling_block.shape):
for
x, val
in
enumerate
(row):
if
val:
b
=
Block(
self
.falling_block.shape,
self
.falling_block.color,
self
.falling_block.x
+
x,
self
.falling_block.y
+
y)
b.draw(surface)
def
draw_next_block(
self
, surface):
if
self
.next_block:
for
y, row
in
enumerate
(
self
.next_block.shape):
for
x, val
in
enumerate
(row):
if
val:
b
=
Block(
self
.next_block.shape,
self
.next_block.color,
self
.width
+
x, y)
b.draw(surface)
def
move_left(
self
):
if
self
.falling_block:
if
self
.falling_block.x >
0
and
not
self
.collides(
self
.falling_block,
-
1
):
self
.falling_block.x
-
=
1
def
move_right(
self
):
if
self
.falling_block:
if
self
.falling_block.x <
self
.width
-
len
(
self
.falling_block.shape[
0
])
and
not
self
.collides(
self
.falling_block,
1
):
self
.falling_block.x
+
=
1
def
rotate(
self
):
if
self
.falling_block:
tmp
=
list
(
zip
(
*
self
.falling_block.shape[::
-
1
]))
if
self
.falling_block.x
+
len
(tmp[
0
]) <
=
self
.width
and
not
self
.collides(Block(tmp,
self
.falling_block.color,
self
.falling_block.x,
self
.falling_block.y),
0
):
self
.falling_block.shape
=
tmp
def
fall(
self
):
if
self
.falling_block:
if
self
.falling_block.y <
self
.height
-
len
(
self
.falling_block.shape)
and
not
self
.collides(
self
.falling_block,
0
,
1
):
self
.falling_block.y
+
=
1
return
False
else
:
self
.merge_falling_block()
self
.new_block()
return
True
def
merge_falling_block(
self
):
for
y, row
in
enumerate
(
self
.falling_block.shape):
for
x, val
in
enumerate
(row):
if
val:
self
.board[
self
.falling_block.y
+
y][
self
.falling_block.x
+
x]
=
self
.falling_block.color
for
y
in
range
(
self
.height):
if
all
(
self
.board[y]):
self
.board.pop(y)
self
.board.insert(
0
, [
0
for
x
in
range
(
self
.width)])
self
.score
+
=
10
if
self
.score
%
100
=
=
0
:
self
.level
+
=
1
@staticmethod
def
collides(block, dx
=
0
, dy
=
0
, board
=
None
):
board
=
board
or
[]
for
y, row
in
enumerate
(block.shape):
for
x, val
in
enumerate
(row):
if
val:
try
:
if
board[block.y
+
y
+
dy][block.x
+
x
+
dx]:
return
True
except
IndexError:
return
True
return
False
def
main():
pygame.init()
screen
=
pygame.display.set_mode((
320
,
480
))
clock
=
pygame.time.Clock()
game
=
Game()
game.new_block()
paused
=
False
font
=
pygame.font.SysFont(
'Arial'
,
20
)
while
not
game.game_over:
clock.tick(game.level
*
5
)
screen.fill((
0
,
0
,
0
))
game.draw_board(screen)
game.draw_falling_block(screen)
game.draw_next_block(screen)
text
=
font.render(
'Score: '
+
str
(game.score),
True
, (
255
,
255
,
255
))
screen.blit(text, (
10
,
10
))
for
event
in
pygame.event.get():
if
event.
type
=
=
pygame.QUIT:
game.game_over
=
True
elif
event.
type
=
=
pygame.KEYDOWN:
if
event.key
=
=
pygame.K_LEFT:
game.move_left()
elif
event.key
=
=
pygame.K_RIGHT:
game.move_right()
elif
event.key
=
=
pygame.K_UP:
game.rotate()
elif
event.key
=
=
pygame.K_DOWN:
if
not
paused:
game.fall()
elif
event.key
=
=
pygame.K_p:
paused
=
not
paused
elif
event.key
=
=
pygame.K_SPACE:
if
paused:
game
=
Game()
game.new_block()
paused
=
False
if
not
paused:
if
game.fall():
if
game.collides(game.falling_block,
0
,
0
, game.board):
text
=
font.render(
'Game Over'
,
True
, (
255
,
255
,
255
))
screen.blit(text, (
100
,
200
))
paused
=
True
pygame.display.update()
pygame.quit()
if
__name__
=
=
'__main__'
:
main()