6.6 案例:利用大语言模型体验 turtle 与 pygame 模块¶

以下示例代码用于课堂演示/自学,环境需安装/支持对应图形库;在部分无图形界面的环境中可能无法直接运行。

6.6.1 使用 turtle 绘制樱花树(分形示意)¶

提示词示例:

“请用Python的turtle库帮我绘制一棵樱花树。要求树干是棕色的,樱花是粉色的,树上要有至少30朵樱花随机分布。请使用递归方式绘制树枝,使整棵树看起来自然。给出完整代码并解释关键步骤。”

In [4]:
#turtle 绘制樱花树(可能需本地运行)
import turtle as t
import random

t.setup(800, 600)
t.bgcolor("white")
t.colormode(255)
t.speed(0)
t.hideturtle()

def draw_branch(length):
    if length < 10:
        t.color(255, 192, 203)  # 粉色花瓣
        t.begin_fill()
        t.circle(3)
        t.end_fill()
        t.color(139, 69, 19)    # 还原树枝颜色
        return
    t.pensize(max(1, length/10))
    t.color(139, 69, 19)  # 棕色枝干
    t.forward(length)
    ang = random.randint(15, 30)
    dec = random.uniform(0.7, 0.8)
    t.right(ang)
    draw_branch(length * dec)
    t.left(2*ang)
    draw_branch(length * dec)
    t.right(ang)
    t.backward(length)

t.left(90)
t.up()
t.backward(200)
t.down()
draw_branch(100)
t.done()

6.6.2 使用 pygame 创建俄罗斯方块(简化框架)¶

提示词示例:

“请用 pygame 写一个简化的俄罗斯方块,包含下落、消行、计分与暂停。”

In [11]:
import pygame
import random
import time

# 初始化pygame
pygame.init()

# 游戏常量
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
GRID_SIZE = 30
GRID_WIDTH = 10
GRID_HEIGHT = 20
SIDEBAR_WIDTH = 200

# 颜色定义
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 120, 255)
YELLOW = (255, 255, 0)
PURPLE = (180, 0, 255)
CYAN = (0, 255, 255)
ORANGE = (255, 165, 0)
GRAY = (128, 128, 128)
BORDER_COLOR = (50, 50, 50)

# 方块形状定义
SHAPES = [
    [[1, 1, 1, 1]],  # I
    [[1, 1], [1, 1]],  # O
    [[1, 1, 1], [0, 1, 0]],  # T
    [[1, 1, 1], [1, 0, 0]],  # L
    [[1, 1, 1], [0, 0, 1]],  # J
    [[0, 1, 1], [1, 1, 0]],  # S
    [[1, 1, 0], [0, 1, 1]]   # Z
]

# 方块颜色
SHAPE_COLORS = [CYAN, YELLOW, PURPLE, ORANGE, BLUE, GREEN, RED]

# 创建游戏窗口
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("Tetris")

# 游戏时钟
clock = pygame.time.Clock()

# 字体
font = pygame.font.SysFont(None, 36)
small_font = pygame.font.SysFont(None, 24)

class Tetromino:
    def __init__(self):
        self.shape_index = random.randint(0, len(SHAPES) - 1)
        self.shape = SHAPES[self.shape_index]
        self.color = SHAPE_COLORS[self.shape_index]
        self.x = GRID_WIDTH // 2 - len(self.shape[0]) // 2
        self.y = 0
    
    def rotate(self):
        # 旋转方块 (转置然后反转每一行)
        rotated = [[self.shape[y][x] for y in range(len(self.shape)-1, -1, -1)] 
                  for x in range(len(self.shape[0]))]
        return rotated

class TetrisGame:
    def __init__(self):
        self.board = [[0 for _ in range(GRID_WIDTH)] for _ in range(GRID_HEIGHT)]
        self.current_piece = Tetromino()
        self.next_piece = Tetromino()
        self.game_over = False
        self.score = 0
        self.level = 1
        self.lines_cleared = 0
        self.paused = False
        self.fall_speed = 0.5  # 初始下落速度(秒)
        self.last_fall_time = time.time()
    
    def new_piece(self):
        self.current_piece = self.next_piece
        self.next_piece = Tetromino()
        
        # 检查游戏是否结束
        if self.check_collision(self.current_piece.shape, self.current_piece.x, self.current_piece.y):
            self.game_over = True
    
    def check_collision(self, shape, x, y):
        for i in range(len(shape)):
            for j in range(len(shape[0])):
                if shape[i][j]:
                    if (y + i >= GRID_HEIGHT or 
                        x + j < 0 or 
                        x + j >= GRID_WIDTH or 
                        (y + i >= 0 and self.board[y + i][x + j])):
                        return True
        return False
    
    def merge_piece(self):
        for i in range(len(self.current_piece.shape)):
            for j in range(len(self.current_piece.shape[0])):
                if self.current_piece.shape[i][j]:
                    if self.current_piece.y + i >= 0:  # 确保不在顶部之外
                        self.board[self.current_piece.y + i][self.current_piece.x + j] = self.current_piece.color
    
    def clear_lines(self):
        lines_to_clear = []
        for i in range(GRID_HEIGHT):
            if all(self.board[i]):
                lines_to_clear.append(i)
        
        for line in lines_to_clear:
            del self.board[line]
            self.board.insert(0, [0 for _ in range(GRID_WIDTH)])
        
        # 更新分数
        if lines_to_clear:
            self.lines_cleared += len(lines_to_clear)
            self.score += [100, 300, 500, 800][min(len(lines_to_clear) - 1, 3)] * self.level
            
            # 更新等级和下落速度
            self.level = self.lines_cleared // 10 + 1
            self.fall_speed = max(0.05, 0.5 - (self.level - 1) * 0.05)
    
    def move(self, dx, dy):
        if not self.check_collision(self.current_piece.shape, self.current_piece.x + dx, self.current_piece.y + dy):
            self.current_piece.x += dx
            self.current_piece.y += dy
            return True
        return False
    
    def rotate_piece(self):
        rotated = self.current_piece.rotate()
        if not self.check_collision(rotated, self.current_piece.x, self.current_piece.y):
            self.current_piece.shape = rotated
            return True
        return False
    
    def drop(self):
        while self.move(0, 1):
            pass
        self.merge_piece()
        self.clear_lines()
        self.new_piece()
    
    def update(self):
        if self.paused or self.game_over:
            return
        
        current_time = time.time()
        if current_time - self.last_fall_time > self.fall_speed:
            if not self.move(0, 1):
                self.merge_piece()
                self.clear_lines()
                self.new_piece()
            self.last_fall_time = current_time
    
    def draw(self):
        screen.fill(BLACK)
        
        # 绘制游戏区域边框
        pygame.draw.rect(screen, BORDER_COLOR, 
                        (GRID_SIZE, GRID_SIZE, 
                         GRID_WIDTH * GRID_SIZE, 
                         GRID_HEIGHT * GRID_SIZE), 2)
        
        # 绘制已落下的方块
        for i in range(GRID_HEIGHT):
            for j in range(GRID_WIDTH):
                if self.board[i][j]:
                    pygame.draw.rect(screen, self.board[i][j], 
                                    (j * GRID_SIZE + GRID_SIZE + 1, 
                                     i * GRID_SIZE + GRID_SIZE + 1, 
                                     GRID_SIZE - 2, GRID_SIZE - 2))
        
        # 绘制当前方块
        if not self.game_over:
            for i in range(len(self.current_piece.shape)):
                for j in range(len(self.current_piece.shape[0])):
                    if self.current_piece.shape[i][j]:
                        pygame.draw.rect(screen, self.current_piece.color, 
                                        ((self.current_piece.x + j) * GRID_SIZE + GRID_SIZE + 1, 
                                         (self.current_piece.y + i) * GRID_SIZE + GRID_SIZE + 1, 
                                         GRID_SIZE - 2, GRID_SIZE - 2))
        
        # 绘制侧边栏
        sidebar_x = GRID_WIDTH * GRID_SIZE + GRID_SIZE * 2
        
        # 绘制下一个方块预览
        next_text = font.render("Next:", True, WHITE)
        screen.blit(next_text, (sidebar_x, GRID_SIZE))
        
        # 绘制下一个方块
        for i in range(len(self.next_piece.shape)):
            for j in range(len(self.next_piece.shape[0])):
                if self.next_piece.shape[i][j]:
                    pygame.draw.rect(screen, self.next_piece.color, 
                                    (sidebar_x + j * GRID_SIZE, 
                                     GRID_SIZE * 3 + i * GRID_SIZE, 
                                     GRID_SIZE - 2, GRID_SIZE - 2))
        
        # 绘制分数
        score_text = font.render(f"Score: {self.score}", True, WHITE)
        screen.blit(score_text, (sidebar_x, GRID_SIZE * 8))
        
        # 绘制等级
        level_text = font.render(f"Level: {self.level}", True, WHITE)
        screen.blit(level_text, (sidebar_x, GRID_SIZE * 10))
        
        # 绘制已消除行数
        lines_text = font.render(f"Lines: {self.lines_cleared}", True, WHITE)
        screen.blit(lines_text, (sidebar_x, GRID_SIZE * 12))
        
        # 绘制控制说明
        controls_y = GRID_SIZE * 14
        controls = [
            "Controls:",
            "Left/Right: Move",
            "Up: Rotate",
            "Down: Speed up",
            "Space: Drop",
            "P: Pause/Resume"
        ]
        
        for i, text in enumerate(controls):
            control_text = small_font.render(text, True, WHITE)
            screen.blit(control_text, (sidebar_x, controls_y + i * 25))
        
        # 如果游戏暂停,显示暂停文本
        if self.paused:
            pause_text = font.render("PAUSED", True, WHITE)
            text_rect = pause_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2))
            screen.blit(pause_text, text_rect)
        
        # 如果游戏结束,显示游戏结束文本
        if self.game_over:
            game_over_text = font.render("GAME OVER", True, RED)
            restart_text = font.render("Press R to restart", True, WHITE)
            text_rect = game_over_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2 - 20))
            restart_rect = restart_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2 + 20))
            screen.blit(game_over_text, text_rect)
            screen.blit(restart_text, restart_rect)

# 创建游戏实例
game = TetrisGame()

# 游戏主循环
running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        
        if event.type == pygame.KEYDOWN:
            if not game.game_over:
                if event.key == pygame.K_LEFT:
                    game.move(-1, 0)
                elif event.key == pygame.K_RIGHT:
                    game.move(1, 0)
                elif event.key == pygame.K_DOWN:
                    game.move(0, 1)
                elif event.key == pygame.K_UP:
                    game.rotate_piece()
                elif event.key == pygame.K_SPACE:
                    game.drop()
                elif event.key == pygame.K_p:
                    game.paused = not game.paused
            
            if event.key == pygame.K_r and game.game_over:
                # 重新开始游戏
                game = TetrisGame()
    
    # 更新游戏状态
    game.update()
    
    # 绘制游戏
    game.draw()
    
    # 更新显示
    pygame.display.flip()
    
    # 控制游戏帧率
    clock.tick(60)

# 退出游戏
pygame.quit()

游戏功能说明¶

  1. 基本功能:

    • 方块下落:方块会按照当前等级的速度自动下落
    • 消行:当一行填满时,该行会被消除并计分
    • 计分:根据一次消除的行数给予不同分数
    • 暂停:按P键可以暂停和继续游戏
  2. 控制方式:

    • 左右箭头键:左右移动方块
    • 上箭头键:旋转方块
    • 下箭头键:加速下落
    • 空格键:直接下落到底部
    • P键:暂停/继续游戏
    • R键:游戏结束后重新开始
  3. 游戏机制:

    • 随着消除行数增加,等级会提高,下落速度会加快
    • 分数计算:1行=100分,2行=300分,3行=500分,4行=800分
    • 游戏区域右侧显示下一个方块、当前分数、等级和已消除行数

代码结构说明¶

  1. Tetromino类:表示俄罗斯方块的单个形状,包括形状数据、颜色和位置信息。

  2. TetrisGame类:游戏主逻辑,包含:

    • 游戏板状态管理
    • 方块移动、旋转和碰撞检测
    • 消行和计分逻辑
    • 游戏状态更新和绘制
  3. 游戏主循环:

    • 处理用户输入
    • 更新游戏状态
    • 绘制游戏界面
    • 控制游戏帧率

这个简化版的俄罗斯方块游戏包含了所有基本功能,代码结构清晰,易于理解和扩展。

小结¶

本章系统讲解了函数(定义/调用/参数/返回值、类型、递归)与高阶函数(map/filter/reduce),并介绍了模块(导入、标准库、自定义、包、__name__)的用法,以及常见错误与排查。最后给出 turtle 与 pygame 的可视化示例提示与代码框架,便于结合大语言模型进行实践。

In [ ]: