import sys
import time
import random

# myCompiler環境(CUI)の制約に対応するためcursesを使用
try:
    import curses
except ImportError:
    print("この環境ではcursesライブラリがサポートされていないか、ターミナル環境が必要です。")
    sys.exit()

# ゲームボードのサイズ
BOARD_WIDTH = 10
BOARD_HEIGHT = 20

# テトロミノ(ブロック)の形状定義
SHAPES = {
    'I': [[1, 1, 1, 1]],
    'O': [[1, 1], [1, 1]],
    'T': [[0, 1, 0], [1, 1, 1]],
    'S': [[0, 1, 1], [1, 1, 0]],
    'Z': [[1, 1, 0], [0, 1, 1]],
    'J': [[1, 0, 0], [1, 1, 1]],
    'L': [[0, 0, 1], [1, 1, 1]]
}

class Tetris:
    def __init__(self):
        self.board = [[0] * BOARD_WIDTH for _ in range(BOARD_HEIGHT)]
        self.score = 0
        self.game_over = False
        self.new_piece()

    def new_piece(self):
        self.current_shape = random.choice(list(SHAPES.values()))
        self.piece_y = 0
        self.piece_x = BOARD_WIDTH // 2 - len(self.current_shape[0]) // 2
        if self.check_collision(self.piece_y, self.piece_x, self.current_shape):
            self.game_over = True

    def check_collision(self, dy, dx, shape):
        for y, row in enumerate(shape):
            for x, val in enumerate(row):
                if val:
                    ny, nx = dy + y, dx + x
                    if nx < 0 or nx >= BOARD_WIDTH or ny >= BOARD_HEIGHT:
                        return True
                    if ny >= 0 and self.board[ny][nx]:
                        return True
        return False

    def lock_piece(self):
        for y, row in enumerate(self.current_shape):
            for x, val in enumerate(row):
                if val:
                    self.board[self.piece_y + y][self.piece_x + x] = 1
        self.clear_lines()
        self.new_piece()

    def clear_lines(self):
        new_board = [row for row in self.board if not all(row)]
        lines_cleared = BOARD_HEIGHT - len(new_board)
        self.score += lines_cleared * 100
        while len(new_board) < BOARD_HEIGHT:
            new_board.insert(0, [0] * BOARD_WIDTH)
        self.board = new_board

    def move(self, dy, dx):
        if not self.check_collision(self.piece_y + dy, self.piece_x + dx, self.current_shape):
            self.piece_y += dy
            self.piece_x += dx
            return True
        if dy > 0:
            self.lock_piece()
        return False

    def rotate(self):
        # 行列を時計回りに回転
        rotated = [list(x) for x in zip(*self.current_shape[::-1])]
        if not self.check_collision(self.piece_y, self.piece_x, rotated):
            self.current_shape = rotated

def draw_game(stdscr, game):
    stdscr.clear()
    
    # スコア表示
    stdscr.addstr(0, 0, f"SCORE: {game.score}")
    stdscr.addstr(1, 0, "Controls: [A]Left [D]Right [S]Down [W]Rotate [Q]Quit")
    
    # 描画用のバッファ作成
    display_board = [row[:] for row in game.board]
    for y, row in enumerate(game.current_shape):
        for x, val in enumerate(row):
            if val and (game.piece_y + y) < BOARD_HEIGHT:
                display_board[game.piece_y + y][game.piece_x + x] = 2

    # 枠とボードの描画
    stdscr.addstr(2, 0, "+" + "-" * (BOARD_WIDTH * 2) + "+")
    for y in range(BOARD_HEIGHT):
        line = "|"
        for x in range(BOARD_WIDTH):
            if display_board[y][x] == 0:
                line += "  "
            else:
                line += "[]"
        line += "|"
        stdscr.addstr(3 + y, 0, line)
    stdscr.addstr(3 + BOARD_HEIGHT, 0, "+" + "-" * (BOARD_WIDTH * 2) + "+")
    
    if game.game_over:
        stdscr.addstr(BOARD_HEIGHT // 2 + 2, BOARD_WIDTH - 4, "GAME OVER", curses.A_BOLD)
    
    stdscr.refresh()

def main(stdscr):
    # 初期設定
    curses.curs_set(0)
    stdscr.nodelay(True)
    stdscr.timeout(100)
    
    game = Tetris()
    last_drop = time.time()
    drop_interval = 0.5 # ブロックが落ちる速度(秒)

    while not game.game_over:
        draw_game(stdscr, game)
        
        # キー入力処理
        try:
            key = stdscr.getch()
        except Exception:
            key = -1

        if key == ord('q') or key == ord('Q'):
            break
        elif key == ord('a') or key == ord('A'):
            game.move(0, -1)
        elif key == ord('d') or key == ord('D'):
            game.move(0, 1)
        elif key == ord('s') or key == ord('S'):
            game.move(1, 0)
        elif key == ord('w') or key == ord('W'):
            game.rotate()

        # 時間経過による自動落下
        if time.time() - last_drop > drop_interval:
            game.move(1, 0)
            last_drop = time.time()

    # ゲームオーバー時の最終画面表示
    draw_game(stdscr, game)
    time.sleep(3)

if __name__ == '__main__':
    curses.wrapper(main)

Embed on website

To embed this project on your website, copy the following code and paste it into your website's HTML: