Python代码实现2048,编写脚本

为2048编写脚本。豆包出现上下文数量限制,使用copilot完成后续。

copilot
import pygame
import random

# 初始化Pygame
pygame.init()

# 设置屏幕大小
screen = pygame.display.set_mode((400, 550))
pygame.display.set_caption("2048 Game with Auto Play")

# 定义颜色
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GRAY = (200, 200, 200)
LIGHT_GRAY = (220, 220, 220)
DARK_GRAY = (180, 180, 180)
TILE_COLORS = {
    0: (205, 193, 180),
    2: (238, 228, 218),
    4: (237, 224, 200),
    8: (242, 177, 121),
    16: (245, 149, 99),
    32: (246, 124, 95),
    64: (246, 94, 59),
    128: (237, 207, 114),
    256: (237, 204, 97),
    512: (237, 200, 80),
    1024: (237, 197, 63),
    2048: (237, 194, 46)
}

# 定义字体
font = pygame.font.Font(None, 36)
score_font = pygame.font.Font(None, 48)
flying_score_font = pygame.font.Font(None, 24)

# 初始化游戏板
board = [[0] * 4 for _ in range(4)]
score = 0
flying_scores = []

def add_new_tile():
    empty_tiles = [(r, c) for r in range(4) for c in range(4) if board[r][c] == 0]
    if empty_tiles:
        r, c = random.choice(empty_tiles)
        board[r][c] = 2 if random.random() < 0.9 else 4

def new_game():
    global board, score, auto_playing
    board = [[0] * 4 for _ in range(4)]
    score = 0
    auto_playing = False
    add_new_tile()
    add_new_tile()

def draw_board():
    screen.fill(WHITE)
    for r in range(4):
        for c in range(4):
            value = board[r][c]
            color = TILE_COLORS.get(value, (0, 0, 0))
            pygame.draw.rect(screen, color, (c * 100, r * 100, 98, 98))
            pygame.draw.rect(screen, DARK_GRAY, (c * 100, r * 100, 98, 98), 2)
            if value:
                text = font.render(str(value), True, BLACK)
                screen.blit(text, (c * 100 + 50 - text.get_width() // 2, r * 100 + 50 - text.get_height() // 2))

    # 绘制自动播放按钮
    mouse_pos = pygame.mouse.get_pos()
    auto_play_button_rect = pygame.Rect(150, 420, 100, 50)
    if auto_play_button_rect.collidepoint(mouse_pos):
        button_color = LIGHT_GRAY
    else:
        button_color = GRAY
    pygame.draw.rect(screen, button_color, auto_play_button_rect)
    text = font.render("Auto Play", True, BLACK)
    screen.blit(text, (150 + 50 - text.get_width() // 2, 420 + 25 - text.get_height() // 2))

    # 绘制新游戏按钮
    new_game_button_rect = pygame.Rect(150, 480, 100, 50)
    if new_game_button_rect.collidepoint(mouse_pos):
        button_color = LIGHT_GRAY
    else:
        button_color = GRAY
    pygame.draw.rect(screen, button_color, new_game_button_rect)
    text = font.render("New Game", True, BLACK)
    screen.blit(text, (150 + 50 - text.get_width() // 2, 480 + 25 - text.get_height() // 2))

    # 显示分数
    score_text = score_font.render(f"Score: {score}", True, BLACK)
    screen.blit(score_text, (10, 10))

    # 绘制飞入的分数特效
    new_flying_scores = []
    for flying_score in flying_scores:
        value, x, y, alpha = flying_score
        alpha -= 5
        if alpha > 0:
            text = flying_score_font.render(f"+{value}", True, (255, 0, 0, alpha))
            text.set_alpha(alpha)
            screen.blit(text, (x, y))
            new_flying_scores.append((value, x, y - 1, alpha))
    flying_scores[:] = new_flying_scores

    pygame.display.flip()

def evaluate_board(current_board):
    """
    评估游戏板的得分,考虑合并次数和大数字的集中程度
    """
    merge_count = 0
    max_value = 0
    for r in range(4):
        for c in range(4):
            if r < 3 and current_board[r][c] == current_board[r + 1][c]:
                merge_count += 1
            if c < 3 and current_board[r][c] == current_board[r][c + 1]:
                merge_count += 1
            max_value = max(max_value, current_board[r][c])
    # 合并次数权重较高,大数字权重次之
    return merge_count * 10 + max_value

def auto_play():
    directions = ["up", "down", "left", "right"]
    best_score = -1
    best_direction = None

    for direction in directions:
        new_board = [row[:] for row in board]  # 复制当前游戏板
        temp_score = score
        move_board(direction, new_board)  # 尝试移动
        new_score = evaluate_board(new_board) + temp_score  # 计算新得分

        # 检查移动是否有效(即新游戏板与原游戏板不同)
        if new_board != board and new_score > best_score:
            best_score = new_score
            best_direction = direction

    if best_direction:
        move_board(best_direction)
    else:
        # 如果所有方向都无法移动,游戏结束
        global auto_playing
        auto_playing = False
        print(f"Game Over! Final Score: {score}")

def move_board(direction, current_board=None):
    global score, flying_scores
    if current_board is None:
        current_board = board

    def slide(row):
        global score, flying_scores
        new_row = [i for i in row if i != 0]
        added_score = 0
        for i in range(len(new_row) - 1):
            if new_row[i] == new_row[i + 1]:
                new_row[i] *= 2
                added_score += new_row[i]
                new_row[i + 1] = 0
        new_row = [i for i in new_row if i != 0]
        if current_board is board:
            score += added_score
            if added_score > 0:
                # 找到合并位置添加飞入分数特效
                for r in range(4):
                    for c in range(4):
                        if current_board[r][c] == new_row[0]:
                            flying_scores.append((added_score, c * 100 + 50, r * 100 + 50, 255))
        return new_row + [0] * (4 - len(new_row))

    moved = False
    if direction == "left":
        for i in range(4):
            new_row = slide(current_board[i])
            if new_row != current_board[i]:
                moved = True
            current_board[i] = new_row
    elif direction == "right":
        for i in range(4):
            new_row = slide(current_board[i][::-1])[::-1]
            if new_row != current_board[i]:
                moved = True
            current_board[i] = new_row
    elif direction == "up":
        for i in range(4):
            col = slide([current_board[r][i] for r in range(4)])
            if col != [current_board[r][i] for r in range(4)]:
                moved = True
            for r in range(4):
                current_board[r][i] = col[r]
    elif direction == "down":
        for i in range(4):
            col = slide([current_board[r][i] for r in range(4)][::-1])[::-1]
            if col != [current_board[r][i] for r in range(4)]:
                moved = True
            for r in range(4):
                current_board[r][i] = col[r]

    if moved and current_board is board:
        add_new_tile()

# 定义按钮矩形
auto_play_button_rect = pygame.Rect(150, 420, 100, 50)
new_game_button_rect = pygame.Rect(150, 480, 100, 50)

# 添加事件处理逻辑
running = True
auto_playing = False
move_delay = 100  # 步骤执行间隔为0.5秒
last_move_time = 0

new_game()  # 初始化游戏

while running:
    current_time = pygame.time.get_ticks()

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.MOUSEBUTTONDOWN:
            mouse_pos = event.pos
            if auto_play_button_rect.collidepoint(mouse_pos):
                auto_playing = not auto_playing
                last_move_time = current_time
            elif new_game_button_rect.collidepoint(mouse_pos):
                new_game()
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_UP:
                move_board("up")
            elif event.key == pygame.K_DOWN:
                move_board("down")
            elif event.key == pygame.K_LEFT:
                move_board("left")
            elif event.key == pygame.K_RIGHT:
                move_board("right")
            last_move_time = current_time

    if auto_playing and current_time - last_move_time > move_delay:
        auto_play()
        last_move_time = current_time

    draw_board()

pygame.quit()

下面是豆包给的详细注释

import pygame
import random

# 初始化 Pygame 库,为后续使用 Pygame 的各种功能做准备
pygame.init()

# 设置游戏窗口的大小,这里创建了一个宽 400 像素、高 550 像素的窗口
screen = pygame.display.set_mode((400, 550))
# 设置游戏窗口的标题
pygame.display.set_caption("2048 Game with Auto Play")

# 定义游戏中使用的各种颜色,以 RGB 元组的形式表示
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GRAY = (200, 200, 200)
LIGHT_GRAY = (220, 220, 220)
DARK_GRAY = (180, 180, 180)
# 定义不同数字方块对应的背景颜色
TILE_COLORS = {
    0: (205, 193, 180),
    2: (238, 228, 218),
    4: (237, 224, 200),
    8: (242, 177, 121),
    16: (245, 149, 99),
    32: (246, 124, 95),
    64: (246, 94, 59),
    128: (237, 207, 114),
    256: (237, 204, 97),
    512: (237, 200, 80),
    1024: (237, 197, 63),
    2048: (237, 194, 46)
}

# 定义游戏中使用的字体,None 表示使用系统默认字体,后面的数字是字体大小
font = pygame.font.Font(None, 36)
score_font = pygame.font.Font(None, 48)
flying_score_font = pygame.font.Font(None, 24)

# 初始化游戏板,创建一个 4x4 的二维列表,初始值都为 0
board = [[0] * 4 for _ in range(4)]
# 初始化游戏得分
score = 0
# 用于存储飞入分数特效的列表,每个元素是一个元组 (分数值, x 坐标, y 坐标, 透明度)
flying_scores = []

def add_new_tile():
    """
    在游戏板的空白格子中随机添加一个新的数字方块,90% 的概率是 2,10% 的概率是 4
    """
    # 找出游戏板中所有值为 0 的空白格子的坐标
    empty_tiles = [(r, c) for r in range(4) for c in range(4) if board[r][c] == 0]
    if empty_tiles:
        # 从空白格子中随机选择一个坐标
        r, c = random.choice(empty_tiles)
        # 以 90% 的概率添加数字 2,10% 的概率添加数字 4
        board[r][c] = 2 if random.random() < 0.9 else 4

def draw_board():
    """
    绘制游戏界面,包括游戏板、按钮、分数以及飞入的分数特效
    """
    # 用白色填充整个屏幕,清空之前的绘制内容
    screen.fill(WHITE)
    # 遍历游戏板的每一行
    for r in range(4):
        # 遍历游戏板的每一列
        for c in range(4):
            # 获取当前格子的值
            value = board[r][c]
            # 根据格子的值从颜色字典中获取对应的颜色,如果值不在字典中则使用黑色
            color = TILE_COLORS.get(value, (0, 0, 0))
            # 在屏幕上绘制当前格子的背景矩形
            pygame.draw.rect(screen, color, (c * 100, r * 100, 98, 98))
            # 在格子周围绘制深灰色的边框
            pygame.draw.rect(screen, DARK_GRAY, (c * 100, r * 100, 98, 98), 2)
            # 如果格子的值不为 0,则在格子中心绘制对应的数字
            if value:
                # 渲染数字文本
                text = font.render(str(value), True, BLACK)
                # 将文本居中绘制在格子内
                screen.blit(text, (c * 100 + 50 - text.get_width() // 2, r * 100 + 50 - text.get_height() // 2))

    # 绘制自动播放按钮
    # 获取鼠标当前位置
    mouse_pos = pygame.mouse.get_pos()
    # 定义自动播放按钮的矩形区域
    auto_play_button_rect = pygame.Rect(150, 420, 100, 50)
    # 检查鼠标是否悬停在自动播放按钮上
    if auto_play_button_rect.collidepoint(mouse_pos):
        # 鼠标悬停时按钮使用浅灰色
        button_color = LIGHT_GRAY
    else:
        # 鼠标未悬停时按钮使用灰色
        button_color = GRAY
    # 绘制自动播放按钮的矩形
    pygame.draw.rect(screen, button_color, auto_play_button_rect)
    # 渲染自动播放按钮的文本
    text = font.render("Auto Play", True, BLACK)
    # 将文本居中绘制在按钮内
    screen.blit(text, (150 + 50 - text.get_width() // 2, 420 + 25 - text.get_height() // 2))

    # 绘制新游戏按钮
    # 定义新游戏按钮的矩形区域
    new_game_button_rect = pygame.Rect(150, 480, 100, 50)
    # 检查鼠标是否悬停在新游戏按钮上
    if new_game_button_rect.collidepoint(mouse_pos):
        # 鼠标悬停时按钮使用浅灰色
        button_color = LIGHT_GRAY
    else:
        # 鼠标未悬停时按钮使用灰色
        button_color = GRAY
    # 绘制新游戏按钮的矩形
    pygame.draw.rect(screen, button_color, new_game_button_rect)
    # 渲染新游戏按钮的文本
    text = font.render("New Game", True, BLACK)
    # 将文本居中绘制在按钮内
    screen.blit(text, (150 + 50 - text.get_width() // 2, 480 + 25 - text.get_height() // 2))

    # 显示分数
    # 渲染当前分数的文本
    score_text = score_font.render(f"Score: {score}", True, BLACK)
    # 将分数文本绘制在屏幕指定位置
    screen.blit(score_text, (10, 480))

    # 绘制飞入的分数特效
    # 用于存储更新后的飞入分数特效信息
    new_flying_scores = []
    # 遍历所有的飞入分数特效信息
    for flying_score in flying_scores:
        # 解包飞入分数特效的信息,包括分数值、位置和透明度
        value, x, y, alpha = flying_score
        # 每次绘制时降低透明度
        alpha -= 5
        # 如果透明度大于 0,则继续绘制特效
        if alpha > 0:
            # 渲染特效文本
            text = flying_score_font.render(f"+{value}", True, (255, 0, 0, alpha))
            # 设置文本的透明度
            text.set_alpha(alpha)
            # 将特效文本绘制在屏幕上
            screen.blit(text, (x, y))
            # 更新特效的位置并添加到新的列表中
            new_flying_scores.append((value, x, y - 1, alpha))
    # 更新飞入分数特效列表
    flying_scores[:] = new_flying_scores

    # 更新整个屏幕的显示
    pygame.display.flip()

def evaluate_board(current_board):
   
    """
    评估游戏板的得分,考虑合并次数和大数字的集中程度
    :param current_board: 当前的游戏板状态,是一个 4x4 的二维列表
    :return: 评估后的得分
    """
    # 初始化合并次数为 0
    merge_count = 0
    # 初始化最大数字为 0
    max_value = 0
    # 遍历游戏板的每一行
    for r in range(4):
        # 遍历游戏板的每一列
        for c in range(4):
            # 检查当前格子下方的格子,如果值相同则合并次数加 1
            if r < 3 and current_board[r][c] == current_board[r + 1][c]:
                merge_count += 1
            # 检查当前格子右方的格子,如果值相同则合并次数加 1
            if c < 3 and current_board[r][c] == current_board[r][c + 1]:
                merge_count += 1
            # 更新最大数字
            max_value = max(max_value, current_board[r][c])
    # 合并次数权重较高,大数字权重次之,计算最终得分
    return merge_count * 10 + max_value

def auto_play():
    """
    自动游戏模式,尝试找到最优的移动方向并执行移动
    """
    # 定义可移动的方向列表
    directions = ["up", "down", "left", "right"]
    # 初始化最佳得分,设为 -1
    best_score = -1
    # 初始化最佳移动方向为 None
    best_direction = None

    # 遍历所有可能的移动方向
    for direction in directions:
        # 复制当前游戏板,避免修改原游戏板
        new_board = [row[:] for row in board]
        # 保存当前得分
        temp_score = score
        # 尝试在复制的游戏板上执行移动操作
        move_board(direction, new_board)
        # 计算移动后的新得分
        new_score = evaluate_board(new_board) + temp_score

        # 检查移动是否有效(即新游戏板与原游戏板不同),并且新得分是否大于最佳得分
        if new_board != board and new_score > best_score:
            # 更新最佳得分
            best_score = new_score
            # 更新最佳移动方向
            best_direction = direction

    # 如果找到了最佳移动方向
    if best_direction:
        # 在原游戏板上执行最佳移动操作
        move_board(best_direction)
    else:
        # 如果所有方向都无法移动,游戏结束
        global auto_playing
        auto_playing = False
        print(f"Game Over! Final Score: {score}")

def move_board(direction, current_board=None):
    """
    根据指定方向移动游戏板上的数字方块,并处理合并和得分
    :param direction: 移动方向,可选值为 "up", "down", "left", "right"
    :param current_board: 可选参数,指定要操作的游戏板,默认为当前游戏板
    """
    global score, flying_scores
    # 如果未指定游戏板,则使用当前游戏板
    if current_board is None:
        current_board = board

    def slide(row):
        """
        辅助函数,用于将一行数字方块进行滑动和合并操作
        :param row: 一行数字方块,是一个列表
        :return: 滑动和合并后的行
        """
        global score, flying_scores
        # 移除行中的所有 0,得到一个只包含非零数字的列表
        new_row = [i for i in row if i != 0]
        # 初始化合并得到的额外得分
        added_score = 0
        # 遍历非零数字列表,检查相邻数字是否相同,如果相同则合并
        for i in range(len(new_row) - 1):
            if new_row[i] == new_row[i + 1]:
                # 合并相邻相同数字,将前一个数字翻倍
                new_row[i] *= 2
                # 增加合并得到的额外得分
                added_score += new_row[i]
                # 将后一个数字置为 0
                new_row[i + 1] = 0
        # 移除合并后产生的 0
        new_row = [i for i in new_row if i != 0]
        # 如果操作的是当前游戏板
        if current_board is board:
            # 更新总得分
            score += added_score
            if added_score > 0:
                # 找到合并位置添加飞入分数特效
                for r in range(4):
                    for c in range(4):
                        if current_board[r][c] == new_row[0]:
                            flying_scores.append((added_score, c * 100 + 50, r * 100 + 50, 255))
        # 在新行末尾补 0,使其长度为 4
        return new_row + [0] * (4 - len(new_row))

    # 标记是否有移动发生
    moved = False
    if direction == "left":
        # 向左移动,对每一行进行滑动操作
        for i in range(4):
            new_row = slide(current_board[i])
            if new_row != current_board[i]:
                moved = True
            current_board[i] = new_row
    elif direction == "right":
        # 向右移动,先将每一行反转,进行滑动操作后再反转回来
        for i in range(4):
            new_row = slide(current_board[i][::-1])[::-1]
            if new_row != current_board[i]:
                moved = True
            current_board[i] = new_row
    elif direction == "up":
        # 向上移动,对每一列进行滑动操作
        for i in range(4):
            col = slide([current_board[r][i] for r in range(4)])
            if col != [current_board[r][i] for r in range(4)]:
                moved = True
            for r in range(4):
                current_board[r][i] = col[r]
    elif direction == "down":
        # 向下移动,先将每一列反转,进行滑动操作后再反转回来
        for i in range(4):
            col = slide([current_board[r][i] for r in range(4)][::-1])[::-1]
            if col != [current_board[r][i] for r in range(4)]:
                moved = True
            for r in range(4):
                current_board[r][i] = col[r]

    # 如果有移动发生,并且操作的是当前游戏板
    if moved and current_board is board:
        # 在空白格子中添加一个新的数字方块
        add_new_tile()

# 定义自动播放按钮的矩形区域
auto_play_button_rect = pygame.Rect(150, 420, 100, 50)
# 定义新游戏按钮的矩形区域
new_game_button_rect = pygame.Rect(150, 480, 100, 50)

# 游戏主循环是否运行的标志
running = True
# 自动播放模式的标志
auto_playing = False
# 自动播放时每次移动的延迟时间(毫秒)
move_delay = 100
# 记录上次移动的时间
last_move_time = 0

def new_game():
    """
    开始新游戏,重置游戏板、得分和自动播放标志,并添加两个初始数字方块
    """
    global board, score, auto_playing
    # 重置游戏板为全 0
    board = [[0] * 4 for _ in range(4)]
    # 重置得分
    score = 0
    # 关闭自动播放模式
    auto_playing = False
    # 添加第一个初始数字方块
    add_new_tile()
    # 添加第二个初始数字方块
    add_new_tile()

# 开始新游戏
new_game()

# 游戏主循环
while running:
    # 获取当前时间(毫秒)
    current_time = pygame.time.get_ticks()

    # 处理所有的 Pygame 事件
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            # 如果用户点击关闭窗口按钮,退出游戏主循环
            running = False
        elif event.type == pygame.MOUSEBUTTONDOWN:
            # 如果用户点击鼠标
            mouse_pos = event.pos
            if auto_play_button_rect.collidepoint(mouse_pos)
                mouse_pos = event.pos
            if auto_play_button_rect.collidepoint(mouse_pos):
                # 若点击自动播放按钮,切换自动播放状态
                auto_playing = not auto_playing
                # 记录当前时间作为上次移动时间
                last_move_time = current_time
            elif new_game_button_rect.collidepoint(mouse_pos):
                # 若点击新游戏按钮,开始新游戏
                new_game()
        elif event.type == pygame.KEYDOWN:
            # 若用户按下键盘按键
            if event.key == pygame.K_UP:
                # 按下上方向键,向上移动方块
                move_board("up")
            elif event.key == pygame.K_DOWN:
                # 按下下方向键,向下移动方块
                move_board("down")
            elif event.key == pygame.K_LEFT:
                # 按下左方向键,向左移动方块
                move_board("left")
            elif event.key == pygame.K_RIGHT:
                # 按下右方向键,向右移动方块
                move_board("right")
            # 记录当前时间作为上次移动时间
            last_move_time = current_time

    # 若处于自动播放模式,且距离上次移动的时间超过设定的延迟
    if auto_playing and current_time - last_move_time > move_delay:
        # 执行自动播放逻辑
        auto_play()
        # 记录当前时间作为上次移动时间
        last_move_time = current_time

    # 绘制游戏界面
    draw_board()

# 退出 Pygame,释放资源
pygame.quit()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值