master
Artem 2017-07-01 01:46:46 +01:00
parent 109a452179
commit f154d6c2b9
1 changed files with 90 additions and 56 deletions

146
tetris.py
View File

@ -77,26 +77,17 @@ BOARD_HEIGHT = 17
GAME_WINDOW_WIDTH = 2 * BOARD_WIDTH + 2
GAME_WINDOW_HEIGHT = BOARD_HEIGHT + 2
HELP_WINDOW_WIDTH = 18
HELP_WINDOW_HEIGHT = 8
HELP_WINDOW_WIDTH = 19
HELP_WINDOW_HEIGHT = 7
STATUS_WINDOW_WIDTH = 18
STATUS_WINDOW_HEIGHT = 10
STATUS_WINDOW_HEIGHT = 12
STATUS_WINDOW_WIDTH = HELP_WINDOW_WIDTH
TITLE_HEIGHT = 6
LEFT_MARGIN = 3
def init_screen():
screen = curses.initscr()
curses.beep()
curses.noecho()
curses.cbreak()
curses.start_color()
curses.curs_set(0)
init_colors()
return screen
TITLE_WIDTH = FOOTER_WIDTH = 50
def init_colors():
@ -106,6 +97,7 @@ def init_colors():
curses.init_pair(98, curses.COLOR_CYAN, curses.COLOR_BLACK)
curses.init_pair(97, curses.COLOR_RED, curses.COLOR_BLACK)
curses.init_pair(96, curses.COLOR_BLACK, curses.COLOR_CYAN)
curses.init_pair(95, curses.COLOR_BLACK, curses.COLOR_WHITE)
curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_BLUE)
curses.init_pair(2, curses.COLOR_BLACK, curses.COLOR_RED)
@ -117,7 +109,7 @@ def init_colors():
def init_game_window():
"""Create and return game window"""
window = curses.newwin(GAME_WINDOW_HEIGHT, GAME_WINDOW_WIDTH, TITLE_HEIGHT, 3)
window = curses.newwin(GAME_WINDOW_HEIGHT, GAME_WINDOW_WIDTH, TITLE_HEIGHT, LEFT_MARGIN)
# window.nodelay(True)
window.keypad(1)
@ -127,7 +119,7 @@ def init_game_window():
def init_help_window():
"""Create and return help window"""
window = curses.newwin(HELP_WINDOW_HEIGHT, HELP_WINDOW_WIDTH, TITLE_HEIGHT + STATUS_WINDOW_HEIGHT + 1,
window = curses.newwin(HELP_WINDOW_HEIGHT, HELP_WINDOW_WIDTH, TITLE_HEIGHT + STATUS_WINDOW_HEIGHT,
GAME_WINDOW_WIDTH + 5)
return window
@ -140,15 +132,10 @@ def init_status_window():
def draw_game_window(window):
"""Draw game widnow"""
"""Draw game window"""
window.border()
# draw dots
for row in range(1, GAME_WINDOW_HEIGHT - 1, 2):
for col in range(1, GAME_WINDOW_WIDTH - 2, 2):
window.addstr(row, col, ".", curses.color_pair(99))
# draw board
for a in range(BOARD_HEIGHT):
for b in range(BOARD_WIDTH):
@ -156,7 +143,7 @@ def draw_game_window(window):
window.addstr(a + 1, 2 * b + 1, " ", curses.color_pair(96))
else:
# hack: to avoid clearing
window.addstr(a + 1, 2 * b + 1, " ")
window.addstr(a + 1, 2 * b + 1, " .", curses.color_pair(99))
# draw current block
for a in range(board.current_block.size[0]):
@ -166,12 +153,22 @@ def draw_game_window(window):
y = board.current_block_pos[0] + a + 1
window.addstr(y, x, " ", curses.color_pair(board.current_block.color))
if board.is_game_over():
go_title = " Game Over "
ag_title = " Enter - play again "
window.addstr(int(GAME_WINDOW_HEIGHT*.4), (GAME_WINDOW_WIDTH - len(go_title)) // 2, go_title, curses.color_pair(95))
window.addstr(int(GAME_WINDOW_HEIGHT*.5), (GAME_WINDOW_WIDTH - len(ag_title)) // 2, ag_title, curses.color_pair(95))
window.refresh()
def draw_status_window(window):
"""Draw status window"""
if board.is_game_over():
return
# hack: avoid clearing (blinking)
for row in range(1, STATUS_WINDOW_HEIGHT - 1):
window.addstr(row, 2, "".rjust(STATUS_WINDOW_WIDTH - 3, " "))
@ -181,14 +178,16 @@ def draw_status_window(window):
score = random.randint(1, 3000)
window.addstr(1, 2, f"Score: {score}")
window.addstr(2, 2, "Next block:")
window.addstr(2, 2, "Lines: 300")
window.addstr(3, 2, "Speed: 2")
window.addstr(4, 2, "Best Score: 2000")
start_col = int(STATUS_WINDOW_WIDTH / 2 - board.next_block.size[1])
for row in range(board.next_block.size[0]):
for col in range(board.next_block.size[1]):
if board.next_block.shape[row][col] == 1:
window.addstr(4 + row, start_col + 2 * col, " ", curses.color_pair(board.next_block.color))
window.addstr(6 + row, start_col + 2 * col, " ", curses.color_pair(board.next_block.color))
window.refresh()
@ -197,8 +196,6 @@ def draw_help_window(window):
"""Draw help window"""
window.border()
title = "Controls"
window.addstr(0, int(HELP_WINDOW_WIDTH / 2 - len(title) / 2), title)
window.addstr(1, 2, "Move - ← ↓ →")
window.addstr(2, 2, "Drop - space")
@ -212,7 +209,7 @@ def draw_help_window(window):
def draw_title():
"""Draw title"""
window = curses.newwin(TITLE_HEIGHT, 50, 1, 3)
window = curses.newwin(TITLE_HEIGHT, TITLE_WIDTH, 1, LEFT_MARGIN)
window.addstr(0, 4, "##### #### ##### ### # ####", curses.color_pair(98))
window.addstr(1, 4, " # # # # # #", curses.color_pair(98))
window.addstr(2, 4, " # ### # # # # ###", curses.color_pair(98))
@ -226,9 +223,11 @@ def draw_title():
def draw_footer():
window = curses.newwin(1, 50, TITLE_HEIGHT + GAME_WINDOW_HEIGHT + 1, 10)
window.addstr(0, 9, "Made with", curses.color_pair(98))
window.addstr(0, 19, "", curses.color_pair(97))
title = "Made with"
window = curses.newwin(1, FOOTER_WIDTH, TITLE_HEIGHT + GAME_WINDOW_HEIGHT + 1, LEFT_MARGIN)
col_pos = int((GAME_WINDOW_WIDTH + STATUS_WINDOW_WIDTH - len(title) + 1) / 2)
window.addstr(0, col_pos, title, curses.color_pair(98))
window.addstr(0, col_pos + len(title) + 1, "", curses.color_pair(97))
window.refresh()
@ -248,7 +247,7 @@ block_shapes = [
[[1, 1],
[1, 1]],
# i block
[[1, 1, 1, 1]]
[[1], [1], [1], [1]]
]
@ -258,20 +257,36 @@ class Board:
def __init__(self, height, width):
self.height = height
self.width = width
self.board = [[0 for _ in range(width)] for _ in range(height)]
self.board = self._get_new_board()
self.current_block_pos = None
self.current_block = None
self.next_block = None
self.game_over = False
def _get_new_board(self):
return [[0 for _ in range(self.width)] for _ in range(self.height)]
def start(self):
"""Start game"""
self.board = self._get_new_board()
self.current_block_pos = None
self.current_block = None
self.next_block = None
self.game_over = False
self.place_new_block()
def place_new_block(self):
"""Place new block and generate the next one"""
if self.is_game_over():
raise Exception("game is over")
if self.next_block is None:
self.current_block = self._generate_block()
self.next_block = self._generate_block()
@ -282,6 +297,9 @@ class Board:
col_pos = math.ceil((self.width - self.current_block.size[1]) / 2)
self.current_block_pos = [0, col_pos]
if self._check_overlapping(self.current_block_pos):
self.game_over = True
def _land_block(self):
"""Put block to the board and generate a new one"""
@ -292,8 +310,8 @@ class Board:
self.place_new_block()
def check_game_over(self):
pass
def is_game_over(self):
return self.game_over
def move_block(self, direction):
"""Try to move block"""
@ -333,6 +351,14 @@ class Board:
for r in range(row, 0, -1):
self.board[r] = self.board[r-1]
def _check_overlapping(self, pos):
for row in range(self.current_block.size[0]):
for col in range(self.current_block.size[1]):
if self.current_block.shape[row][col] == 1:
if self.board[pos[0] + row][pos[1] + col] == 1:
return True
return False
def _can_move(self, to_pos):
"""Check if move is possible"""
@ -340,12 +366,7 @@ class Board:
or to_pos[0] + self.current_block.size[0] > BOARD_HEIGHT:
return False
for row in range(self.current_block.size[0]):
for col in range(self.current_block.size[1]):
if self.current_block.shape[row][col] == 1:
if self.board[to_pos[0] + row][to_pos[1] + col] == 1:
return False
return True
return not self._check_overlapping(to_pos)
@staticmethod
def _generate_block():
@ -383,7 +404,14 @@ board.start()
if __name__ == "__main__":
try:
screen = init_screen()
scr = curses.initscr()
curses.beep()
curses.noecho()
curses.cbreak()
curses.start_color()
curses.curs_set(0)
init_colors()
draw_title()
draw_footer()
@ -405,20 +433,26 @@ if __name__ == "__main__":
key_event = game_window.getch()
if key_event == curses.KEY_UP:
board.current_block.rotate()
elif key_event == curses.KEY_DOWN:
board.move_block("down")
elif key_event == curses.KEY_LEFT:
board.move_block("left")
elif key_event == curses.KEY_RIGHT:
board.move_block("right")
elif key_event == ord(" "):
board.drop()
elif key_event == ord("q"):
if key_event == ord("q"):
quit_game = True
elif key_event == ord("p"):
pass
if not board.is_game_over():
if key_event == curses.KEY_UP:
board.current_block.rotate()
elif key_event == curses.KEY_DOWN:
board.move_block("down")
elif key_event == curses.KEY_LEFT:
board.move_block("left")
elif key_event == curses.KEY_RIGHT:
board.move_block("right")
elif key_event == ord(" "):
board.drop()
elif key_event == ord("p"):
pass
else:
curses.beep()
if key_event == ord("\n"):
board.start()
draw_game_window(game_window)