基于机器学习的AI俄罗斯方块游戏(框架:python)

在经典的游戏领域,俄罗斯方块无疑占据了重要的一席之地。自其诞生以来,这款简单而又富有挑战性的游戏便吸引了无数玩家的青睐。而今,随着人工智能技术的飞速发展,将机器学习应用于传统游戏中已成为一个热门话题。本文将详细介绍如何使用Python及其相关库,结合机器学习算法,开发一款具备AI智能的俄罗斯方块游戏。

一、项目背景与目标

1.1 项目背景

俄罗斯方块是一款经典的休闲益智游戏,玩家需要控制不同形状的方块下落,并旋转、移动这些方块,以填满游戏的每一行。每填满一行,这些行就会消失,并为玩家腾出空间继续游戏。随着游戏的进行,方块下落的速度会逐渐加快,增加了游戏的挑战性。

1.2 项目目标

本项目旨在通过Python编程语言,结合机器学习技术,实现一个具备AI智能的俄罗斯方块游戏。具体目标包括:

  • 设计并实现一个基本的俄罗斯方块游戏框架。
  • 集成机器学习算法,让AI能够自动进行方块的旋转、移动和下落操作。
  • 提供用户交互界面,允许玩家与AI进行对战或观察AI游戏过程。
  • 实现AI性能的可视化展示,包括得分、等级等信息。

二、技术选型与工具

2.1 Python编程语言

Python因其简洁的语法、丰富的库支持和强大的社区资源,成为实现本项目的首选编程语言。

2.2 Pygame库

Pygame是一个跨平台的Python模块,专为电子游戏开发设计,提供了图形和声音库,用于创建视频游戏。它非常适合用来实现俄罗斯方块的图形界面。

2.3 NumPy库

NumPy是Python的一个扩展库,支持大量的维度数组与矩阵运算,为AI算法中的数据处理提供了极大便利。

2.4 机器学习算法

虽然俄罗斯方块游戏本质上并非典型的机器学习应用场景,但可以通过模拟人类玩家的决策过程,设计一套基于规则的AI系统。同时,也可以探索使用强化学习等算法来训练AI模型,以进一步提升游戏表现。

三、系统设计与实现

3.1 游戏框架设计

游戏框架主要包括以下几个部分:

  • 游戏界面:使用Pygame库绘制游戏界面,包括游戏区域、下一个方块预览、得分显示等。
  • 方块控制:实现方块的生成、旋转、移动和下落逻辑。
  • 游戏逻辑:处理游戏得分、等级提升、游戏结束判断等逻辑。
  • AI控制:集成机器学习算法或预设规则,实现AI自动操作。

3.2 AI设计思路

AI的设计可以采用多种策略,包括但不限于以下几种:

  • 预设规则:根据游戏状态(如当前方块形状、游戏区域填满情况等),预设一系列规则来决定方块的旋转、移动和下落。
  • 模拟退火算法:通过模拟物理退火过程,在解空间中寻找最优解,以指导AI的决策。
  • 强化学习:利用强化学习算法,通过与环境(即游戏)的交互来学习最优策略。这通常需要大量的训练数据和计算资源。

在本项目中,我们将主要采用预设规则来实现AI,并简单探讨强化学习的应用前景。

3.3 关键代码实现

3.3.1 游戏界面绘制

使用Pygame绘制游戏界面,包括游戏区域、得分板、等级显示等。

3.3.2 AI决策逻辑

AI通过预设规则来决定方块的旋转、移动和下落。
四、系统测试与优化

4.1 测试方案

  • 单元测试:针对游戏框架的各个模块编写单元测试,确保每个功能按预期工作。
  • 集成测试:测试整个游戏系统的集成情况,确保各模块协同工作无误。
  • 性能测试:评估游戏在不同配置下的运行性能,确保流畅的游戏体验。

4.2 优化策略

  • 算法优化:对AI决策算法进行优化,提高决策效率和准确性。
  • 资源管理:优化游戏资源的使用,减少内存和CPU消耗。
  • 用户体验:改进用户界面和交互设计,提升用户体验。

五、结论与展望

本文介绍了一个基于Python的AI俄罗斯方块游戏的设计与实现过程。通过Pygame库构建游戏界面,结合NumPy库处理数据,我们实现了一个基本的俄罗斯方块游戏框架,并探讨了如何集成机器学习算法来提升游戏的AI智能。

然而,当前的AI实现仍较为简单,主要依赖于预设规则。未来工作可以进一步探索强化学习等高级机器学习算法在游戏AI中的应用,通过训练模型来学习更复杂的游戏策略。此外,还可以考虑增加网络对战功能,允许玩家与全球玩家进行实时对战,进一步提升游戏的趣味性和挑战性。

通过本项目的实践,我们不仅掌握了Python在游戏开发中的应用技巧,还深刻理解了机器学习在游戏AI中的潜力和挑战。相信随着技术的不断进步和创新思维的不断激发,未来的游戏世界将更加丰富多彩、充满惊喜。

完整代码:

import pygame
import random
import numpy as np
from collections import deque
import copy
from typing import List, Tuple

# 初始化 Pygame
pygame.init()

# 设置游戏窗口大小
WINDOW_WIDTH = 900  # 增大窗口宽度
WINDOW_HEIGHT = 920
screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
pygame.display.set_caption("俄罗斯方块 AI")

# 定义方块颜色
COLORS = [
    (0, 0, 0),
    (255, 0, 0),
    (0, 255, 0),
    (0, 0, 255),
    (255, 255, 0),
    (255, 0, 255),
    (0, 255, 255),
]

# 定义游戏网格大小
GRID_ROWS = 23
GRID_COLS = 12
BLOCK_SIZE = 40  # 稍微减小方块大小

# 定义方块的形状
SHAPES = [
    [[1, 1, 1, 1]],
    [[1, 1], [1, 1]],
    [[1, 0, 0], [1, 1, 1]],
    [[0, 0, 1], [1, 1, 1]],
    [[0, 1, 1], [1, 1, 0]],
    [[1, 1, 0], [0, 1, 1]],
    [[0, 1, 0], [1, 1, 1]],
    [[1, 1, 1, 1]],

]

# 定义按键重复延迟和间隔
KEY_REPEAT_DELAY = 100
KEY_REPEAT_INTERVAL = 5


# 定义游戏状态
class GameState:
    def __init__(self):
        self.board = np.zeros((GRID_ROWS, GRID_COLS), dtype=int)
        self.current_shape = random.choice(SHAPES)
        self.next_shape = random.choice(SHAPES)
        self.current_color = random.randint(1, len(COLORS) - 1)
        self.current_x = GRID_COLS // 2 - len(self.current_shape[0]) // 2
        self.current_y = 0
        self.score = 0
        self.level = 1
        self.lines_cleared = 0
        self.game_over = False # 游戏结束标志
        self.history = deque(maxlen=100)  # 保存最近 10 个游戏状态
        self.fall_time = 0 # 记录方块下落的时间
        self.fall_speed = 1.0  # 初始下落速度
        self.add_blocks_time = 0 # 添加底部方块的计时器
        self.add_blocks_interval = 1000000  # 每60秒添加一次底部方块
        self.ai_speed = 0.01  # AI 速度参数
        self.next_color = random.randint(1, len(COLORS) - 1)
        self.ai_rotation_speed = 0.01  # AI 旋转速度
        self.ai_move_speed = 0.01  # AI 平移速度
        self.ai_move_queue = []  # 存储 AI 的移动指令队列
    def update(self, dt):
        self.fall_time += dt
        if self.fall_time >= self.fall_speed:
            self.fall_time = 0
            self.current_y += 1
            if self.check_collision():
                self.current_y -= 1
                self.lock_shape()
                self.remove_full_rows()
                self.spawn_new_shape()
                if self.check_collision():
                    self.game_over = True

        self.add_blocks_time += dt
        if self.add_blocks_time >= self.add_blocks_interval:
            self.add_blocks_time = 0
            self.add_bottom_blocks()

    def move_left(self):
        self.current_x -= 1
        if self.check_collision():
            self.current_x += 1

    def move_right(self):
        self.current_x += 1
        if self.check_collision():
            self.current_x -= 1

    def rotate_shape(self):
        rotated_shape = list(zip(*reversed(self.current_shape)))
        old_shape = self.current_shape
        self.current_shape = rotated_shape
        if self.check_collision():
            self.current_shape = old_shape

    def soft_drop(self):
        self.current_y += 1
        if self.check_collision():
            self.current_y -= 1
            self.lock_shape()
            self.remove_full_rows()
            self.spawn_new_shape()
            if self.check_collision():
                self.game_over = True

    def hard_drop(self):
        while not self.check_collision():
            self.current_y += 1
        self.current_y -= 1
        self.lock_shape()
        self.remove_full_rows()
        self.spawn_new_shape()
        if self.check_collision():
            self.game_over = True

    def check_collision(self):
        for y, row in enumerate(self.current_shape):
            for x, cell in enumerate(row):
                if cell:
                    if (self.current_y + y >= GRID_ROWS or
                            self.current_x + x < 0 or
                            self.current_x + x >= GRID_COLS or
                            self.board[self.current_y + y][self.current_x + x]):
                        return True
        return False

    def lock_shape(self):
        for y, row in enumerate(self.current_shape):
            for x, cell in enumerate(row):
                if cell:
                    self.board[self.current_y + y][self.current_x + x] = self.current_color

    def remove_full_rows(self):
        full_rows = [i for i, row in enumerate(self.board) if all(row)]
        if full_rows:
            print(f"Removing full rows: {full_rows}")  # 添加日志记录

            # 删除满行
            self.board = np.delete(self.board, full_rows, axis=0)

            # 在顶部添加新的空行
            new_rows = np.zeros((len(full_rows), GRID_COLS), dtype=int)
            self.board = np.vstack((new_rows, self.board))

            cleared_rows = len(full_rows)
            self.lines_cleared += cleared_rows

            # 根据消除的行数计算得分
            if cleared_rows == 1:
                self.score += 100
            elif cleared_rows == 2:
                self.score += 300
            elif cleared_rows == 3:
                self.score += 700
            elif cleared_rows == 4:
                self.score += 1500

            self.level = self.lines_cleared // 100 + 1
            self.fall_speed = max(0.5, 1.0 - (self.level - 1) * 0.05)

            print(f"Cleared {cleared_rows} rows. New score: {self.score}, New level: {self.level}")
    def spawn_new_shape(self):
        self.current_shape = self.next_shape
        self.current_color = self.next_color
        self.next_shape = random.choice(SHAPES)
        self.next_color = random.randint(1, len(COLORS) - 1)
        self.current_x = GRID_COLS // 2 - len(self.current_shape[0]) // 2
        self.current_y = 0


    def add_bottom_blocks(self):
        # 将现有方块向上移动两行
        self.board = np.roll(self.board, -2, axis=0)

        # 在底部两行添加交错的方块
        for i in range(GRID_ROWS - 2, GRID_ROWS):
            for j in range(GRID_COLS):
                if (i + j) % 2 == 0:
                    self.board[i][j] = random.randint(1, len(COLORS) - 1)
                else:
                    self.board[i][j] = 0

        # 检查游戏是否结束
        if np.any(self.board[0] != 0) or np.any(self.board[1] != 0):
            self.game_over = True

    def clear_screen(self):
        self.board = np.zeros((GRID_ROWS, GRID_COLS), dtype=int)

    def execute_ai_move(self, rotation, move):
        self.ai_move_queue = []
        for _ in range(rotation):
            self.ai_move_queue.append(('rotate', None))
        if move < 0:
            for _ in range(abs(move)):
                self.ai_move_queue.append(('move', 'left'))
        elif move > 0:
            for _ in range(move):
                self.ai_move_queue.append(('move', 'right'))
        self.ai_move_queue.append(('drop', None))

    def process_ai_move(self):
        if self.ai_move_queue:
            action, direction = self.ai_move_queue.pop(0)
            if action == 'rotate':
                self.rotate_shape()
            elif action == 'move':
                if direction == 'left':
                    self.move_left()
                elif direction == 'right':
                    self.move_right()
            elif action == 'drop':
                self.hard_drop()
            return True
        return False


class TetrisAI:
    def __init__(self, game_state, well_score_weight=5, i_piece_well_bonus=2000):
        self.game_state = game_state
        self.well_score_weight = well_score_weight
        self.i_piece_well_bonus = i_piece_well_bonus  # 新增:I型方块放入竖井的奖励分数

    def find_deepest_well(self, board):
        """
        找到最深竖井的列索引和深度。
        返回 (column_index, depth) 或 (None, None) 如果没有找到竖井。
        """
        max_depth = 0
        deepest_well_col = None
        for col in range(GRID_COLS):
            # 检查左右两边的高度
            left_height = GRID_ROWS
            right_height = GRID_ROWS
            if col > 0:
                left_height = np.argmax(board[:, col - 1] > 0)
            if col < GRID_COLS - 1:
                right_height = np.argmax(board[:, col + 1] > 0)
            current_height = np.argmax(board[:, col] > 0)
            # 检查是否为竖井(当前列比左右两列都低)
            if current_height > 0 and (left_height - current_height >= 4 or right_height - current_height >= 4):
                if GRID_ROWS - current_height > max_depth:
                    max_depth = GRID_ROWS - current_height
                    deepest_well_col = col
        return deepest_well_col, max_depth
    def get_best_move(self):
        best_score = float('-inf')
        best_rotation = 0
        best_move = 0

        for rotation in range(4):
            for move in range(-8, 9):
                score = self.evaluate_move(rotation, move)
                if score > best_score:
                    best_score = score
                    best_rotation = rotation
                    best_move = move

        # 检查是否可以强制放置长条
        if np.max(self.game_state.board > 0) > 10 and self.game_state.current_shape == [[1, 1, 1, 1]]:
            deepest_col, _ = self.find_deepest_well(self.game_state.board)
            if deepest_col is not None:
                # 尝试将长条放入最深竖井
                test_state = copy.deepcopy(self.game_state)
                test_state.current_x = deepest_col - len(test_state.current_shape[0]) // 2
                if not test_state.check_collision():
                    # 如果没有碰撞,则锁定方块并返回特殊标记(或None,表示已处理)
                    test_state.lock_shape()
                    self.game_state = test_state  # 直接更新游戏状态
                    return None, None  # 或其他特殊标记
        return best_rotation, best_move

    def try_force_place_i_piece_in_rightmost_well(game_state):
        # 假设这个函数实现了检测竖井和尝试放置长条的逻辑
        # 如果成功放置,返回True;否则返回False
        pass
    def evaluate_move(self, rotation, move):
        test_state = copy.deepcopy(self.game_state)

        for _ in range(rotation):
            test_state.rotate_shape()
        if move < 0:
            for _ in range(abs(move)):
                test_state.move_left()
        elif move > 0:
            for _ in range(move):
                test_state.move_right()

        while not test_state.check_collision():
            test_state.current_y += 1
        test_state.current_y -= 1

        test_state.lock_shape()

        # 检查游戏板的高度(这里简化为检查整个游戏板)
        max_height = np.max(self.game_state.board > 0)
        is_i_piece = self.game_state.current_shape == [[1, 1, 1, 1]]

        # 如果游戏板高度很高且当前是I型方块,则调整评估逻辑以优先考虑竖井
        if max_height > 13 and is_i_piece:
            # 可以在这里添加逻辑来检测竖井并尝试将I型方块放入竖井
            # 但由于这涉及到复杂的游戏板分析和可能的方块预览,我们在这里不实现它
            # 相反,我们只是在评估分数时给予一个额外的奖励来鼓励这种行为
            well_bonus = 1000  # 假设的额外奖励
        else:
            well_bonus = 0
        height = self.get_height(test_state.board)
        holes = self.count_holes(test_state.board)
        bumpiness = self.get_bumpiness(test_state.board)
        complete_lines = self.count_complete_lines(test_state.board)
        well_score = self.get_well_score(test_state.board)
        bonus_for_multiple_lines = 0
        if complete_lines >= 3:
            bonus_for_multiple_lines += 500  # 假设消除3行或更多行的额外奖励
        if complete_lines == 4:
            # 如果同时消除了4行,我们可以再给一个额外的奖励,或者增加上面的奖励
            bonus_for_multiple_lines += 1000  # 额外奖励,仅当消除4行时
        # 新增:检查是否为I型方块并是否放入了竖井
        i_piece_well_bonus = self.check_i_piece_in_well(test_state) * self.i_piece_well_bonus

        if height <= 11 and holes == 0:
            score = (complete_lines * -1000000 -
                height * 400 -
                holes * 2000000000 -
                bumpiness * 800 -
                well_score * self.well_score_weight * 10 +
                i_piece_well_bonus * 2000 + bonus_for_multiple_lines * 2000000000)   # 加入I型方块放入竖井的奖励
        elif height >= 12 or holes > 0:
            score = (complete_lines * 10000 -
                height * 40000 -
                holes * 2000000000 -
                bumpiness * 800 -
                well_score * self.well_score_weight * 10 +
                i_piece_well_bonus * 2000 + bonus_for_multiple_lines * 2000000000)   # 加入I型方块放入竖井的奖励
        return score

    def check_i_piece_in_well(self, test_state):
        # 检查是否为I型方块
        if test_state.current_shape == [[1, 1, 1, 1]]:
            # 检查是否放入了竖井
            for col in range(GRID_COLS):
                if (col == 0 or np.all(test_state.board[:, col-1] != 0)) and \
                   (col == GRID_COLS-1 or np.all(test_state.board[:, col+1] != 0)) and \
                   np.all(test_state.board[:, col] == 0):
                    return 1  # 找到了竖井,并且I型方块放入其中
        return 0  # 不是I型方块或没有放入竖井
    def get_height(self, board):
        return GRID_ROWS - np.argmax(board.sum(axis=1) > 0)

    def count_holes(self, board):
        holes = 0
        for col in range(GRID_COLS):
            block_found = False
            for row in range(GRID_ROWS):
                if board[row][col]:
                    block_found = True
                elif block_found:
                    holes += 1
        return holes

    def get_bumpiness(self, board):
        heights = [0] * GRID_COLS
        for col in range(GRID_COLS):
            for row in range(GRID_ROWS):
                if board[row][col]:
                    heights[col] = GRID_ROWS - row
                    break
        return sum(abs(heights[i] - heights[i + 1]) for i in range(GRID_COLS - 1))

    def get_well_score(self, board):
        well_score = 0
        for col in range(GRID_COLS):
            # 检查当前列是否比左右两列(或边缘)低至少4格
            left_height = GRID_ROWS  # 假设左边没有方块,高度为网格行数
            right_height = GRID_ROWS  # 假设右边没有方块,高度为网格行数

            if col > 0:
                left_height = GRID_ROWS - np.argmax(board[:, col - 1] > 0)
            if col < GRID_COLS - 1:
                right_height = GRID_ROWS - np.argmax(board[:, col + 1] > 0)

            current_col_height = GRID_ROWS - np.argmax(board[:, col] > 0)

            # 如果当前列比左右两列都低至少4格,则认为是竖井的一部分
            if current_col_height >= 4 and (
                    left_height - current_col_height >= 4 or right_height - current_col_height >= 4):
                # 实际上,我们不需要检查两边都低4格,只要一边低4格就足够了
                # 但为了保持逻辑的清晰,这里还是按照两边都检查的方式写(虽然效率稍低)
                # 更优化的方式是只检查一边,并累加竖井长度
                well_start = col
                well_length = 1

                # 向左扩展竖井范围
                while well_start > 0 and GRID_ROWS - np.argmax(board[:, well_start - 1] > 0) - current_col_height >= 4:
                    well_start -= 1
                    well_length += 1

                    # 无需再向右扩展,因为我们已经检查了右边(除非你想要连续的低列都被算作一个竖井)
                # 但为了简化,我们只计算当前列作为竖井的一部分

                # 累加竖井分数(这里我们简单地将竖井长度作为分数)
                well_score += well_length

        return well_score
    def count_complete_lines(self, board):
        return sum(1 for row in board if all(row))


def render_game(screen, game_state, font, ai_enabled):
    # 绘制游戏区域背景
    pygame.draw.rect(screen, (0, 0, 0), (0, 0, GRID_COLS * BLOCK_SIZE, GRID_ROWS * BLOCK_SIZE))

    # 绘制游戏区域
    for y in range(GRID_ROWS):
        for x in range(GRID_COLS):
            color = COLORS[game_state.board[y][x]]
            pygame.draw.rect(screen, color, (x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE - 1, BLOCK_SIZE - 1))

    # 绘制当前方块
    for i in range(len(game_state.current_shape)):
        for j in range(len(game_state.current_shape[i])):
            if game_state.current_shape[i][j] == 1:
                x = game_state.current_x + j
                y = game_state.current_y + i
                color = COLORS[game_state.current_color]
                pygame.draw.rect(screen, color, (x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE - 1, BLOCK_SIZE - 1))

    # 绘制下一个方块
    next_shape_surface = pygame.Surface((6 * BLOCK_SIZE, 6 * BLOCK_SIZE))
    next_shape_surface.fill((255, 255, 255))
    for i in range(len(game_state.next_shape)):
        for j in range(len(game_state.next_shape[i])):
            if game_state.next_shape[i][j] == 1:
                color = COLORS[game_state.next_color]
                pygame.draw.rect(next_shape_surface, color, ((j+1) * BLOCK_SIZE, (i+1) * BLOCK_SIZE, BLOCK_SIZE - 1, BLOCK_SIZE - 1))
    screen.blit(next_shape_surface, (GRID_COLS * BLOCK_SIZE + 20, 20))

    # 绘制分数和等级
    score_text = font.render(f"Score: {game_state.score}", True, (0, 0, 0))
    level_text = font.render(f"Level: {game_state.level}", True, (0, 0, 0))
    lines_text = font.render(f"Lines: {game_state.lines_cleared}", True, (0, 0, 0))
    screen.blit(score_text, (GRID_COLS * BLOCK_SIZE + 20, 200))
    screen.blit(level_text, (GRID_COLS * BLOCK_SIZE + 20, 240))
    screen.blit(lines_text, (GRID_COLS * BLOCK_SIZE + 20, 280))

    # 绘制AI状态和速度
    ai_status = "ON" if ai_enabled else "OFF"
    ai_status_text = font.render(f"AI: {ai_status}", True, (0, 0, 0))
    ai_speed_text = font.render(f"AI Speed: {game_state.ai_speed:.3f}", True, (0, 0, 0))
    screen.blit(ai_status_text, (GRID_COLS * BLOCK_SIZE + 20, 320))
    screen.blit(ai_speed_text, (GRID_COLS * BLOCK_SIZE + 20, 360))
    ai_rotation_speed_text = font.render(f"AI Rotation Speed: {game_state.ai_rotation_speed:.3f}", True, (0, 0, 0))
    ai_move_speed_text = font.render(f"AI Move Speed: {game_state.ai_move_speed:.3f}", True, (0, 0, 0))
    screen.blit(ai_rotation_speed_text, (GRID_COLS * BLOCK_SIZE + 20, 400))
    screen.blit(ai_move_speed_text, (GRID_COLS * BLOCK_SIZE + 20, 440))
    # 绘制游戏说明
    instructions = [
        "Controls:",
        "Left/Right: Move",
        "Up: Rotate",
        "Down: Soft Drop",
        "Space: Hard Drop",
        "A: Toggle AI",
        "1/2 Arrows: Adjust AI Speed",
        "3/4 Arrows: Adjust AI Rotation Speed",
        "5/6 Arrows: Adjust AI Move Speed",
        "-: Remove Bottom Row",
        "=: Clear Screen"
    ]
    for i, instruction in enumerate(instructions):
        instruction_text = font.render(instruction, True, (0, 0, 0))
        screen.blit(instruction_text, (GRID_COLS * BLOCK_SIZE + 20, 500 + i * 30))

    # 绘制游戏结束文本
    if game_state.game_over:
        game_over_text = font.render("Game Over", True, (255, 0, 0))
        screen.blit(game_over_text, (WINDOW_WIDTH // 2 - 70, WINDOW_HEIGHT // 2 - 18))


def main():
    game_state = GameState()
    ai = TetrisAI(game_state, well_score_weight=20, i_piece_well_bonus=1000)
    clock = pygame.time.Clock()
    font = pygame.font.Font(None, 30)
    running = True
    ai_enabled = False

    pygame.key.set_repeat(KEY_REPEAT_DELAY, KEY_REPEAT_INTERVAL)

    ai_move_time = 0
    ai_rotation_time = 0
    ai_action_in_progress = False
    while running:
        dt = clock.tick(60) / 1000.0

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_a:
                    ai_enabled = not ai_enabled
                elif event.key == pygame.K_2:
                    game_state.ai_speed = min(1.0, game_state.ai_speed + 0.001)
                elif event.key == pygame.K_1:
                    game_state.ai_speed = max(0.001, game_state.ai_speed - 0.001)
                elif event.key == pygame.K_3:
                    game_state.ai_rotation_speed = max(0.001, game_state.ai_rotation_speed - 0.001)
                elif event.key == pygame.K_4:
                    game_state.ai_rotation_speed = min(1.0, game_state.ai_rotation_speed + 0.001)
                elif event.key == pygame.K_5:
                    game_state.ai_move_speed = max(0.001, game_state.ai_move_speed - 0.001)
                elif event.key == pygame.K_6:
                    game_state.ai_move_speed = min(1.0, game_state.ai_move_speed + 0.001)
                elif not ai_enabled:
                    if event.key == pygame.K_LEFT:
                        game_state.move_left()
                    elif event.key == pygame.K_RIGHT:
                        game_state.move_right()
                    elif event.key == pygame.K_DOWN:
                        game_state.soft_drop()
                    elif event.key == pygame.K_SPACE:
                        game_state.hard_drop()
                    elif event.key == pygame.K_UP:
                        game_state.rotate_shape()
                    elif event.key == pygame.K_MINUS:
                        game_state.remove_bottom_row()
                    elif event.key == pygame.K_EQUALS:
                        game_state.clear_screen()

        if not game_state.game_over:
            game_state.update(dt)

            if ai_enabled:
                if not ai_action_in_progress:
                    rotation, move = ai.get_best_move()
                    game_state.execute_ai_move(rotation, move)
                    ai_action_in_progress = True

                if ai_action_in_progress:
                    ai_move_time += dt
                    ai_rotation_time += dt
                    if game_state.ai_move_queue and game_state.ai_move_queue[0][0] == 'rotate':
                        if ai_rotation_time >= game_state.ai_rotation_speed:
                            ai_rotation_time = 0
                            game_state.process_ai_move()
                    elif ai_move_time >= game_state.ai_move_speed:
                        ai_move_time = 0
                        if not game_state.process_ai_move():
                            ai_action_in_progress = False

        screen.fill((255, 255, 255))
        render_game(screen, game_state, font, ai_enabled)
        pygame.display.flip()

        if game_state.game_over:
            pygame.time.wait(2000)  # 等待2秒
            running = False

    pygame.quit()
    print("Final Score:", game_state.score)

if __name__ == "__main__":
    main()

游戏演示:

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值