terminal上でテトリスで遊ぶ。テトリミノはカラーで描画される。実行環境: python3.X, `pip install pygame`, Windows or Linux
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
import pygame | |
from pygame.locals import * | |
import numpy as np | |
import subprocess | |
class Color: | |
"""print文に色をつける | |
用例:print(f'赤:{Color.RED}これは赤色文字です{Color.RESET}') | |
参考:https://www.nomuramath.com/kv8wr0mp/ | |
""" | |
BLACK = '\033[30m' # (文字)黒 | |
RED = '\033[31m' # (文字)赤 | |
GREEN = '\033[32m' # (文字)緑 | |
YELLOW = '\033[33m' # (文字)黄 | |
BLUE = '\033[34m' # (文字)青 | |
MAGENTA = '\033[35m' # (文字)マゼンタ | |
CYAN = '\033[36m' # (文字)シアン | |
WHITE = '\033[37m' # (文字)白 | |
COLOR_DEFAULT = '\033[39m' # 文字色をデフォルトに戻す | |
BOLD = '\033[1m' # 太字 | |
UNDERLINE = '\033[4m' # 下線 | |
INVISIBLE = '\033[08m' # 不可視 | |
REVERCE = '\033[07m' # 文字色と背景色を反転 | |
BG_BLACK = '\033[40m' # (背景)黒 | |
BG_RED = '\033[41m' # (背景)赤 | |
BG_GREEN = '\033[42m' # (背景)緑 | |
BG_YELLOW = '\033[43m' # (背景)黄 | |
BG_BLUE = '\033[44m' # (背景)青 | |
BG_MAGENTA = '\033[45m' # (背景)マゼンタ | |
BG_CYAN = '\033[46m' # (背景)シアン | |
BG_WHITE = '\033[47m' # (背景)白 | |
BG_DEFAULT = '\033[49m' # 背景色をデフォルトに戻す | |
RESET = '\033[0m' # 全てリセット | |
class Tetris(object): | |
def __init__(self): | |
pygame.init() | |
pygame.display.set_mode((1, 1)) | |
print("") # pygame text | |
self.board_size = [20, 10] | |
self.mino_col = {1: Color.BG_CYAN, | |
2: Color.BG_YELLOW, | |
3: Color.BG_MAGENTA, | |
4: Color.BG_BLUE, | |
5: Color.BG_DEFAULT, | |
6: Color.BG_GREEN, | |
7: Color.BG_RED, | |
" ": Color.COLOR_DEFAULT} | |
self.init_t4mino() | |
self.init_board() | |
self.gen_t4mino() | |
def init_board(self): | |
"""ボードを初期化する | |
""" | |
self.board = np.zeros(self.board_size, dtype=np.int) | |
def init_t4mino(self): | |
"""テトリミノを初期化する | |
""" | |
# including rotation table | |
self.t4mino_li = [ | |
# i | |
[[[1, i] for i in range(4)], | |
[[i, 1] for i in range(4)]] * 2, | |
# o | |
[[[0, 0], [0, 1], [1, 0], [1, 1]]] * 4, | |
# t | |
[[[0, 1]] + [[1, i] for i in range(3)], | |
[[1, 2]] + [[i, 1] for i in range(3)], | |
[[2, 1]] + [[1, i] for i in range(3)], | |
[[1, 0]] + [[i, 1] for i in range(3)]], | |
# j | |
[[[0, 0]] + [[1, i] for i in range(3)], | |
[[0, 2]] + [[i, 1] for i in range(3)], | |
[[2, 2]] + [[1, i] for i in range(3)], | |
[[2, 0]] + [[i, 1] for i in range(3)]], | |
# l | |
[[[0, 2]] + [[1, i] for i in range(3)], | |
[[2, 2]] + [[i, 1] for i in range(3)], | |
[[2, 0]] + [[1, i] for i in range(3)], | |
[[0, 0]] + [[i, 1] for i in range(3)]], | |
# s | |
[[[0, 1], [0, 2], [1, 0], [1, 1]], | |
[[0, 0], [1, 0], [1, 1], [2, 1]]] * 2, | |
# z | |
[[[0, 0], [0, 1], [1, 1], [1, 2]], | |
[[0, 1], [1, 0], [1, 1], [2, 0]]] * 2 | |
] | |
def game(self): | |
"""ゲームのメイン部分 | |
30 fps -> 1 frame: 33 ms | |
""" | |
print("H:Left,L:Right,F/A:Rotate") | |
print("Type Command: ") | |
while self.yet(): | |
pygame.time.wait(300) | |
self.display() | |
_pt = self.pt.copy() | |
key = self.get_key_input() | |
self.move(key) | |
self.move() # テトリミノを1個下げる | |
if _pt == self.pt: | |
self.save_board() | |
self.gen_t4mino() | |
print('END') | |
def yet(self) -> bool: | |
"""ゲームの終了条件 | |
""" | |
mid = self.board_size[1] // 2 | |
if (self.board[0, mid-2:mid+2] == 0).all(): | |
return True | |
return False | |
def save_board(self): | |
"""ボードを保存する | |
""" | |
pt = self.pt | |
for ix in self.t4mino_li[self.cur][self.rot]: | |
self.board[ix[0]+pt[0], ix[1]+pt[1]] = self.cur + 1 | |
# flush | |
for i in range(self.board_size[0]): | |
if (self.board[i] != 0).all(): | |
for i_ in reversed(range(i)): | |
self.board[i_+1] = self.board[i_] | |
def element(self, i: int, j: int) -> str: | |
"""ボードに表示する要素 | |
""" | |
ix_li = self.t4mino_li[self.cur][self.rot] | |
pt = self.pt | |
for ix in ix_li: | |
if ix[0]+pt[0] == i and ix[1]+pt[1] == j: | |
return self.cur + 1 | |
tmp = self.board[i, j] | |
return ' ' if tmp == 0 else tmp | |
def display(self): | |
"""ボードの表示 | |
""" | |
ix_li = self.t4mino_li[self.cur][self.rot] | |
pt = self.pt | |
for i in range(self.board_size[0]): | |
print('{:>2}|'.format(i), end='') | |
for j in range(self.board_size[1]): | |
e = self.element(i, j) | |
print(self.mino_col[e], end='') | |
print(e, end='') | |
print(Color.RESET, end='') | |
print('|') | |
print('--+' + '-' * self.board_size[1] + '+') | |
print("\033[{}A".format(self.board_size[0]+2), end="") | |
print("\r", sep="") | |
def get_key_input(self) -> str: | |
key = "" | |
for event in pygame.event.get(): | |
# キーを押したとき | |
if event.type == KEYDOWN: | |
if event.key == K_ESCAPE: | |
key = "escape" | |
if event.key == K_LEFT: | |
key = "h" | |
if event.key == K_RIGHT: | |
key = "l" | |
if event.key == K_UP: | |
key = "f" | |
if event.key == K_DOWN: | |
key = "a" | |
return key | |
def move(self, to: str = ' ') -> bool: | |
"""テトリミノの移動や回転をする | |
""" | |
pt = self.pt | |
# left | |
if to == 'h': | |
q_li = [pt[0], pt[1]-1, self.rot] | |
# right | |
elif to == 'l': | |
q_li = [pt[0], pt[1]+1, self.rot] | |
# rotate right | |
elif to == 'f': | |
q_li = [pt[0], pt[1], (self.rot+1) % 4] | |
# rotate left | |
elif to == 'a': | |
q_li = [pt[0], pt[1], (self.rot-1) % 4] | |
# down | |
else: | |
q_li = [pt[0]+1, pt[1], self.rot] | |
for ix in self.t4mino_li[self.cur][q_li[-1]]: | |
if ix[0]+q_li[0] >= self.board_size[0] \ | |
or ix[1]+q_li[1] < 0 \ | |
or ix[1]+q_li[1] >= self.board_size[1] \ | |
or self.board[ix[0]+q_li[0], ix[1]+q_li[1]] != 0: | |
return False | |
pt[0], pt[1], self.rot = q_li | |
return True | |
def gen_t4mino(self): | |
"""テトリミノを生成する | |
""" | |
self.cur = np.random.randint(7) | |
# i, otjlst | |
self.pt = [0, self.board_size[1] // 2 - (2 if self.cur == 0 else 1)] | |
self.pt = [0, self.board_size[1] // 2 - 1] | |
self.rot = 0 | |
if __name__ == '__main__': | |
# Windows の場合 | |
subprocess.run('cls', shell=True) # terminalの出力をすべて消去 | |
# Linux の場合 | |
# subprocess.run('clear') # terminalの出力をすべて消去 | |
t = Tetris() | |
t.game() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
プレイの様子
