SoFunction
Updated on 2024-11-12

Detailed graphic tutorials for making Tetris using python

synopsis

Tetris (Russian: Тетрис) is a casual game invented in June 1984 by Russian Alexei Pakitnov.

The game had been represented by several companies. After many rounds of litigation, the rights to represent the game eventually went to Nintendo. [1] Nintendo was significant for Tetris, as pairing it with GB led to great success. [1]

The basic rules of Tetris are to move, rotate, and arrange the various cubes automatically output by the game to form a complete row or rows and eliminate them to score points.

encodings

Build the base page

The first step is to create a python file

Create a form to display the interface of this game

coding

import tkinter as tk
# First create a form
win = ()
()

running result

Drawing Lattice

The principle is as follows

The main application here is the Canvas function in tkinter.

The code is as follows

import tkinter as tk

# of rows and columns set
row = 20
col = 12

# Set the size of each grid
cell_size = 30

# Set the height and width of the window
height = row * cell_size
width = col * cell_size

# First create a form
win = ()

# Drawing grids on the drawing board
def draw_cell(canvas, col, row, color="#CCCCCC"):
    x0 = col * cell_size
    y0 = row * cell_size

    x1 = col * cell_size + cell_size
    y1 = row * cell_size + cell_size

    # Create rectangles
    canvas.create_rectangle(x0, y0, x1, y1, fill=color, outline="white", width=2)

def draw_blank_board(canvas):
    for ri in range(row):
        for cj in range(col):
            draw_cell(canvas, cj, ri)


# Draw the length and width of the canvas
canvas = (win, width=width, height=height)

# Pack and place component objects
()

draw_blank_board(canvas)

()

Drawing Tetris

Now draw one based on this rule and see what happens

code talk

import tkinter as tk

# of rows and columns set
Row = 20
Col = 12

# Set the size of each grid
cell_size = 30

# Set the height and width of the window
height = Row * cell_size
width = Col * cell_size

# Set up grids of different shapes
SHAPES = {
    "O": [(-1, -1), (0, -1), (-1, 0), (0, 0)]
}

# Set the color of the grid
SHAPESCOLOR = {
    "O":"blue"
}

# Drawing grids on the drawing board
def draw_cell_background(canvas, col, row, color="#CCCCCC"):
    x0 = col * cell_size
    y0 = row * cell_size

    x1 = col * cell_size + cell_size
    y1 = row * cell_size + cell_size

    # Create rectangles
    canvas.create_rectangle(x0, y0, x1, y1, fill=color, outline="white", width=2)

def draw_blank_board(canvas):
    for ri in range(Row):
        for cj in range(Col):
            draw_cell_background(canvas, cj, ri)

def draw_cells(canvas, col, row, cell_list, color="#CCCCCC"):
    """
    :param canvas: the canvas object
    :param col: The column where the origin of this shape is located.
    :param row: the row where the origin of this shape is located
    :param cell_list: coordinates of each cell of this shape relative to its origin
    :param color: the color of the shape
    :return.
    """
    for cell in cell_list:
        cell_col, cell_row = cell
        ci = cell_col + col
        ri = cell_row + row
        # Determining whether or not a boundary has been crossed
        if 0 <= col < Col and 0 <= row < Row:
            draw_cell_background(canvas, ci, ri, color)

# First create a form
win = ()

# Draw the length and width of the canvas
canvas = (win, width=width, height=height)

# Pack and place component objects
()

# Painting backgrounds
draw_blank_board(canvas)

# Starting to draw shapes, and here's a test.
draw_cells(canvas, 3, 3, SHAPES['O'], SHAPESCOLOR['O'])


()

Run the results, by running the results you can see that there is not much of a problem

Drawing other styles of grids

Here are the various coordinates of the other grids, just put them into SHAPES and SHAPESCOLOR in the code above.

Demo Code

import tkinter as tk

# of rows and columns set
Row = 20
Col = 12

# Set the size of each grid
cell_size = 30

# Set the height and width of the window
height = Row * cell_size
width = Col * cell_size

# Set up grids of different shapes
SHAPES = {
    "O": [(-1, -1), (0, -1), (-1, 0), (0, 0)],
    "S":[(-1, 0),(0, 0),(0, -1),(1, -1)],
    "T":[(-1, 0),(0, 0),(0, -1),(1, 0)],
    "I":[(0, 1),(0, 0),(0, -1),(0, -2)],
    "L":[(-1, 0),(0, 0),(-1, -1),(-1, -2)],
    "J":[(-1, 0),(0, 0),(0, 1),(0, -2)],
    "Z":[(-1, -1),(0, -1),(0, 0),(1, 0)]
}

# Set the color of the grid
SHAPESCOLOR = {
    "O":"blue",
    "S":"red",
    "T":"yellow",
    "I":"green",
    "L":"purple",
    "J":"orange",
    "Z":"Cyan",
}

# Drawing grids on the drawing board
def draw_cell_background(canvas, col, row, color="#CCCCCC"):
    x0 = col * cell_size
    y0 = row * cell_size

    x1 = col * cell_size + cell_size
    y1 = row * cell_size + cell_size

    # Create rectangles
    canvas.create_rectangle(x0, y0, x1, y1, fill=color, outline="white", width=2)

def draw_blank_board(canvas):
    for ri in range(Row):
        for cj in range(Col):
            draw_cell_background(canvas, cj, ri)

def draw_cells(canvas, col, row, cell_list, color="#CCCCCC"):
    """
    :param canvas: the canvas object
    :param col: The column where the origin of this shape is located.
    :param row: the row where the origin of this shape is located
    :param cell_list: coordinates of each cell of this shape relative to its origin
    :param color: the color of the shape
    :return.
    """
    for cell in cell_list:
        cell_col, cell_row = cell
        ci = cell_col + col
        ri = cell_row + row
        # Determining whether or not a boundary has been crossed
        if 0 <= col < Col and 0 <= row < Row:
            draw_cell_background(canvas, ci, ri, color)

# First create a form
win = ()

# Draw the length and width of the canvas
canvas = (win, width=width, height=height)

# Pack and place component objects
()

# Painting backgrounds
draw_blank_board(canvas)

# Starting to draw shapes, and here's a test.
draw_cells(canvas, 3, 3, SHAPES['O'], SHAPESCOLOR['O'])
draw_cells(canvas, 3, 8, SHAPES['S'], SHAPESCOLOR['S'])
draw_cells(canvas, 3, 13, SHAPES['T'], SHAPESCOLOR['T'])
draw_cells(canvas, 8, 3, SHAPES['I'], SHAPESCOLOR['I'])
draw_cells(canvas, 8, 8, SHAPES['L'], SHAPESCOLOR['L'])
draw_cells(canvas, 8, 13, SHAPES['J'], SHAPESCOLOR['J'])
draw_cells(canvas, 5, 18, SHAPES['Z'], SHAPESCOLOR['Z'])


()

running result

By testing this various graphic grids are completed.

Getting the grid moving

Let this grid make people feel moving, the main principle is to set a refresh time, and then this grid is constantly loading, and then constantly refreshing, so that is the use of thegame_loop(),draw_block_move(canvas, block, direction=[0,0])Two functions.

code talk

import tkinter as tk
import time
# of rows and columns set
Row = 20
Col = 12

# Set the size of each grid
cell_size = 30

# Set the height and width of the window
height = Row * cell_size
width = Col * cell_size

# Set up grids of different shapes
SHAPES = {
    "O": [(-1, -1), (0, -1), (-1, 0), (0, 0)],
    "S":[(-1, 0),(0, 0),(0, -1),(1, -1)],
    "T":[(-1, 0),(0, 0),(0, -1),(1, 0)],
    "I":[(0, 1),(0, 0),(0, -1),(0, -2)],
    "L":[(-1, 0),(0, 0),(-1, -1),(-1, -2)],
    "J":[(-1, 0),(0, 0),(0, 1),(0, -2)],
    "Z":[(-1, -1),(0, -1),(0, 0),(1, 0)]
}

# Set the color of the grid
SHAPESCOLOR = {
    "O":"blue",
    "S":"red",
    "T":"yellow",
    "I":"green",
    "L":"purple",
    "J":"orange",
    "Z":"Cyan",
}

# Drawing grids on the drawing board
def draw_cell_background(canvas, col, row, color="#CCCCCC"):
    x0 = col * cell_size
    y0 = row * cell_size

    x1 = col * cell_size + cell_size
    y1 = row * cell_size + cell_size

    # Create rectangles
    canvas.create_rectangle(x0, y0, x1, y1, fill=color, outline="white", width=2)

def draw_blank_board(canvas):
    for ri in range(Row):
        for cj in range(Col):
            draw_cell_background(canvas, cj, ri)

def draw_cells(canvas, col, row, cell_list, color="#CCCCCC"):
    """
    :param canvas: the canvas object
    :param col: The column where the origin of this shape is located.
    :param row: the row where the origin of the shape is located
    :param cell_list: coordinates of each cell of this shape relative to its origin
    :param color: the color of the shape
    :return.
    """
    for cell in cell_list:
        cell_col, cell_row = cell
        ci = cell_col + col
        ri = cell_row + row
        # Determining whether or not a boundary has been crossed
        if 0 <= col < Col and 0 <= row < Row:
            draw_cell_background(canvas, ci, ri, color)

# First create a form
win = ()

# Draw the length and width of the canvas
canvas = (win, width=width, height=height)

# Pack and place component objects
()

# Painting backgrounds
draw_blank_board(canvas)

# Starting to draw shapes, and here's a test.
# draw_cells(canvas, 3, 3, SHAPES['O'], SHAPESCOLOR['O'])
# draw_cells(canvas, 3, 8, SHAPES['S'], SHAPESCOLOR['S'])
# draw_cells(canvas, 3, 13, SHAPES['T'], SHAPESCOLOR['T'])
# draw_cells(canvas, 8, 3, SHAPES['I'], SHAPESCOLOR['I'])
# draw_cells(canvas, 8, 8, SHAPES['L'], SHAPESCOLOR['L'])
# draw_cells(canvas, 8, 13, SHAPES['J'], SHAPESCOLOR['J'])
# draw_cells(canvas, 5, 18, SHAPES['Z'], SHAPESCOLOR['Z'])

# Set the grid refresh frequency in milliseconds
FPS = 500

# Define a way to make Tetris move
def draw_block_move(canvas, block, direction=[0,0]):
    """
    :param canvas: panel object
    :param block: Tetris
    :param direction: Direction of movement
    :return.
    """
    shape_type = block['kind']
    c, r = block['cr']
    cell_list = block['cell_list']

    draw_cells(canvas, c, r, cell_list)

    dc, dr = direction
    new_c, new_r = c + dc, r + dr
    block['cr'] = [new_c, new_r]
    draw_cells(canvas, new_c, new_r, cell_list, SHAPESCOLOR[shape_type])

# Define each shape's attributes with a dictionary
one_block = {
    'kind': 'O', # Types corresponding to Tetris
    'cell_list': SHAPES['O'], # Coordinates of each corresponding Tetris
    'cr': [3, 3], # Corresponding row and column coordinates
}

draw_block_move(canvas, one_block)
# Keep the game looping through recursion #
def game_loop():
    ()

    # Going down
    down = [0, 1]
    draw_block_move(canvas, one_block, down)
    (FPS, game_loop) # Note that this game_loop cannot be followed by parentheses.

game_loop()
()

running result

Here a small Tetris, falling downwards, is generated.

Generating, fixing, transforming, moving Generating and fixing

Demo Code

import tkinter as tk
import time
# of rows and columns set
Row = 20
Col = 12

# Set the size of each grid
cell_size = 30

# Set the height and width of the window
height = Row * cell_size
width = Col * cell_size

# Set up grids of different shapes
SHAPES = {
    "O": [(-1, -1), (0, -1), (-1, 0), (0, 0)],
    "S":[(-1, 0),(0, 0),(0, -1),(1, -1)],
    "T":[(-1, 0),(0, 0),(0, -1),(1, 0)],
    "I":[(0, 1),(0, 0),(0, -1),(0, -2)],
    "L":[(-1, 0),(0, 0),(-1, -1),(-1, -2)],
    "J":[(-1, 0),(0, 0),(0, 1),(0, -2)],
    "Z":[(-1, -1),(0, -1),(0, 0),(1, 0)]
}

# Set the color of the grid
SHAPESCOLOR = {
    "O":"blue",
    "S":"red",
    "T":"yellow",
    "I":"green",
    "L":"purple",
    "J":"orange",
    "Z":"Cyan",
}

# Drawing grids on the drawing board
def draw_cell_background(canvas, col, row, color="#CCCCCC"):
    x0 = col * cell_size
    y0 = row * cell_size

    x1 = col * cell_size + cell_size
    y1 = row * cell_size + cell_size

    # Create rectangles
    canvas.create_rectangle(x0, y0, x1, y1, fill=color, outline="white", width=2)

def draw_blank_board(canvas):
    for ri in range(Row):
        for cj in range(Col):
            draw_cell_background(canvas, cj, ri)

def draw_cells(canvas, col, row, cell_list, color="#CCCCCC"):
    """
    :param canvas: the canvas object
    :param col: The column where the origin of this shape is located.
    :param row: the row where the origin of this shape is located
    :param cell_list: coordinates of each cell of this shape relative to its origin
    :param color: the color of the shape
    :return.
    """
    for cell in cell_list:
        cell_col, cell_row = cell
        ci = cell_col + col
        ri = cell_row + row
        # Determining whether or not a boundary has been crossed
        if 0 <= col < Col and 0 <= row < Row:
            draw_cell_background(canvas, ci, ri, color)

# First create a form
win = ()

# Draw the length and width of the canvas
canvas = (win, width=width, height=height)

# Pack and place component objects
()

# Painting backgrounds
draw_blank_board(canvas)

# Starting to draw shapes, and here's a test.
# draw_cells(canvas, 3, 3, SHAPES['O'], SHAPESCOLOR['O'])
# draw_cells(canvas, 3, 8, SHAPES['S'], SHAPESCOLOR['S'])
# draw_cells(canvas, 3, 13, SHAPES['T'], SHAPESCOLOR['T'])
# draw_cells(canvas, 8, 3, SHAPES['I'], SHAPESCOLOR['I'])
# draw_cells(canvas, 8, 8, SHAPES['L'], SHAPESCOLOR['L'])
# draw_cells(canvas, 8, 13, SHAPES['J'], SHAPESCOLOR['J'])
# draw_cells(canvas, 5, 18, SHAPES['Z'], SHAPESCOLOR['Z'])

# Set the grid refresh frequency in milliseconds
FPS = 500

# Define a way to make Tetris move
def draw_block_move(canvas, block, direction=[0,0]):
    """
    :param canvas: panel object
    :param block: Tetris
    :param direction: Direction of movement
    :return.
    """
    shape_type = block['kind']
    c, r = block['cr']
    cell_list = block['cell_list']

    draw_cells(canvas, c, r, cell_list)

    dc, dr = direction
    new_c, new_r = c + dc, r + dr
    block['cr'] = [new_c, new_r]
    draw_cells(canvas, new_c, new_r, cell_list, SHAPESCOLOR[shape_type])

# Define each shape's attributes with a dictionary
one_block = {
    'kind': 'O', # Types corresponding to Tetris
    'cell_list': SHAPES['O'], # Coordinates of each corresponding Tetris
    'cr': [3, 3], # Corresponding row and column coordinates
}

draw_block_move(canvas, one_block)
# Keep the game looping through recursion #
def game_loop():
    ()

    # Going down
    down = [0, 1]
    draw_block_move(canvas, one_block, down)
    (FPS, game_loop) # Note that this game_loop cannot be followed by parentheses.

game_loop()
()

Here we realize the constant generation of Tetris, and the constant stacking of Tetris, which basically realizes the production function of Tetris.

running result

mobility

running result

The effect is that you can move left and right, the specific code see below, mainly relying on thehorizontal_move_block(event)The implementation of this function.

Full Code

import tkinter as tk
import random

# of rows and columns set
Row = 20
Col = 12

# Set the grid refresh frequency in milliseconds
FPS = 50

# Set the size of each grid
cell_size = 30

# Set the height and width of the window
height = Row * cell_size
width = Col * cell_size

# Set up grids of different shapes
SHAPES = {
    "Z": [(-1, -1), (0, -1), (0, 0), (1, 0)],
    "O": [(-1, -1), (0, -1), (-1, 0), (0, 0)],
    "S": [(-1, 0), (0, 0), (0, -1), (1, -1)],
    "T": [(-1, 0), (0, 0), (0, -1), (1, 0)],
    "I": [(0, 1), (0, 0), (0, -1), (0, -2)],
    "L": [(-1, 0), (0, 0), (-1, -1), (-1, -2)],
    "J": [(-1, 0), (0, 0), (0, -1), (0, -2)]
}

# Set the color of the grid
SHAPESCOLOR = {
    "O":"blue",
    "S":"red",
    "T":"yellow",
    "I":"green",
    "L":"purple",
    "J":"orange",
    "Z":"Cyan",
}

# Drawing grids on the drawing board
def draw_cell_background(canvas, col, row, color="#CCCCCC"):
    x0 = col * cell_size
    y0 = row * cell_size

    x1 = col * cell_size + cell_size
    y1 = row * cell_size + cell_size

    # Create rectangles
    canvas.create_rectangle(x0, y0, x1, y1, fill=color, outline="white", width=2)

# Drawing plates
def draw_blank_board(canvas):
    for ri in range(Row):
        for cj in range(Col):
            draw_cell_background(canvas, cj, ri)

# Drawing cells
def draw_cells(canvas, col, row, cell_list, color="#CCCCCC"):
    """
    :param canvas: the canvas object
    :param col: The column where the origin of this shape is located.
    :param row: the row where the origin of this shape is located
    :param cell_list: coordinates of each cell of this shape relative to its origin
    :param color: the color of the shape
    :return.
    """
    for cell in cell_list:
        cell_col, cell_row = cell
        ci = cell_col + col
        ri = cell_row + row
        # Determining whether or not a boundary has been crossed
        if 0 <= col < Col and 0 <= row < Row:
            draw_cell_background(canvas, ci, ri, color)

# First create a form
win = ()

# Draw the length and width of the canvas
canvas = (win, width=width, height=height)

# Pack and place component objects
()

# Painting backgrounds
draw_blank_board(canvas)

block_list = []
for i in range(Row):
    i_row = ['' for j in range(Col)]
    block_list.append(i_row)


# Starting to draw shapes, and here's a test.
# draw_cells(canvas, 3, 3, SHAPES['O'], SHAPESCOLOR['O'])
# draw_cells(canvas, 3, 8, SHAPES['S'], SHAPESCOLOR['S'])
# draw_cells(canvas, 3, 13, SHAPES['T'], SHAPESCOLOR['T'])
# draw_cells(canvas, 8, 3, SHAPES['I'], SHAPESCOLOR['I'])
# draw_cells(canvas, 8, 8, SHAPES['L'], SHAPESCOLOR['L'])
# draw_cells(canvas, 8, 13, SHAPES['J'], SHAPESCOLOR['J'])
# draw_cells(canvas, 5, 18, SHAPES['Z'], SHAPESCOLOR['Z'])


# Define a way to make Tetris move
def draw_block_move(canvas, block, direction=[0,0]):
    """
    :param canvas: panel object
    :param block: Tetris
    :param direction: Direction of movement
    :return.
    """
    shape_type = block['kind']
    c, r = block['cr']
    cell_list = block['cell_list']

    draw_cells(canvas, c, r, cell_list)

    dc, dr = direction
    new_c, new_r = c + dc, r + dr
    block['cr'] = [new_c, new_r]
    draw_cells(canvas, new_c, new_r, cell_list, SHAPESCOLOR[shape_type])

# Define each shape's attributes with a dictionary
one_block = {
    'kind': 'O', # Types corresponding to Tetris
    'cell_list': SHAPES['O'], # Coordinates of each corresponding Tetris
    'cr': [3, 3], # Corresponding row and column coordinates
}

# Test code
# draw_block_move(canvas, one_block)

def product_new_block():
    # Randomly generate new Tetris
    kind = (list(()))

    cr = [Col // 2, 0]
    new_block = {
        "kind": kind,
        "cell_list": SHAPES[kind],
        'cr': cr
    }
    return new_block

def check_move(block, direction=[0,0]):
    """
    :param block: The predecessor of Tetris.
    :param direction: direction of movement
    :return: boolean Whether the block can be moved in the specified direction.
    """
    cc, cr = block['cr']
    cell_list = block['cell_list']

    for cell in cell_list:
        cell_c, cell_r = cell
        c = cell_c + cc + direction[0]
        r = cell_r + cr + direction[1]

        # Judging the boundaries
        if c < 0 or c >= Col or r >= Row:
            return False
        # r >= 0 is to prevent the grid from going down
        if r >= 0 and block_list[r][c]:
            return False
    return True

# Save the current Tetris in the list
def save_to_block_list(block):
    shape_type = block['kind']
    cc, cr = block['cr']
    cell_list = block['cell_list']

    for cell in cell_list:
        cell_c, cell_r = cell
        c = cell_c + cc
        r = cell_r + cr

        block_list[r][c] = shape_type


def horizontal_move_block(event):
    """
    Move Tetris horizontally left and right
    event:Keyboard listening events
    """
    # Only left and right directions are set here #
    direction = [0, 0]
    if  == 'Left':
        direction = [-1, 0]
    elif  == 'Right':
        direction = [1, 0]
    else:
        return

    global current_block
    if current_block is not None and check_move(current_block, direction):
        draw_block_move(canvas, current_block, direction)


# Keep the game looping through recursion #
def game_loop():
    ()

    global current_block
    # If there's no current Tetris, generate a new one #
    if current_block is None:
        # Generate new Tetris
        new_block = product_new_block()
        draw_block_move(canvas, new_block)
        current_block = new_block
    # Down the line if it's current
    else:
        if check_move(current_block, [0, 1]):
            draw_block_move(canvas, current_block, [0, 1])
        else:
            # Save the current Tetris
            save_to_block_list(current_block)
            current_block = None
    (FPS, game_loop) # Note that this game_loop cannot be followed by parentheses.

# Current Tetris
current_block = None

# Canvas focus
canvas.focus_set()
# Add events for left and right movement
("<KeyPress-Left>", horizontal_move_block)
("<KeyPress-Right>", horizontal_move_block)


game_loop()
()

a transformation

This is so that the angle of this Tetris can be transformed, the main thing is to use this function, this rotate_block is the rotation of the angle, this land is immediately down the function.

def rotate_block(event):
    global current_block
    if current_block is None:
        return
 
    cell_list = current_block['cell_list']
    rotate_list = []
    for cell in cell_list:
        cell_c, cell_r = cell
        rotate_cell = [cell_r, -cell_c]
        rotate_list.append(rotate_cell)
 
    block_after_rotate = {
        'kind': current_block['kind'],  # Types corresponding to Tetris
        'cell_list': rotate_list,
        'cr': current_block['cr']
    }
 
    if check_move(block_after_rotate):
        cc, cr= current_block['cr']
        draw_cells(canvas, cc, cr, current_block['cell_list'])
        draw_cells(canvas, cc, cr, rotate_list,SHAPESCOLOR[current_block['kind']])
        current_block = block_after_rotate
 
 
def land(event):
    global current_block
    if current_block is None:
        return
 
    cell_list = current_block['cell_list']
    cc, cr = current_block['cr']
    min_height = R
    for cell in cell_list:
        cell_c, cell_r = cell
        c, r = cell_c + cc, cell_r + cr
        if block_list[r][c]:
            return
        h = 0
        for ri in range(r+1, R):
            if block_list[ri][c]:
                break
            else:
                h += 1
        if h < min_height:
            min_height = h
 
    down = [0, min_height]
    if check_move(current_block, down):
        draw_block_move(canvas, current_block, down)

Complete Code

import tkinter as tk
import random

# of rows and columns set
Row = 20
Col = 12

# Set the grid refresh frequency in milliseconds
FPS = 250

# Set the size of each grid
cell_size = 30

# Set the height and width of the window
height = Row * cell_size
width = Col * cell_size

# Set up grids of different shapes
SHAPES = {
    "Z": [(-1, -1), (0, -1), (0, 0), (1, 0)],
    "O": [(-1, -1), (0, -1), (-1, 0), (0, 0)],
    "S": [(-1, 0), (0, 0), (0, -1), (1, -1)],
    "T": [(-1, 0), (0, 0), (0, -1), (1, 0)],
    "I": [(0, 1), (0, 0), (0, -1), (0, -2)],
    "L": [(-1, 0), (0, 0), (-1, -1), (-1, -2)],
    "J": [(-1, 0), (0, 0), (0, -1), (0, -2)]
}

# Set the color of the grid
SHAPESCOLOR = {
    "O":"blue",
    "S":"red",
    "T":"yellow",
    "I":"green",
    "L":"purple",
    "J":"orange",
    "Z":"Cyan",
}

# Drawing grids on the drawing board
def draw_cell_background(canvas, col, row, color="#CCCCCC"):
    x0 = col * cell_size
    y0 = row * cell_size

    x1 = col * cell_size + cell_size
    y1 = row * cell_size + cell_size

    # Create rectangles
    canvas.create_rectangle(x0, y0, x1, y1, fill=color, outline="white", width=2)

# Drawing plates
def draw_blank_board(canvas):
    for ri in range(Row):
        for cj in range(Col):
            draw_cell_background(canvas, cj, ri)

# Drawing cells
def draw_cells(canvas, col, row, cell_list, color="#CCCCCC"):
    """
    :param canvas: the canvas object
    :param col: The column where the origin of this shape is located.
    :param row: the row where the origin of this shape is located
    :param cell_list: coordinates of each cell of this shape relative to its origin
    :param color: the color of the shape
    :return.
    """
    for cell in cell_list:
        cell_col, cell_row = cell
        ci = cell_col + col
        ri = cell_row + row
        # Determining whether or not a boundary has been crossed
        if 0 <= col < Col and 0 <= row < Row:
            draw_cell_background(canvas, ci, ri, color)

# First create a form
win = ()

# Draw the length and width of the canvas
canvas = (win, width=width, height=height)

# Pack and place component objects
()

# Painting backgrounds
draw_blank_board(canvas)

block_list = []
for i in range(Row):
    i_row = ['' for j in range(Col)]
    block_list.append(i_row)


# Starting to draw shapes, and here's a test.
# draw_cells(canvas, 3, 3, SHAPES['O'], SHAPESCOLOR['O'])
# draw_cells(canvas, 3, 8, SHAPES['S'], SHAPESCOLOR['S'])
# draw_cells(canvas, 3, 13, SHAPES['T'], SHAPESCOLOR['T'])
# draw_cells(canvas, 8, 3, SHAPES['I'], SHAPESCOLOR['I'])
# draw_cells(canvas, 8, 8, SHAPES['L'], SHAPESCOLOR['L'])
# draw_cells(canvas, 8, 13, SHAPES['J'], SHAPESCOLOR['J'])
# draw_cells(canvas, 5, 18, SHAPES['Z'], SHAPESCOLOR['Z'])


# Define a way to make Tetris move
def draw_block_move(canvas, block, direction=[0,0]):
    """
    :param canvas: panel object
    :param block: Tetris
    :param direction: Direction of movement
    :return.
    """
    shape_type = block['kind']
    c, r = block['cr']
    cell_list = block['cell_list']

    draw_cells(canvas, c, r, cell_list)

    dc, dr = direction
    new_c, new_r = c + dc, r + dr
    block['cr'] = [new_c, new_r]
    draw_cells(canvas, new_c, new_r, cell_list, SHAPESCOLOR[shape_type])

# Define each shape's attributes with a dictionary
one_block = {
    'kind': 'O', # Types corresponding to Tetris
    'cell_list': SHAPES['O'], # Coordinates of each corresponding Tetris
    'cr': [3, 3], # Corresponding row and column coordinates
}

# Test code
# draw_block_move(canvas, one_block)

def product_new_block():
    # Randomly generate new Tetris
    kind = (list(()))

    cr = [Col // 2, 0]
    new_block = {
        "kind": kind,
        "cell_list": SHAPES[kind],
        'cr': cr
    }
    return new_block

def check_move(block, direction=[0,0]):
    """
    :param block: The predecessor of Tetris.
    :param direction: direction of movement
    :return: boolean Whether the block can be moved in the specified direction.
    """
    cc, cr = block['cr']
    cell_list = block['cell_list']

    for cell in cell_list:
        cell_c, cell_r = cell
        c = cell_c + cc + direction[0]
        r = cell_r + cr + direction[1]

        # Judging the boundaries
        if c < 0 or c >= Col or r >= Row:
            return False
        # r >= 0 is to prevent the grid from going down
        if r >= 0 and block_list[r][c]:
            return False
    return True

# Save the current Tetris in the list
def save_to_block_list(block):
    shape_type = block['kind']
    cc, cr = block['cr']
    cell_list = block['cell_list']

    for cell in cell_list:
        cell_c, cell_r = cell
        c = cell_c + cc
        r = cell_r + cr

        block_list[r][c] = shape_type


def horizontal_move_block(event):
    """
    Move Tetris horizontally left and right
    event:Keyboard listening events
    """
    # Only left and right directions are set here #
    direction = [0, 0]
    if  == 'Left':
        direction = [-1, 0]
    elif  == 'Right':
        direction = [1, 0]
    else:
        return

    global current_block
    if current_block is not None and check_move(current_block, direction):
        draw_block_move(canvas, current_block, direction)


def rotate_block(event):
    global current_block
    if current_block is None:
        return

    cell_list = current_block['cell_list']
    rotate_list = []
    for cell in cell_list:
        cell_c, cell_r = cell
        rotate_cell = [cell_r, -cell_c]
        rotate_list.append(rotate_cell)

    block_after_rotate = {
        'kind': current_block['kind'],  # Types corresponding to Tetris
        'cell_list': rotate_list,
        'cr': current_block['cr']
    }

    if check_move(block_after_rotate):
        cc, cr = current_block['cr']
        draw_cells(canvas, cc, cr, current_block['cell_list'])
        draw_cells(canvas, cc, cr, rotate_list, SHAPESCOLOR[current_block['kind']])
        current_block = block_after_rotate


def land(event):
    global current_block
    if current_block is None:
        return

    cell_list = current_block['cell_list']
    cc, cr = current_block['cr']
    min_height = Row
    for cell in cell_list:
        cell_c, cell_r = cell
        c, r = cell_c + cc, cell_r + cr
        if block_list[r][c]:
            return
        h = 0
        for ri in range(r + 1, Row):
            if block_list[ri][c]:
                break
            else:
                h += 1
        if h < min_height:
            min_height = h

    down = [0, min_height]
    if check_move(current_block, down):
        draw_block_move(canvas, current_block, down)


# Keep the game looping through recursion #
def game_loop():
    ()

    global current_block
    # If there's no current Tetris, generate a new one #
    if current_block is None:
        # Generate new Tetris
        new_block = product_new_block()
        draw_block_move(canvas, new_block)
        current_block = new_block
    # Down the line if it's current
    else:
        if check_move(current_block, [0, 1]):
            draw_block_move(canvas, current_block, [0, 1])
        else:
            # Save the current Tetris
            save_to_block_list(current_block)
            current_block = None
    (FPS, game_loop) # Note that this game_loop cannot be followed by parentheses.

# Current Tetris
current_block = None

# Canvas focus
canvas.focus_set()
# Add events for left and right movement
("<KeyPress-Left>", horizontal_move_block)
("<KeyPress-Right>", horizontal_move_block)
# Add events that change angle
("<KeyPress-Up>", rotate_block)
("<KeyPress-Down>", land)


game_loop()
()

running result

Now this Tetris can be angled up and down.

Clearance and Scoring

In this version, the function of clearing and scoring is implemented, each time you clear this tetris, you get a +10 bonus, and finally when it's not possible to continue, this game is over, and then you quit.

import tkinter as tk
from tkinter import messagebox
import random

# of rows and columns set
Row = 20
Col = 12

# Set the grid refresh frequency in milliseconds
FPS = 150

# Set the size of each grid
cell_size = 30

# Set the height and width of the window
height = Row * cell_size
width = Col * cell_size

# Set up grids of different shapes
SHAPES = {
    "Z": [(-1, -1), (0, -1), (0, 0), (1, 0)],
    "O": [(-1, -1), (0, -1), (-1, 0), (0, 0)],
    "S": [(-1, 0), (0, 0), (0, -1), (1, -1)],
    "T": [(-1, 0), (0, 0), (0, -1), (1, 0)],
    "I": [(0, 1), (0, 0), (0, -1), (0, -2)],
    "L": [(-1, 0), (0, 0), (-1, -1), (-1, -2)],
    "J": [(-1, 0), (0, 0), (0, -1), (0, -2)]
}

# Set the color of the grid
SHAPESCOLOR = {
    "O":"blue",
    "S":"red",
    "T":"yellow",
    "I":"green",
    "L":"purple",
    "J":"orange",
    "Z":"Cyan",
}
# Draw the panel, change the draw_blank_board method to the following method
def draw_board(canvas, block_list):
    for ri in range(Row):
        for ci in range(Col):
            cell_type = block_list[ri][ci]
            if cell_type:
                draw_cell_background(canvas, ci, ri, SHAPESCOLOR[cell_type])
            else:
                draw_cell_background(canvas, ci, ri)
# Drawing grids on the drawing board
def draw_cell_background(canvas, col, row, color="#CCCCCC"):
    x0 = col * cell_size
    y0 = row * cell_size

    x1 = col * cell_size + cell_size
    y1 = row * cell_size + cell_size

    # Create rectangles
    canvas.create_rectangle(x0, y0, x1, y1, fill=color, outline="white", width=2)

# Drawing plates
def draw_blank_board(canvas):
    for ri in range(Row):
        for cj in range(Col):
            draw_cell_background(canvas, cj, ri)

# Drawing cells
def draw_cells(canvas, col, row, cell_list, color="#CCCCCC"):
    """
    :param canvas: the canvas object
    :param col: The column where the origin of this shape is located.
    :param row: the row where the origin of this shape is located
    :param cell_list: coordinates of each cell of this shape relative to its origin
    :param color: the color of the shape
    :return.
    """
    for cell in cell_list:
        cell_col, cell_row = cell
        ci = cell_col + col
        ri = cell_row + row
        # Determining whether or not a boundary has been crossed
        if 0 <= col < Col and 0 <= row < Row:
            draw_cell_background(canvas, ci, ri, color)

# First create a form
win = ()

# Draw the length and width of the canvas
canvas = (win, width=width, height=height)

# Pack and place component objects
()

# Painting backgrounds
block_list = []
for i in range(Row):
    i_row = ['' for j in range(Col)]
    block_list.append(i_row)

draw_board(canvas, block_list)


# Starting to draw shapes, and here's a test.
# draw_cells(canvas, 3, 3, SHAPES['O'], SHAPESCOLOR['O'])
# draw_cells(canvas, 3, 8, SHAPES['S'], SHAPESCOLOR['S'])
# draw_cells(canvas, 3, 13, SHAPES['T'], SHAPESCOLOR['T'])
# draw_cells(canvas, 8, 3, SHAPES['I'], SHAPESCOLOR['I'])
# draw_cells(canvas, 8, 8, SHAPES['L'], SHAPESCOLOR['L'])
# draw_cells(canvas, 8, 13, SHAPES['J'], SHAPESCOLOR['J'])
# draw_cells(canvas, 5, 18, SHAPES['Z'], SHAPESCOLOR['Z'])


# Define a way to make Tetris move
def draw_block_move(canvas, block, direction=[0,0]):
    """
    :param canvas: panel object
    :param block: Tetris
    :param direction: Direction of movement
    :return.
    """
    shape_type = block['kind']
    c, r = block['cr']
    cell_list = block['cell_list']

    draw_cells(canvas, c, r, cell_list)

    dc, dr = direction
    new_c, new_r = c + dc, r + dr
    block['cr'] = [new_c, new_r]
    draw_cells(canvas, new_c, new_r, cell_list, SHAPESCOLOR[shape_type])

# Define each shape's attributes with a dictionary
one_block = {
    'kind': 'O', # Types corresponding to Tetris
    'cell_list': SHAPES['O'], # Coordinates of each corresponding Tetris
    'cr': [3, 3], # Corresponding row and column coordinates
}

# Test code
# draw_block_move(canvas, one_block)

def product_new_block():
    # Randomly generate new Tetris
    kind = (list(()))

    cr = [Col // 2, 0]
    new_block = {
        "kind": kind,
        "cell_list": SHAPES[kind],
        'cr': cr
    }
    return new_block

def check_move(block, direction=[0,0]):
    """
    :param block: The predecessor of Tetris.
    :param direction: direction of movement
    :return: boolean Whether the block can be moved in the specified direction.
    """
    cc, cr = block['cr']
    cell_list = block['cell_list']

    for cell in cell_list:
        cell_c, cell_r = cell
        c = cell_c + cc + direction[0]
        r = cell_r + cr + direction[1]

        # Judging the boundaries
        if c < 0 or c >= Col or r >= Row:
            return False
        # r >= 0 is to prevent the grid from going down
        if r >= 0 and block_list[r][c]:
            return False
    return True

# Save the current Tetris in the list
def save_to_block_list(block):
    shape_type = block['kind']
    cc, cr = block['cr']
    cell_list = block['cell_list']

    for cell in cell_list:
        cell_c, cell_r = cell
        c = cell_c + cc
        r = cell_r + cr

        block_list[r][c] = shape_type


def horizontal_move_block(event):
    """
    Move Tetris horizontally left and right
    event:Keyboard listening events
    """
    # Only left and right directions are set here #
    direction = [0, 0]
    if  == 'Left':
        direction = [-1, 0]
    elif  == 'Right':
        direction = [1, 0]
    else:
        return

    global current_block
    if current_block is not None and check_move(current_block, direction):
        draw_block_move(canvas, current_block, direction)


def rotate_block(event):
    global current_block
    if current_block is None:
        return

    cell_list = current_block['cell_list']
    rotate_list = []
    for cell in cell_list:
        cell_c, cell_r = cell
        rotate_cell = [cell_r, -cell_c]
        rotate_list.append(rotate_cell)

    block_after_rotate = {
        'kind': current_block['kind'],  # Types corresponding to Tetris
        'cell_list': rotate_list,
        'cr': current_block['cr']
    }

    if check_move(block_after_rotate):
        cc, cr = current_block['cr']
        draw_cells(canvas, cc, cr, current_block['cell_list'])
        draw_cells(canvas, cc, cr, rotate_list, SHAPESCOLOR[current_block['kind']])
        current_block = block_after_rotate


def land(event):
    global current_block
    if current_block is None:
        return

    cell_list = current_block['cell_list']
    cc, cr = current_block['cr']
    min_height = Row
    for cell in cell_list:
        cell_c, cell_r = cell
        c, r = cell_c + cc, cell_r + cr
        if block_list[r][c]:
            return
        h = 0
        for ri in range(r + 1, Row):
            if block_list[ri][c]:
                break
            else:
                h += 1
        if h < min_height:
            min_height = h

    down = [0, min_height]
    if check_move(current_block, down):
        draw_block_move(canvas, current_block, down)



# Add the original rotate_block method (outside) under the
def check_row_complete(row):
    for cell in row:
        if cell == '':
            return False

    return True


score = 0
("SCORES: %s" % score)  # Fractions displayed in headings


def check_and_clear():
    has_complete_row = False
    for ri in range(len(block_list)):
        if check_row_complete(block_list[ri]):
            has_complete_row = True
            # Current line can be eliminated
            if ri > 0:
                for cur_ri in range(ri, 0, -1):
                    block_list[cur_ri] = block_list[cur_ri - 1][:]
                block_list[0] = ['' for j in range(Col)]
            else:
                block_list[ri] = ['' for j in range(Col)]
            global score
            # Ten points for each elimination
            score += 10


    if has_complete_row:
        draw_board(canvas, block_list)
        # Redrawing
        ("SCORES: %s" % score)


# Keep the game looping through recursion #
def game_loop():
    ()

    global current_block
    # If there's no current Tetris, generate a new one #
    if current_block is None:
        # Generate new Tetris
        new_block = product_new_block()
        draw_block_move(canvas, new_block)
        current_block = new_block

        # Game over
        if not check_move(current_block, [0, 0]):
            ("Game Over!", "Your Score is %s" % score)
            ()
            return

    # Down the line if it's current
    else:
        if check_move(current_block, [0, 1]):
            draw_block_move(canvas, current_block, [0, 1])
        else:
            # Save the current Tetris
            save_to_block_list(current_block)
            current_block = None
    # Game over
    check_and_clear()
    (FPS, game_loop) # Note that this game_loop cannot be followed by parentheses.

# Current Tetris
current_block = None

# Canvas focus
canvas.focus_set()
# Add events for left and right movement
("<KeyPress-Left>", horizontal_move_block)
("<KeyPress-Right>", horizontal_move_block)
# Add events that change angle
("<KeyPress-Up>", rotate_block)
("<KeyPress-Down>", land)


game_loop()
()

running result

This is what the game will look like at the end, you can actually add a database function later to record the results of each score.

Full Code

import tkinter as tk
from tkinter import messagebox
import random

# of rows and columns set
Row = 20
Col = 12

# Set the grid refresh frequency in milliseconds
FPS = 150

# Set the size of each grid
cell_size = 30

# Set the height and width of the window
height = Row * cell_size
width = Col * cell_size

# Set up grids of different shapes
SHAPES = {
    "Z": [(-1, -1), (0, -1), (0, 0), (1, 0)],
    "O": [(-1, -1), (0, -1), (-1, 0), (0, 0)],
    "S": [(-1, 0), (0, 0), (0, -1), (1, -1)],
    "T": [(-1, 0), (0, 0), (0, -1), (1, 0)],
    "I": [(0, 1), (0, 0), (0, -1), (0, -2)],
    "L": [(-1, 0), (0, 0), (-1, -1), (-1, -2)],
    "J": [(-1, 0), (0, 0), (0, -1), (0, -2)]
}

# Set the color of the grid
SHAPESCOLOR = {
    "O":"blue",
    "S":"red",
    "T":"yellow",
    "I":"green",
    "L":"purple",
    "J":"orange",
    "Z":"Cyan",
}
# Draw the panel, change the draw_blank_board method to the following method
def draw_board(canvas, block_list):
    for ri in range(Row):
        for ci in range(Col):
            cell_type = block_list[ri][ci]
            if cell_type:
                draw_cell_background(canvas, ci, ri, SHAPESCOLOR[cell_type])
            else:
                draw_cell_background(canvas, ci, ri)
# Drawing grids on the drawing board
def draw_cell_background(canvas, col, row, color="#CCCCCC"):
    x0 = col * cell_size
    y0 = row * cell_size

    x1 = col * cell_size + cell_size
    y1 = row * cell_size + cell_size

    # Create rectangles
    canvas.create_rectangle(x0, y0, x1, y1, fill=color, outline="white", width=2)

# Drawing plates
def draw_blank_board(canvas):
    for ri in range(Row):
        for cj in range(Col):
            draw_cell_background(canvas, cj, ri)

# Drawing cells
def draw_cells(canvas, col, row, cell_list, color="#CCCCCC"):
    """
    :param canvas: the canvas object
    :param col: The column where the origin of this shape is located.
    :param row: the row where the origin of this shape is located
    :param cell_list: coordinates of each cell of this shape relative to its origin
    :param color: the color of the shape
    :return.
    """
    for cell in cell_list:
        cell_col, cell_row = cell
        ci = cell_col + col
        ri = cell_row + row
        # Determining whether or not a boundary has been crossed
        if 0 <= col < Col and 0 <= row < Row:
            draw_cell_background(canvas, ci, ri, color)

# First create a form
win = ()

# Draw the length and width of the canvas
canvas = (win, width=width, height=height)

# Pack and place component objects
()

# Painting backgrounds
block_list = []
for i in range(Row):
    i_row = ['' for j in range(Col)]
    block_list.append(i_row)

draw_board(canvas, block_list)


# Starting to draw shapes, and here's a test.
# draw_cells(canvas, 3, 3, SHAPES['O'], SHAPESCOLOR['O'])
# draw_cells(canvas, 3, 8, SHAPES['S'], SHAPESCOLOR['S'])
# draw_cells(canvas, 3, 13, SHAPES['T'], SHAPESCOLOR['T'])
# draw_cells(canvas, 8, 3, SHAPES['I'], SHAPESCOLOR['I'])
# draw_cells(canvas, 8, 8, SHAPES['L'], SHAPESCOLOR['L'])
# draw_cells(canvas, 8, 13, SHAPES['J'], SHAPESCOLOR['J'])
# draw_cells(canvas, 5, 18, SHAPES['Z'], SHAPESCOLOR['Z'])


# Define a way to make Tetris move
def draw_block_move(canvas, block, direction=[0,0]):
    """
    :param canvas: panel object
    :param block: Tetris
    :param direction: Direction of movement
    :return.
    """
    shape_type = block['kind']
    c, r = block['cr']
    cell_list = block['cell_list']

    draw_cells(canvas, c, r, cell_list)

    dc, dr = direction
    new_c, new_r = c + dc, r + dr
    block['cr'] = [new_c, new_r]
    draw_cells(canvas, new_c, new_r, cell_list, SHAPESCOLOR[shape_type])

# Define each shape's attributes with a dictionary
one_block = {
    'kind': 'O', # Types corresponding to Tetris
    'cell_list': SHAPES['O'], # Coordinates of each corresponding Tetris
    'cr': [3, 3], # Corresponding row and column coordinates
}

# Test code
# draw_block_move(canvas, one_block)

def product_new_block():
    # Randomly generate new Tetris
    kind = (list(()))

    cr = [Col // 2, 0]
    new_block = {
        "kind": kind,
        "cell_list": SHAPES[kind],
        'cr': cr
    }
    return new_block

def check_move(block, direction=[0,0]):
    """
    :param block: The predecessor of Tetris.
    :param direction: direction of movement
    :return: boolean Whether the block can be moved in the specified direction.
    """
    cc, cr = block['cr']
    cell_list = block['cell_list']

    for cell in cell_list:
        cell_c, cell_r = cell
        c = cell_c + cc + direction[0]
        r = cell_r + cr + direction[1]

        # Judging the boundaries
        if c < 0 or c >= Col or r >= Row:
            return False
        # r >= 0 is to prevent the grid from going down
        if r >= 0 and block_list[r][c]:
            return False
    return True

# Save the current Tetris in the list
def save_to_block_list(block):
    shape_type = block['kind']
    cc, cr = block['cr']
    cell_list = block['cell_list']

    for cell in cell_list:
        cell_c, cell_r = cell
        c = cell_c + cc
        r = cell_r + cr

        block_list[r][c] = shape_type


def horizontal_move_block(event):
    """
    Move Tetris horizontally left and right
    event:Keyboard listening events
    """
    # Only left and right directions are set here #
    direction = [0, 0]
    if  == 'Left':
        direction = [-1, 0]
    elif  == 'Right':
        direction = [1, 0]
    else:
        return

    global current_block
    if current_block is not None and check_move(current_block, direction):
        draw_block_move(canvas, current_block, direction)


def rotate_block(event):
    global current_block
    if current_block is None:
        return

    cell_list = current_block['cell_list']
    rotate_list = []
    for cell in cell_list:
        cell_c, cell_r = cell
        rotate_cell = [cell_r, -cell_c]
        rotate_list.append(rotate_cell)

    block_after_rotate = {
        'kind': current_block['kind'],  # Types corresponding to Tetris
        'cell_list': rotate_list,
        'cr': current_block['cr']
    }

    if check_move(block_after_rotate):
        cc, cr = current_block['cr']
        draw_cells(canvas, cc, cr, current_block['cell_list'])
        draw_cells(canvas, cc, cr, rotate_list, SHAPESCOLOR[current_block['kind']])
        current_block = block_after_rotate


def land(event):
    global current_block
    if current_block is None:
        return

    cell_list = current_block['cell_list']
    cc, cr = current_block['cr']
    min_height = Row
    for cell in cell_list:
        cell_c, cell_r = cell
        c, r = cell_c + cc, cell_r + cr
        if block_list[r][c]:
            return
        h = 0
        for ri in range(r + 1, Row):
            if block_list[ri][c]:
                break
            else:
                h += 1
        if h < min_height:
            min_height = h

    down = [0, min_height]
    if check_move(current_block, down):
        draw_block_move(canvas, current_block, down)



# Add the original rotate_block method (outside) under the
def check_row_complete(row):
    for cell in row:
        if cell == '':
            return False

    return True


score = 0
("SCORES: %s" % score)  # Fractions displayed in headings


def check_and_clear():
    has_complete_row = False
    for ri in range(len(block_list)):
        if check_row_complete(block_list[ri]):
            has_complete_row = True
            # Current line can be eliminated
            if ri > 0:
                for cur_ri in range(ri, 0, -1):
                    block_list[cur_ri] = block_list[cur_ri - 1][:]
                block_list[0] = ['' for j in range(Col)]
            else:
                block_list[ri] = ['' for j in range(Col)]
            global score
            # Ten points for each elimination
            score += 10


    if has_complete_row:
        draw_board(canvas, block_list)
        # Redrawing
        ("SCORES: %s" % score)


# Keep the game looping through recursion #
def game_loop():
    ()

    global current_block
    # If there's no current Tetris, generate a new one #
    if current_block is None:
        # Generate new Tetris
        new_block = product_new_block()
        draw_block_move(canvas, new_block)
        current_block = new_block

        # Game over
        if not check_move(current_block, [0, 0]):
            ("Game Over!", "Your Score is %s" % score)
            ()
            return

    # Down the line if it's current
    else:
        if check_move(current_block, [0, 1]):
            draw_block_move(canvas, current_block, [0, 1])
        else:
            # Save the current Tetris
            save_to_block_list(current_block)
            current_block = None
    # Game over
    check_and_clear()
    (FPS, game_loop) # Note that this game_loop cannot be followed by parentheses.

# Current Tetris
current_block = None

# Canvas focus
canvas.focus_set()
# Add events for left and right movement
("<KeyPress-Left>", horizontal_move_block)
("<KeyPress-Right>", horizontal_move_block)
# Add events that change angle
("<KeyPress-Up>", rotate_block)
("<KeyPress-Down>", land)


game_loop()
()

summarize

This article on the use of python to make Tetris is introduced to this article, more related python to make Tetris content please search for my previous posts or continue to browse the following related articles I hope you will support me more in the future!