Você está na página 1de 5

import atexit

import collections
import itertools
import random
import sqlite3
import threading
import time

import console

original_terminal_state =
console.get_terminal_mode()
atexit.register(console.set_terminal_mode,
original_terminal_state)

class Game:
"Game state for Tetris."
def __init__(self, width, height, seed=None):
self.random = random.Random(seed)
self.width = width
self.height = height
self.board =
collections.defaultdict(lambda: '#')
for x in range(width):
for y in range(height):
self.board[x, y] = ' '
self.active = True
self.speed = 20
self.next_letter =
self.random.choice('IJLOSTZ')
self.piece = self.next_piece()
self.score = 0
self.stash = None

def draw(self):
"Draw game state."
print('Score:', self.score, end='\r\n')
print('Level:', self.score // 4 + 1,
end='\r\n')
print('Next piece:', self.next_letter,
end='\r\n')
print('Stash piece:', 'no' if self.stash
is None else 'yes', end='\r\n')
print('*' * (self.width + 2), end='\r\n')
for y in range(self.height):
print('|', end='')
for x in range(self.width):
if (x, y) in self.piece:
print('@', end='')
else:
print(self.board[x, y],
end='')
print('|', end='\r\n')
print('*' * (self.width + 2), end='\r\n')

def next_piece(self):
"Create a new piece, on collision set
active to False."
letter = self.next_letter
self.next_letter =
self.random.choice('IJLOSTZ')
if letter == 'I':
piece = {(0, 0), (0, 1), (0, 2), (0,
3)}
elif letter == 'J':
piece = {(1, 0), (1, 1), (1, 2), (0,
2)}
elif letter == 'L':
piece = {(0, 0), (0, 1), (0, 2), (1,
2)}
elif letter == 'O':
piece = {(0, 0), (0, 1), (1, 0), (1,
1)}
elif letter == 'S':
piece = {(0, 1), (1, 0), (1, 1), (2,
0)}
elif letter == 'T':
piece = {(0, 0), (1, 0), (2, 0), (1,
1)}
else:
assert letter == 'Z'
piece = {(0, 0), (1, 0), (1, 1), (2,
1)}
offset = self.width // 2 - 1
piece = {(x + offset, y) for x, y in
piece}
if self.collide(piece):
self.end()
return piece

def end(self):
self.active = False
print('Game over! Press any key to quit.',
end='\r\n')

def tick(self, mark):


"Notify the game of a clock tick."
if mark % self.speed == 0:
moved = self.move_piece(0, 1)
if not moved:
for x, y in self.piece:
self.board[x, y] = '#'
self.collapse()
self.piece = self.next_piece()
self.draw()

def collapse(self):
"Collapse full lines."
y = self.height - 1
while y >= 0:
full_line = all(self.board[x, y] ==
'#' for x in range(self.width))
if full_line:
z = y
while z > 0:
for x in range(self.width):
self.board[x, z] =
self.board[x, z - 1]
z -= 1
for x in range(self.width):
self.board[x, 0] = ' '
self.score += 1
if self.score % 4 == 0:
self.speed -= 1
else:
y -= 1

def collide(self, piece):


"Check whether piece collides with others
on board."
return any(self.board[x, y] != ' ' for x,
y in piece)

def move_piece(self, x, y):


"Move piece by delta x and y."
new_piece = {(a + x, y + b) for a, b in
self.piece}
if self.collide(new_piece):
return False
self.piece = new_piece
return True

def rotate_piece(self):
"Rotate piece."
min_x = min(x for x, y in self.piece)
max_x = max(x for x, y in self.piece)
diff_x = max_x - min_x
min_y = min(y for x, y in self.piece)
max_y = max(y for x, y in self.piece)
diff_y = max_y - min_y
size = max(diff_x, diff_y)
new_piece = set()
for x, y in self.piece:
pair = (min_x + size) - (y - min_y),
min_y + (x - min_x)
new_piece.add(pair)
if self.collide(new_piece):
return False
self.piece = new_piece
return True

def move(self, key):


"Update game state based on key press."
if key == 'left':
moved = self.move_piece(-1, 0)
elif key == 'right':
moved = self.move_piece(1, 0)
elif key == 'down':
moved = self.move_piece(0, 1)
elif key == 'up':
moved = self.rotate_piece()
elif key == 'swap':
if self.stash is None:
self.stash = self.piece
self.piece = self.next_piece()
else:
self.piece, self.stash =
self.stash, self.piece
if self.collide(self.piece):
self.end()
moved = True
else:
assert key == 'space'
moved = self.move_piece(0, 1)
while moved:
moved = self.move_piece(0, 1)
moved = True
if moved:
self.draw()

def draw_loop(game):
"""Draw loop.

Handle console drawing in a separate thread.

"""
game.draw()
counter = itertools.count(start=1)
while game.active:
mark = next(counter)
game.tick(mark)
time.sleep(0.1)

def input_loop(game):
"""Input loop.

Handle keyboard input in a separate thread.

"""
while game.active:
key = console.get_input()
if key is None:
continue
elif key == 'quit':
game.active = False
else:
assert key in ('left', 'down',
'right', 'up', 'space', 'swap')
game.move(key)

console.set_terminal_mode(original_terminal_state)
print('Enter your name for leaderboard (blank
to ignore):')
name = input()
if name:
con = sqlite3.connect('tetris.sqlite3',
isolation_level=None)
con.execute('CREATE TABLE IF NOT EXISTS
Leaderboard (name, score)')
con.execute('INSERT INTO Leaderboard
VALUES (?, ?)', (name, game.score))
scores = con.execute('SELECT * FROM
Leaderboard ORDER BY score DESC LIMIT 10')
print('{0:<16} | {1:<16}'.format('Name',
'Score'))
for pair in scores:
print('{0:<16} |
{1:<16}'.format(*pair))

def main():
"Main entry-point for Tetris."
game = Game(10, 10)
draw_thread =
threading.Thread(target=draw_loop, args=(game,))
input_thread =
threading.Thread(target=input_loop, args=(game,))
draw_thread.start()
input_thread.start()
draw_thread.join()
input_thread.join()

if __name__ == '__main__':
main()

Você também pode gostar