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!