tak.lol
09 ноябрь 2024
8
0
Не нравится 0 Нравится

Код игры Тетрис на Python для исследования

Код игры "Тетрис" на Python, который мне любезно сгенерировал ChatGPT для изучения логики и смыслов.

Чтобы создать что-то новое, необходимо суметь повторить что-то старое. Это я сам придумал только что 😆


Код игры на Python



import tkinter as tk
import random

# Определяем размеры игрового поля и блоков
GRID_WIDTH = 10
GRID_HEIGHT = 20
BLOCK_SIZE = 30

# Определяем цвета для фигур
COLORS = ["cyan", "blue", "orange", "yellow", "green", "purple", "red"]

# Определяем фигуры
SHAPES = [
    [[1, 1, 1, 1]],  # I
    [[1, 1], [1, 1]],  # O
    [[0, 1, 0], [1, 1, 1]],  # T
    [[1, 0, 0], [1, 1, 1]],  # L
    [[0, 0, 1], [1, 1, 1]],  # J
    [[0, 1, 1], [1, 1, 0]],  # S
    [[1, 1, 0], [0, 1, 1]],  # Z
]

class Tetris:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("Тетрис")
        
        self.canvas = tk.Canvas(self.root, width=GRID_WIDTH * BLOCK_SIZE,
                                height=GRID_HEIGHT * BLOCK_SIZE)
        self.canvas.pack()
        
        self.score_label = tk.Label(self.root, text="Очки: 0")
        self.score_label.pack()
        
        self.board = [[0] * GRID_WIDTH for _ in range(GRID_HEIGHT)]
        self.current_piece = None
        self.current_color = None
        self.current_x = GRID_WIDTH // 2 - 1
        self.current_y = 0
        self.score = 0
        
        self.spawn_piece()
        self.update()
        self.root.bind("<Left>", self.move_left)
        self.root.bind("<Right>", self.move_right)
        self.root.bind("<Down>", self.move_down)
        self.root.bind("<Up>", self.rotate)
        
        self.root.mainloop()

    def spawn_piece(self):
        shape = random.choice(SHAPES)
        self.current_piece = shape
        self.current_color = random.choice(COLORS)
        self.current_x = GRID_WIDTH // 2 - len(shape[0]) // 2
        self.current_y = 0
        
        if not self.valid_move():
            print("Игра окончена!")
            self.root.quit()

    def valid_move(self):
        for y in range(len(self.current_piece)):
            for x in range(len(self.current_piece[y])):
                if (self.current_piece[y][x] and 
                    (self.current_x + x < 0 or 
                     self.current_x + x >= GRID_WIDTH or 
                     self.current_y + y >= GRID_HEIGHT or 
                     self.board[self.current_y + y][self.current_x + x])):
                    return False
        return True

    def merge(self):
        for y in range(len(self.current_piece)):
            for x in range(len(self.current_piece[y])):
                if self.current_piece[y][x]:
                    self.board[self.current_y + y][self.current_x + x] = self.current_color

    def clear_lines(self):
        lines_to_clear = []
        for y in range(GRID_HEIGHT):
            if all(self.board[y]):
                lines_to_clear.append(y)
        
        for y in lines_to_clear:
            del self.board[y]
            self.board.insert(0, [0] * GRID_WIDTH)
            self.score += 100
        
        self.score_label.config(text=f"Очки: {self.score}")

    def draw_board(self):
        self.canvas.delete(tk.ALL)
        
        for y in range(GRID_HEIGHT):
            for x in range(GRID_WIDTH):
                if self.board[y][x]:
                    color = self.board[y][x]
                    self.canvas.create_rectangle(x * BLOCK_SIZE,
                                                  y * BLOCK_SIZE,
                                                  (x + 1) * BLOCK_SIZE,
                                                  (y + 1) * BLOCK_SIZE,
                                                  fill=color, outline="black")
        
        # Рисуем текущую фигуру
        for y in range(len(self.current_piece)):
            for x in range(len(self.current_piece[y])):
                if self.current_piece[y][x]:
                    color = self.current_color
                    self.canvas.create_rectangle((self.current_x + x) * BLOCK_SIZE,
                                                  (self.current_y + y) * BLOCK_SIZE,
                                                  (self.current_x + x + 1) * BLOCK_SIZE,
                                                  (self.current_y + y + 1) * BLOCK_SIZE,
                                                  fill=color, outline="black")

    def drop(self):
        self.current_y += 1
        if not self.valid_move():
            self.current_y -= 1
            self.merge()
            self.clear_lines()
            self.spawn_piece()
        self.draw_board()

    def update(self):
        self.drop()
        self.root.after(1000, self.update)

    def move_left(self, event):
        self.current_x -= 1
        if not self.valid_move():
            self.current_x += 1
        self.draw_board()

    def move_right(self, event):
        self.current_x += 1
        if not self.valid_move():
            self.current_x -= 1
        self.draw_board()

    def move_down(self, event):
        self.drop()

    def rotate(self, event):
        rotated_shape = list(zip(*self.current_piece[::-1]))
        original_piece = self.current_piece
        self.current_piece = rotated_shape
        
        if not self.valid_move():
            self.current_piece = original_piece
        
        self.draw_board()

if __name__ == "__main__":
    Tetris()
 

Код игры Тетрис на Python для исследования
А теперь детали:
Давай подробно разберем каждую часть кода для игры в Тетрис на Python с использованием библиотеки Tkinter. Я буду объяснять, что делает каждая строчка, чтобы вы могли лучше понять, как работает эта игра.

import tkinter as tk
import random


• Импортируем библиотеку tkinter, которая используется для создания графического интерфейса, и библиотеку random, которая поможет нам случайным образом выбирать фигуры.

GRID_WIDTH = 10
GRID_HEIGHT = 20
BLOCK_SIZE = 30


• Определяем размеры игрового поля: ширина (GRID_WIDTH) и высота (GRID_HEIGHT) в клетках, а также размер каждой клетки (BLOCK_SIZE) в пикселях.

COLORS = ["cyan", "blue", "orange", "yellow", "green", "purple", "red"]


• Создаем список цветов, которые будут использоваться для различных фигур в игре.

SHAPES = [
    [[1, 1, 1, 1]],  # I
    [[1, 1], [1, 1]],  # O
    [[0, 1, 0], [1, 1, 1]],  # T
    [[1, 0, 0], [1, 1, 1]],  # L
    [[0, 0, 1], [1, 1, 1]],  # J
    [[0, 1, 1], [1, 1, 0]],  # S
    [[1, 1, 0], [0, 1, 1]],  # Z
]

• Определяем фигуры Тетриса в виде списков. Каждая фигура представлена в виде двумерного массива (списка списков), где 1 обозначает часть фигуры, а 0 — пустое пространство. Комментарии указывают на тип фигуры.

class Tetris:


• Определяем класс Tetris, который будет содержать всю логику игры и графический интерфейс.

    def __init__(self):
        self.root = tk.Tk()
        self.root.title("Тетрис")



• Конструктор класса Tetris. Создаем главное окно приложения с помощью tk.Tk() и устанавливаем заголовок окна на "Тетрис".

        self.canvas = tk.Canvas(self.root, width=GRID_WIDTH * BLOCK_SIZE,
                                height=GRID_HEIGHT * BLOCK_SIZE)
        self.canvas.pack()


• Создаем холст (Canvas), на котором будет рисоваться игровое поле. Устанавливаем его ширину и высоту, умножая количество клеток на размер каждой клетки. Затем добавляем холст в главное окно с помощью метода pack().

        self.score_label = tk.Label(self.root, text="Очки: 0")
        self.score_label.pack()


• Создаем метку (Label) для отображения текущего счета игрока и добавляем ее в главное окно.

        self.board = [[0] * GRID_WIDTH for _ in range(GRID_HEIGHT)]


• Инициализируем игровое поле (board) в виде двумерного списка (списка списков), заполненного нулями. Это будет представлять собой пустое поле.

        self.current_piece = None
        self.current_color = None
        self.current_x = GRID_WIDTH // 2 - 1
        self.current_y = 0
        self.score = 0



• Инициализируем переменные для текущей фигуры (current_piece), ее цвета (current_color), координат фигуры на поле (current_x, current_y) и начального счета (score).

        self.spawn_piece()



• Вызываем метод spawn_piece(), чтобы создать новую фигуру в начале игры.

        self.update()



• Запускаем метод update(), который будет обновлять состояние игры.

        self.root.bind("<Left>", self.move_left)
        self.root.bind("<Right>", self.move_right)
        self.root.bind("<Down>", self.move_down)
        self.root.bind("<Up>", self.rotate)



• Привязываем клавиши управления к соответствующим методам. Теперь при нажатии стрелок на клавиатуре будут вызываться методы для перемещения и вращения фигур.

        self.root.mainloop()



• Запускаем главный цикл приложения Tkinter. Это позволяет окну оставаться открытым и обрабатывать события.

Методы класса Tetris



Метод spawn_piece

    def spawn_piece(self):
        shape = random.choice(SHAPES)
        self.current_piece = shape
        self.current_color = random.choice(COLORS)
        self.current_x = GRID_WIDTH // 2 - len(shape[0]) // 2
        self.current_y = 0

• Этот метод создает новую фигуру. Мы случайным образом выбираем фигуру из списка SHAPES и цвет из списка COLORS. Устанавливаем начальные координаты фигуры так, чтобы она появлялась в верхней части экрана по центру.

        if not self.valid_move():
            print("Игра окончена!")
            self.root.quit()



• Проверяем, можно ли разместить новую фигуру на игровом поле. Если нет — выводим сообщение об окончании игры и закрываем приложение.

Метод valid_move

    def valid_move(self):
        for y in range(len(self.current_piece)):
            for x in range(len(self.current_piece[y])):
                if (self.current_piece[y][x] and 
                    (self.current_x + x < 0 or 
                     self.current_x + x >= GRID_WIDTH or 
                     self.current_y + y >= GRID_HEIGHT or 
                     self.board[self.current_y + y][self.current_x + x])):
                    return False
        return True



• Этот метод проверяет, можно ли переместить текущую фигуру на заданные координаты. Мы проходим по всем частям фигуры и проверяем:

• Не выходит ли фигура за границы игрового поля.

• Не пересекается ли она с уже занятыми клетками на поле.

• Если хотя бы одно условие не выполняется — возвращаем False, иначе — True.

Метод merge

    def merge(self):
        for y in range(len(self.current_piece)):
            for x in range(len(self.current_piece[y])):
                if self.current_piece[y][x]:
                    self.board[self.current_y + y][self.current_x + x] = self.current_color



• Этот метод объединяет текущую фигуру с игровым полем. Он добавляет цвет текущей фигуры в соответствующие позиции на поле.

Метод clear_lines

    def clear_lines(self):
        lines_to_clear = []
        for y in range(GRID_HEIGHT):
            if all(self.board[y]):
                lines_to_clear.append(y)



• Этот метод проверяет каждую строку игрового поля. Если вся строка заполнена (все элементы не равны нулю), мы добавляем ее индекс в список строк для очистки.

        for y in lines_to_clear:
            del self.board[y]
            self.board.insert(0, [0] * GRID_WIDTH)
            self.score += 100
        
        self.score_label.config(text=f"Очки: {self.score}")



• После того как мы нашли строки для очистки, удаляем их из поля и добавляем новые пустые строки сверху. Увеличиваем счет на 100 очков и обновляем текст метки счета.

Метод draw_board

    def draw_board(self):
        self.canvas.delete(tk.ALL)



• Этот метод очищает холст перед тем, как нарисовать текущее состояние игрового поля.

        for y in range(GRID_HEIGHT):
            for x in range(GRID_WIDTH):
                if self.board[y][x]:
                    color = self.board[y][x]
                    self.canvas.create_rectangle(x * BLOCK_SIZE,
                                                  y * BLOCK_SIZE,
                                                  (x + 1) * BLOCK_SIZE,
                                                  (y + 1) * BLOCK_SIZE,
                                                  fill=color, outline="black")



• Здесь мы проходим по всем клеткам игрового поля и рисуем прямоугольники для заполненных клеток с соответствующими цветами.

        # Рисуем текущую фигуру
        for y in range(len(self.current_piece)):
            for x in range(len(self.current_piece[y])):
                if self.current_piece[y][x]:
                    color = self.current_color
                    self.canvas.create_rectangle((self.current_x + x) * BLOCK_SIZE,
                                                  (self.current_y + y) * BLOCK_SIZE,
                                                  (self.current_x + x + 1) * BLOCK_SIZE,
                                                  (self.current_y + y + 1) * BLOCK_SIZE,
                                                  fill=color, outline="black")



• Затем рисуем текущую фигуру на холсте с ее цветом и координатами.
Метод drop

    def drop(self):
        self.current_y += 1



• Этот метод отвечает за падение текущей фигуры вниз на одну клетку.

        if not self.valid_move():
            self.current_y -= 1
            self.merge()
            self.clear_lines()
            self.spawn_piece()



• Если фигура не может упасть дальше (например, достигла дна или столкнулась с другой фигурой), мы откатываем ее обратно на одну клетку вниз, объединяем с полем и очищаем линии. Затем создаем новую фигуру.

        self.draw_board()



• Обновляем отображение игрового поля после падения фигуры.

Метод update

    def update(self):
        self.drop()
        self.root.after(1000, self.update)


• Этот метод отвечает за обновление состояния игры. Он вызывает метод drop() для падения текущей фигуры и затем снова вызывает себя через одну секунду (1000 миллисекунд) с помощью метода after(). Это создает эффект постоянного падения фигур.

▎Методы управления фигурой

Каждый из этих методов отвечает за управление текущей фигурой:

Метод move_left
    def move_left(self, event):
        self.current_x -= 1
        if not self.valid_move():
            self.current_x += 1
        self.draw_board()


• Этот метод перемещает текущую фигуру влево. Если перемещение невозможно (например, фигура выходит за границы или сталкивается с другой фигурой), мы откатываем ее обратно вправо. Затем обновляем отображение поля.

Метод move_right
    def move_right(self, event):
        self.current_x += 1
        if not self.valid_move():
            self.current_x -= 1
        self.draw_board()


• Аналогично методу move_left, этот метод перемещает текущую фигуру вправо.

Метод move_down
    def move_down(self, event):
        self.drop()



• Этот метод вызывает метод drop(), чтобы быстро опустить фигуру вниз при нажатии клавиши вниз.

Метод rotate

    def rotate(self, event):
        rotated_shape = list(zip(*self.current_piece[::-1]))
        original_piece = self.current_piece
        self.current_piece = rotated_shape
        
        if not self.valid_move():
            self.current_piece = original_piece
        
        self.draw_board()



• Этот метод вращает текущую фигуру. Мы создаем новую версию фигуры путем транспонирования и реверсирования текущей. Если новая позиция недопустима, мы возвращаем фигуру в оригинальное состояние. Затем обновляем отображение поля.

Заключение



Эта игра является базовой реализацией Тетриса и может быть расширена различными функциями и улучшениями. Вы можете добавить уровни сложности, различные режимы игры или даже звук. Надеюсь, это объяснение помогло вам понять каждую часть кода! Если у вас есть дополнительные вопросы или вы хотите узнать больше о конкретных аспектах кода или его улучшениях, дайте знать!

Первая задача, переписать с нуля, для закрепления.
Комментарии к материалу
Комментировать
Ваш комментарий: