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


import pygame as pg
import random
import time
import sys
from pygame.locals import *

fps = 25
window_w, window_h = 600, 500
block = 20
cup_h = 20
cup_w = 10
side_freq = 0.15
down_freq = 0.1
side_margin = int((window_w - cup_w * block) / 2)
top_margin = window_h - (cup_h * block) - 5

empty = 0

figures = {
    'O': [['oooo', 'oooo', 'oxxo', 'oxxo', 'oooo']],
    'I': [
        ['oooo', 'oooo', 'xxxx', 'oooo', 'oooo'],
        ['ooxo', 'ooxo', 'ooxo', 'ooxo', 'oooo']
    ],
    'T': [
        ['oooo', 'oooo', 'oxxo', 'xxo', 'oooo'],
        ['oooo', 'oxo', 'xxo', 'oxo', 'oooo'],
        ['oooo', 'oxx', 'oxo', 'oooo', 'oooo'],
        ['oooo', 'oxo', 'oxx', 'oxo', 'oooo']
    ],
    'S': [
        ['oooo', 'oooo', 'oxx', 'xxo', 'oooo'],
        ['oooo', 'oxo', 'oxx', 'oox', 'oooo']
    ],
    'Z': [
        ['oooo', 'oooo', 'xxo', 'oxx', 'oooo'],
        ['oooo', 'oox', 'oxx', 'oxo', 'oooo']
    ],
    'L': [
        ['oooo', 'oooo', 'oxxx', 'oxo', 'oooo'],
        ['oooo', 'oxo', 'oxo', 'oxx', 'oooo'],
        ['oooo', 'oox', 'oxxx', 'oooo', 'oooo'],
        ['oooo', 'xxo', 'oxo', 'oxo', 'oooo']
    ],
    'J': [
        ['oooo', 'oooo', 'oxxx', 'oox', 'oooo'],
        ['oooo', 'oxo', 'oxo', 'xxo', 'oooo'],
        ['oooo', 'xoo', 'oxxx', 'oooo', 'oooo'],
        ['oooo', 'oxx', 'oxo', 'oxo', 'oooo']
    ]
}

colors = {
    'O': (255, 255, 0),
    'I': (0, 255, 255),
    'T': (128, 0, 128),
    'S': (0, 255, 0),
    'Z': (255, 0, 0),
    'L': (255, 165, 0),
    'J': (0, 0, 255)
}
lightcolors = {
    'O': (255, 255, 150),
    'I': (150, 255, 255),
    'T': (200, 100, 200),
    'S': (150, 255, 150),
    'Z': (255, 150, 150),
    'L': (255, 200, 100),
    'J': (100, 100, 255)
}
bg_color = (0, 0, 0)
fig_w, fig_h = 5, 5

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)
small_font = pg.font.Font(None, 24)
pg.display.set_caption('Тетрис')

try:
    start_sound = pg.mixer.Sound('start.wav')
    move_sound = pg.mixer.Sound('move.wav')
    gameover_sound = pg.mixer.Sound('gameover.wav')
    pg.mixer.music.load('bg_music.mp3')
    pg.mixer.music.set_volume(0.5)
    sound_enabled = True
except:
    sound_enabled = False

def showText(text, font=big_font, color=(255,255,255), y_offset=0):
    text_surf = font.render(text, True, color)
    text_rect = text_surf.get_rect()
    text_rect.center = (window_w // 2, window_h // 2 + y_offset)
    display_surf.blit(text_surf, text_rect)

def drawButton(text, x, y, w, h, color, text_color):
    pg.draw.rect(display_surf, color, (x, y, w, h))
    pg.draw.rect(display_surf, (255,255,255), (x, y, w, h), 2)
    surf = small_font.render(text, True, text_color)
    rect = surf.get_rect(center=(x + w//2, y + h//2))
    display_surf.blit(surf, rect)
    return pg.Rect(x, y, w, h)

def getPlayerName():
    name = ""
    active = True
    while active:
        display_surf.fill(bg_color)
        showText("Введите имя:", big_font, (255,255,255), -50)
        name_surf = basic_font.render(name + "_", True, (255,255,255))
        name_rect = name_surf.get_rect(center=(window_w//2, window_h//2))
        display_surf.blit(name_surf, name_rect)
        pg.display.update()
        for event in pg.event.get():
            if event.type == QUIT:
                pg.quit()
                sys.exit()
            if event.type == KEYDOWN:
                if event.key == K_RETURN and name.strip() != "":
                    active = False
                elif event.key == K_BACKSPACE:
                    name = name[:-1]
                elif event.key == K_ESCAPE:
                    pg.quit()
                    sys.exit()
                else:
                    if len(name) < 15 and event.unicode.isprintable():
                        name += event.unicode
    return name.strip()

def chooseDifficulty():
    difficulties = ["Легкая", "Средняя", "Сложная"]
    selected = 0
    while True:
        display_surf.fill(bg_color)
        showText("Выбери сложность:", big_font, (255,255,255), -100)
        for i, diff in enumerate(difficulties):
            color = (255,255,0) if i == selected else (255,255,255)
            y = window_h//2 - 30 + i * 50
            showText(diff, big_font, color, y - window_h//2)
        pg.display.update()
        for event in pg.event.get():
            if event.type == QUIT:
                pg.quit()
                sys.exit()
            if event.type == KEYDOWN:
                if event.key == K_UP:
                    selected = (selected - 1) % 3
                elif event.key == K_DOWN:
                    selected = (selected + 1) % 3
                elif event.key == K_RETURN:
                    if selected == 0:
                        return 0.5
                    elif selected == 1:
                        return 0.8
                    else:
                        return 1.2

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

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

def drawBlock(block_x, block_y, color, pixelx=None, pixely=None):
    if color == empty or color is None:
        return
    if pixelx is None and pixely is None:
        pixelx, pixely = convertCoords(block_x, block_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 emptycup():
    return [[empty for _ in range(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):
    for x in range(fig_w):
        for y in range(fig_h):
            if figures[fig['shape']][fig['rotation']][y][x] != 'o':
                if not incup(x + fig['x'] + adjX, y + fig['y'] + adjY):
                    return False
                if cup[x + fig['x'] + adjX][y + fig['y'] + adjY] != empty:
                    return False
    return True

def addToCup(cup, fig):
    for x in range(fig_w):
        for y in range(fig_h):
            if figures[fig['shape']][fig['rotation']][y][x] != 'o':
                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 push in range(y, 0, -1):
                for x in range(cup_w):
                    cup[x][push] = cup[x][push-1]
            for x in range(cup_w):
                cup[x][0] = empty
            removed += 1
        else:
            y -= 1
    return removed

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 drawFig(fig):
    for x in range(fig_w):
        for y in range(fig_h):
            if figures[fig['shape']][fig['rotation']][y][x] != 'o':
                drawBlock(fig['x'] + x, fig['y'] + y, fig['color'])

def drawnextFig(fig):
    surf = pg.Surface((100, 100))
    surf.fill(bg_color)
    start_x, start_y = window_w - 100, 100
    for x in range(fig_w):
        for y in range(fig_h):
            if figures[fig['shape']][fig['rotation']][y][x] != 'o':
                pixelx = start_x + x * 15
                pixely = start_y + y * 15
                pg.draw.rect(surf, colors[fig['color']], (pixelx - (window_w-100) + 1, pixely-100 + 1, 13, 13), 0, 2)
                pg.draw.rect(surf, lightcolors[fig['color']], (pixelx - (window_w-100) + 1, pixely-100 + 1, 9, 9), 0, 2)
    display_surf.blit(surf, (window_w-100, 100))

def drawInfo(points, level):
    showText(f"Счёт: {points}", basic_font, (255,255,255), -180)
    showText(f"Уровень: {level}", basic_font, (255,255,255), -150)
    showText("Следующая:", basic_font, (255,255,255), -220)

def drawTitle():
    showText("ТЕТРИС", big_font, (255,255,0), -230)

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

def calcSpeed(points):
    level = points // 10 + 1
    speed = max(0.1, 0.8 - (level - 1) * 0.05)
    return level, speed

def pauseScreen():
    pause = True
    while pause:
        for event in pg.event.get():
            if event.type == QUIT:
                stopGame()
            if event.type == KEYDOWN:
                if event.key == K_SPACE:
                    pause = False
                if event.key == K_ESCAPE:
                    stopGame()
        s = pg.Surface((window_w, window_h), pg.SRCALPHA)
        s.fill((0, 0, 255, 100))
        display_surf.blit(s, (0, 0))
        showText("Пауза. Пробел - продолжить", basic_font, (255,255,255), 0)
        pg.display.update()
        fps_clock.tick(fps)

def runTetris(speed_factor, 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)
    fall_speed = max(0.05, fall_speed * speed_factor)
    fallingFig = getNewFig()
    nextFig = getNewFig()
    move_repeat_delay = 0.1

    if sound_enabled:
        pg.mixer.music.play(-1)

    while True:
        if fallingFig is None:
            fallingFig = nextFig
            nextFig = getNewFig()
            last_fall = time.time()
            if not checkPos(cup, fallingFig):
                if sound_enabled:
                    pg.mixer.music.stop()
                    gameover_sound.play()
                return points

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

        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
            elif going_right and checkPos(cup, fallingFig, adjX=1):
                fallingFig['x'] += 1
            last_side_move = time.time()

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

        if time.time() - last_fall > fall_speed:
            if not checkPos(cup, fallingFig, adjY=1):
                addToCup(cup, fallingFig)
                removed = clearCompleted(cup)
                points += removed * 10
                level, new_speed = calcSpeed(points)
                fall_speed = max(0.05, new_speed * speed_factor)
                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 main():
    player_name = getPlayerName()
    speed_factor = chooseDifficulty()
    if sound_enabled:
        start_sound.play()
        time.sleep(0.5)
    final_score = runTetris(speed_factor, player_name)
    if sound_enabled:
        pg.mixer.music.stop()
        gameover_sound.play()
    while True:
        display_surf.fill(bg_color)
        showText("ИГРА ЗАКОНЧЕНА", big_font, (255,0,0), -80)
        showText(f"{player_name}, твой счёт: {final_score}", big_font, (255,255,0), -20)
        showText("Нажми R для повтора или ESC для выхода", basic_font, (255,255,255), 60)
        pg.display.update()
        for event in pg.event.get():
            if event.type == QUIT:
                stopGame()
            if event.type == KEYDOWN:
                if event.key == K_ESCAPE:
                    stopGame()
                if event.key == K_r:
                    main()
                    return

if __name__ == '__main__':
    main()