249 lines
7.6 KiB
Python
249 lines
7.6 KiB
Python
"""
|
|
##### #### ##### ### # ####
|
|
# # # # # #
|
|
* # ### # # # # ### *
|
|
# # # # # # #
|
|
# #### # # # # ####
|
|
|
|
"""
|
|
|
|
import curses
|
|
import board
|
|
import time
|
|
|
|
BOARD_WIDTH = 11
|
|
BOARD_HEIGHT = 17
|
|
|
|
GAME_WINDOW_WIDTH = 2 * BOARD_WIDTH + 2
|
|
GAME_WINDOW_HEIGHT = BOARD_HEIGHT + 2
|
|
|
|
HELP_WINDOW_WIDTH = 19
|
|
HELP_WINDOW_HEIGHT = 7
|
|
|
|
STATUS_WINDOW_HEIGHT = 12
|
|
STATUS_WINDOW_WIDTH = HELP_WINDOW_WIDTH
|
|
|
|
TITLE_HEIGHT = 6
|
|
|
|
LEFT_MARGIN = 3
|
|
|
|
TITLE_WIDTH = FOOTER_WIDTH = 50
|
|
|
|
|
|
def init_colors():
|
|
"""Init colors"""
|
|
|
|
curses.init_pair(99, 8, curses.COLOR_BLACK) # 1 - grey
|
|
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, 13) # 13 - pink
|
|
curses.init_pair(3, curses.COLOR_BLACK, curses.COLOR_YELLOW)
|
|
curses.init_pair(4, curses.COLOR_BLACK, curses.COLOR_GREEN)
|
|
curses.init_pair(5, curses.COLOR_BLACK, curses.COLOR_MAGENTA)
|
|
|
|
|
|
def init_game_window():
|
|
"""Create and return game window"""
|
|
|
|
window = curses.newwin(GAME_WINDOW_HEIGHT, GAME_WINDOW_WIDTH, TITLE_HEIGHT, LEFT_MARGIN)
|
|
window.nodelay(True)
|
|
window.keypad(1)
|
|
|
|
return window
|
|
|
|
|
|
def init_status_window():
|
|
"""Create and return status window"""
|
|
|
|
window = curses.newwin(STATUS_WINDOW_HEIGHT, STATUS_WINDOW_WIDTH, TITLE_HEIGHT, GAME_WINDOW_WIDTH + 5)
|
|
return window
|
|
|
|
|
|
def draw_game_window(window):
|
|
"""Draw game window"""
|
|
|
|
window.border()
|
|
|
|
# draw board
|
|
for a in range(BOARD_HEIGHT):
|
|
for b in range(BOARD_WIDTH):
|
|
if game_board.board[a][b] == 1:
|
|
window.addstr(a + 1, 2 * b + 1, " ", curses.color_pair(96))
|
|
else:
|
|
# draw net
|
|
window.addstr(a + 1, 2 * b + 1, " .", curses.color_pair(99))
|
|
|
|
# draw current block
|
|
for a in range(game_board.current_block.size()[0]):
|
|
for b in range(game_board.current_block.size()[1]):
|
|
if game_board.current_block.shape[a][b] == 1:
|
|
x = 2 * game_board.current_block_pos[1] + 2 * b + 1
|
|
y = game_board.current_block_pos[0] + a + 1
|
|
window.addstr(y, x, " ", curses.color_pair(game_board.current_block.color))
|
|
|
|
if game_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))
|
|
|
|
if pause:
|
|
p_title = " Pause "
|
|
window.addstr(int(GAME_WINDOW_HEIGHT * .4), (GAME_WINDOW_WIDTH - len(p_title)) // 2, p_title,
|
|
curses.color_pair(95))
|
|
|
|
window.refresh()
|
|
|
|
|
|
def draw_status_window(window):
|
|
"""Draw status window"""
|
|
|
|
if game_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, " "))
|
|
|
|
window.border()
|
|
|
|
window.addstr(1, 2, f"Score: {game_board.score}")
|
|
window.addstr(2, 2, f"Lines: {game_board.lines}")
|
|
window.addstr(3, 2, f"Level: {game_board.level}")
|
|
window.addstr(4, 2, f"Best Score:{game_board.best_score}")
|
|
|
|
start_col = int(STATUS_WINDOW_WIDTH / 2 - game_board.next_block.size()[1])
|
|
|
|
for row in range(game_board.next_block.size()[0]):
|
|
for col in range(game_board.next_block.size()[1]):
|
|
if game_board.next_block.shape[row][col] == 1:
|
|
window.addstr(6 + row, start_col + 2 * col, " ", curses.color_pair(game_board.next_block.color))
|
|
|
|
window.refresh()
|
|
pass
|
|
|
|
|
|
def draw_help_window():
|
|
"""Draw help window"""
|
|
|
|
window = curses.newwin(HELP_WINDOW_HEIGHT, HELP_WINDOW_WIDTH, TITLE_HEIGHT + STATUS_WINDOW_HEIGHT,
|
|
GAME_WINDOW_WIDTH + 5)
|
|
|
|
window.border()
|
|
|
|
window.addstr(1, 2, "Move - ← ↓ →")
|
|
window.addstr(2, 2, "Drop - space")
|
|
window.addstr(3, 2, "Rotate - ↑")
|
|
window.addstr(4, 2, "Pause - p")
|
|
window.addstr(5, 2, "Quit - q")
|
|
|
|
window.refresh()
|
|
|
|
|
|
def draw_title():
|
|
"""Draw title"""
|
|
|
|
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))
|
|
window.addstr(3, 4, " # # # # # # #", curses.color_pair(98))
|
|
window.addstr(4, 4, " # #### # # # # ####", curses.color_pair(98))
|
|
|
|
window.addstr(2, 0, " *", curses.color_pair(97))
|
|
window.addstr(2, 41, " *", curses.color_pair(97))
|
|
|
|
window.refresh()
|
|
|
|
|
|
def draw_footer():
|
|
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()
|
|
|
|
pause = False
|
|
|
|
game_board = board.Board(BOARD_HEIGHT, BOARD_WIDTH)
|
|
game_board.start()
|
|
|
|
old_score = game_board.score
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
scr = curses.initscr()
|
|
curses.beep()
|
|
curses.noecho()
|
|
curses.cbreak()
|
|
curses.start_color()
|
|
curses.curs_set(0)
|
|
|
|
init_colors()
|
|
|
|
draw_title()
|
|
draw_footer()
|
|
draw_help_window()
|
|
|
|
game_window = init_game_window()
|
|
status_window = init_status_window()
|
|
|
|
draw_game_window(game_window)
|
|
draw_status_window(status_window)
|
|
|
|
start = time.time()
|
|
|
|
quit_game = False
|
|
while not quit_game:
|
|
key_event = game_window.getch()
|
|
|
|
# hack: redraw it on resize
|
|
if key_event == curses.KEY_RESIZE:
|
|
draw_footer()
|
|
draw_help_window()
|
|
draw_game_window(game_window)
|
|
|
|
if key_event == ord("q"):
|
|
quit_game = True
|
|
|
|
if not game_board.is_game_over():
|
|
if not pause:
|
|
if time.time() - start >= 1 / game_board.level:
|
|
game_board.move_block("down")
|
|
start = time.time()
|
|
|
|
if key_event == curses.KEY_UP:
|
|
game_board.rotate_block()
|
|
elif key_event == curses.KEY_DOWN:
|
|
game_board.move_block("down")
|
|
elif key_event == curses.KEY_LEFT:
|
|
game_board.move_block("left")
|
|
elif key_event == curses.KEY_RIGHT:
|
|
game_board.move_block("right")
|
|
elif key_event == ord(" "):
|
|
game_board.drop()
|
|
if key_event == ord("p"):
|
|
pause = not pause
|
|
game_window.nodelay(not pause)
|
|
else:
|
|
curses.beep()
|
|
game_window.nodelay(False)
|
|
if key_event == ord("\n"):
|
|
game_board.start()
|
|
game_window.nodelay(True)
|
|
|
|
draw_game_window(game_window)
|
|
|
|
if old_score != game_board.score:
|
|
draw_status_window(status_window)
|
|
old_score = game_board.score
|
|
finally:
|
|
curses.endwin()
|