We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
See: https://en.wikipedia.org/wiki/Tetris
Prototype:
"""Game of Tetris for Liftoff Interview Written by Grant Jenks Copyright 2019 """ 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()
The text was updated successfully, but these errors were encountered:
No branches or pull requests
See: https://en.wikipedia.org/wiki/Tetris
Prototype:
The text was updated successfully, but these errors were encountered: