Загрузка данных


import pygame as pg
import random
import sys
import time
import pygame_menu
from pygame_menu import themes

try:
    pg.mixer.init()
    sound_start = pg.mixer.Sound("start.wav")
    sound_gameover = pg.mixer.Sound("gameover.wav")
    sound_move = pg.mixer.Sound("move.wav")
    sound_rotate = pg.mixer.Sound("rotate.wav")
    sound_drop = pg.mixer.Sound("drop.wav")
except:
    sound_start = sound_gameover = sound_move = sound_rotate = sound_drop = None

fps = 25
window_w, window_h = 600, 500
block, cup_h, cup_w = 20, 20, 10
side_margin = int((window_w - cup_w * block) / 2)
top_margin = window_h - (cup_h * block) - 5
fig_w, fig_h = 5, 5
empty = 'o'

colors = (
    (0, 0, 0),
    (255, 0, 0),
    (0, 150, 0),
    (0, 0, 255),
    (255, 120, 0),
    (255, 255, 0),
    (180, 0, 255),
    (0, 220, 220)
)
lightcolors = (
    (0, 0, 0),
    (255, 120, 120),
    (120, 255, 120),
    (120, 120, 255),
    (255, 200, 120),
    (255, 255, 120),
    (220, 120, 255),
    (120, 220, 220)
)
bg_color = (30, 30, 40)

figures = {
    'O': [['oooo', 'oooo', 'oxxo', 'oxxo', 'oooo']],
    'I': [['oooo', 'oxxxo', 'oxxxo', 'oxxxo', 'oooo'], ['oooo', 'oooox', 'oooox', 'oooox', 'oooo']],
    'S': [['oooo', 'oxxo', 'oxxo', 'oxxo', 'oooo']],
    'Z': [['oooo', 'oxxo', 'oxxo', 'oxxo', 'oooo']],
    'L': [['oooo', 'oxxx', 'oxxx', 'oxxx', 'oooo']],
    'J': [['oooo', 'oxxx', 'oxxx', 'oxxx', 'oooo']],
    'T': [['oooo', 'oxxx', 'oxxx', 'oxxx', 'oooo']]
}

figures = {
    'O': [[list('oooo'), list('oooo'), list('oxxo'), list('oxxo'), list('oooo')]],
    'I': [
        [list('oooo'), list('oxxx'), list('oxxx'), list('oxxx'), list('oooo')],
        [list('oooo'), list('oooox'), list('oooox'), list('oooox'), list('oooo')]
    ],
    'S': [
        [list('oooo'), list('oxxo'), list('oxxo'), list('oxxo'), list('oooo')]
    ],
    'Z': [
        [list('oooo'), list('oxxo'), list('oxxo'), list('oxxo'), list('oooo')]
    ],
    'L': [
        [list('oooo'), list('oxxx'), list('oxxx'), list('oxxx'), list('oooo')]
    ],
    'J': [
        [list('oooo'), list('oxxx'), list('oxxx'), list('oxxx'), list('oooo')]
    ],
    'T': [
        [list('oooo'), list('oxxx'), list('oxxx'), list('oxxx'), list('oooo')]
    ]
}

for shape in ('S', 'Z', 'L', 'J', 'T'):
    base = figures[shape][0]
    rot = []
    for _ in range(4):
        rot.append(base)
    figures[shape] = rot

def getNewFig():
    shape = random.choice(list(figures.keys()))
    rotation = 0
    color = list(figures.keys()).index(shape) + 1
    fig = {'shape': shape, 'rotation': rotation, 'color': color, 'x': cup_w // 2 - 2, 'y': -2}
    return fig

def emptycup():
    return [[empty] * cup_h for _ in range(cup_w)]

def incup(x, y):
    return 0 <= x < cup_w and 0 <= y < cup_h

def checkPos(cup, fig, adjX=0, adjY=0):
    shape_data = figures[fig['shape']][fig['rotation']]
    for x in range(fig_w):
        for y in range(fig_h):
            if shape_data[y][x] == 'x':
                cx = x + fig['x'] + adjX
                cy = y + fig['y'] + adjY
                if not incup(cx, cy):
                    return False
                if cup[cx][cy] != empty:
                    return False
    return True

def addToCup(cup, fig):
    shape_data = figures[fig['shape']][fig['rotation']]
    for x in range(fig_w):
        for y in range(fig_h):
            if shape_data[y][x] == 'x':
                cup[x + fig['x']][y + fig['y']] = fig['color']

def isCompleted(cup, y):
    for x in range(cup_w):
        if cup[x][y] == empty:
            return False
    return True

def clearCompleted(cup):
    removed = 0
    y = cup_h - 1
    while y >= 0:
        if isCompleted(cup, y):
            for pushY in range(y, 0, -1):
                for x in range(cup_w):
                    cup[x][pushY] = cup[x][pushY-1]
            for x in range(cup_w):
                cup[x][0] = empty
            removed += 1
        else:
            y -= 1
    return removed

def calcSpeed(points):
    level = points // 10 + 1
    fall_speed = max(0.05, 0.5 - (level-1)*0.03)
    return level, fall_speed

def convertCoords(x, y):
    return side_margin + x * block, top_margin + y * block

def drawBlock(x, y, color, pixelx=None, pixely=None):
    if color == empty:
        return
    if pixelx is None:
        pixelx, pixely = convertCoords(x, y)
    pg.draw.rect(display_surf, colors[color], (pixelx+1, pixely+1, block-1, block-1), 0, 3)
    pg.draw.rect(display_surf, lightcolors[color], (pixelx+1, pixely+1, block-4, block-4), 0, 3)
    pg.draw.circle(display_surf, colors[color], (pixelx+block//2, pixely+block//2), 5)

def drawFig(fig):
    shape_data = figures[fig['shape']][fig['rotation']]
    for x in range(fig_w):
        for y in range(fig_h):
            if shape_data[y][x] == 'x':
                drawBlock(x + fig['x'], y + fig['y'], fig['color'])

def gamecup(cup):
    for x in range(cup_w):
        for y in range(cup_h):
            if cup[x][y] != empty:
                drawBlock(x, y, cup[x][y])

def drawnextFig(fig):
    title = basic_font.render("Следующая:", True, (255,255,200))
    display_surf.blit(title, (window_w - 150, 50))
    shape_data = figures[fig['shape']][fig['rotation']]
    start_x = window_w - 130
    start_y = 100
    for x in range(fig_w):
        for y in range(fig_h):
            if shape_data[y][x] == 'x':
                px = start_x + x * (block-2)
                py = start_y + y * (block-2)
                drawBlock(0,0,fig['color'], pixelx=px, pixely=py)

def drawInfo(points, level):
    txt = basic_font.render(f"Очки: {points}", True, (255,255,200))
    display_surf.blit(txt, (window_w - 150, 250))
    txt = basic_font.render(f"Уровень: {level}", True, (255,255,200))
    display_surf.blit(txt, (window_w - 150, 280))

def drawTitle():
    title = big_font.render("ТЕТРИС", True, (220,220,255))
    display_surf.blit(title, (side_margin + cup_w*block//2 - title.get_width()//2, 10))

def showText(text):
    surf = big_font.render(text, True, (255,100,100))
    rect = surf.get_rect(center=(window_w//2, window_h//2))
    display_surf.blit(surf, rect)
    pg.display.update()
    time.sleep(2)

def pauseScreen():
    pause = pg.Surface((window_w, window_h), pg.SRCALPHA)
    pause.fill((0,0,255,127))
    display_surf.blit(pause, (0,0))
    pg.display.update()
    waiting = True
    while waiting:
        for e in pg.event.get():
            if e.type == pg.KEYDOWN:
                if e.key == pg.K_SPACE:
                    waiting = False
            if e.type == pg.QUIT:
                sys.exit()

def stopGame():
    pg.quit()
    sys.exit()

def runTetris(player_name):
    cup = emptycup()
    last_move_down = time.time()
    last_side_move = time.time()
    last_fall = time.time()
    going_down = False
    going_left = False
    going_right = False
    points = 0
    level, fall_speed = calcSpeed(points)
    fallingFig = getNewFig()
    nextFig = getNewFig()
    side_freq = 0.15
    down_freq = 0.1

    if sound_start:
        sound_start.play()

    while True:
        if fallingFig is None:
            fallingFig = nextFig
            nextFig = getNewFig()
            last_fall = time.time()
            if not checkPos(cup, fallingFig):
                if sound_gameover:
                    sound_gameover.play()
                return points

        for event in pg.event.get():
            if event.type == pg.QUIT:
                stopGame()
            if event.type == pg.KEYDOWN:
                if event.key == pg.K_SPACE:
                    pauseScreen()
                elif event.key == pg.K_LEFT:
                    if checkPos(cup, fallingFig, adjX=-1):
                        fallingFig['x'] -= 1
                        if sound_move: sound_move.play()
                    going_left = True
                    going_right = False
                    last_side_move = time.time()
                elif event.key == pg.K_RIGHT:
                    if checkPos(cup, fallingFig, adjX=1):
                        fallingFig['x'] += 1
                        if sound_move: sound_move.play()
                    going_right = True
                    going_left = False
                    last_side_move = time.time()
                elif event.key == pg.K_UP:
                    old_rot = fallingFig['rotation']
                    fallingFig['rotation'] = (fallingFig['rotation'] + 1) % len(figures[fallingFig['shape']])
                    if not checkPos(cup, fallingFig):
                        fallingFig['rotation'] = old_rot
                    else:
                        if sound_rotate: sound_rotate.play()
                elif event.key == pg.K_DOWN:
                    if checkPos(cup, fallingFig, adjY=1):
                        fallingFig['y'] += 1
                        last_move_down = time.time()
                        if sound_move: sound_move.play()
                    going_down = True
                elif event.key == pg.K_RETURN:
                    for i in range(1, cup_h):
                        if not checkPos(cup, fallingFig, adjY=i):
                            break
                    fallingFig['y'] += i - 1
                    if sound_drop: sound_drop.play()
                    going_down = False
                    going_left = False
                    going_right = False

            if event.type == pg.KEYUP:
                if event.key == pg.K_LEFT:
                    going_left = False
                elif event.key == pg.K_RIGHT:
                    going_right = False
                elif event.key == pg.K_DOWN:
                    going_down = False

        if (going_left or going_right) and time.time() - last_side_move > side_freq:
            if going_left and checkPos(cup, fallingFig, adjX=-1):
                fallingFig['x'] -= 1
                if sound_move: sound_move.play()
            elif going_right and checkPos(cup, fallingFig, adjX=1):
                fallingFig['x'] += 1
                if sound_move: sound_move.play()
            last_side_move = time.time()

        if going_down and time.time() - last_move_down > down_freq:
            if checkPos(cup, fallingFig, adjY=1):
                fallingFig['y'] += 1
                if sound_move: sound_move.play()
            last_move_down = time.time()

        if time.time() - last_fall > fall_speed:
            if not checkPos(cup, fallingFig, adjY=1):
                addToCup(cup, fallingFig)
                cleared = clearCompleted(cup)
                points += cleared
                level, fall_speed = calcSpeed(points)
                fallingFig = None
            else:
                fallingFig['y'] += 1
            last_fall = time.time()

        display_surf.fill(bg_color)
        drawTitle()
        gamecup(cup)
        drawInfo(points, level)
        drawnextFig(nextFig)
        if fallingFig is not None:
            drawFig(fallingFig)
        pg.display.update()
        fps_clock.tick(fps)

def game_loop(player_name, difficulty):
    global fps_clock, display_surf, basic_font, big_font
    pg.init()
    fps_clock = pg.time.Clock()
    display_surf = pg.display.set_mode((window_w, window_h))
    basic_font = pg.font.Font(None, 18)
    big_font = pg.font.Font(None, 45)
    pg.display.set_caption("Тетрис")
    score = runTetris(player_name)
    show_gameover(player_name, score)

def show_gameover(player_name, score):
    display_surf.fill(bg_color)
    msg1 = big_font.render("ИГРА ЗАКОНЧЕНА", True, (255,100,100))
    msg2 = basic_font.render(f"{player_name}, ваш счёт: {score}", True, (255,255,200))
    msg3 = basic_font.render("Нажмите любую клавишу для возврата в меню", True, (200,200,200))
    display_surf.blit(msg1, (window_w//2 - msg1.get_width()//2, window_h//2 - 60))
    display_surf.blit(msg2, (window_w//2 - msg2.get_width()//2, window_h//2))
    display_surf.blit(msg3, (window_w//2 - msg3.get_width()//2, window_h//2 + 50))
    pg.display.update()
    waiting = True
    while waiting:
        for e in pg.event.get():
            if e.type == pg.QUIT:
                sys.exit()
            if e.type == pg.KEYDOWN:
                waiting = False

def start_game():
    player_name = name_input.get_value()
    diff = difficulty.get_value()[0]
    speeds = {"Нормальная": 25, "Быстрая": 40, "Медленная": 15}
    global fps
    fps = speeds[diff]
    game_loop(player_name, diff)

def main_menu():
    global name_input, difficulty
    menu = pygame_menu.Menu("ТЕТРИС", window_w, window_h, theme=themes.THEME_DARK)
    name_input = menu.add.text_input("Имя игрока:", default="Игрок", maxchar=20)
    difficulty = menu.add.selector("Сложность:", [("Нормальная", 0), ("Быстрая", 1), ("Медленная", 2)])
    menu.add.button("СТАРТ", start_game)
    menu.add.button("ВЫХОД", pygame_menu.events.EXIT)
    menu.mainloop(display_surf)

if __name__ == "__main__":
    pg.init()
    display_surf = pg.display.set_mode((window_w, window_h))
    pg.display.set_caption("Тетрис")
    main_menu()
    pg.quit()