Python 绘制迷宫游戏,自带最优解路线

1、需要安装pygame
2、上下左右移动,空格实现物体所在位置到终点的路线,会有虚线绘制。
在这里插入图片描述

import pygame
import random
import math


# 迷宫单元格类
class Cell:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.walls = {'top': True, 'right': True, 'bottom': True, 'left': True}
        self.visited = False
        self.is_obstacle = False

    def draw(self, screen, cell_size):
        x = self.x * cell_size
        y = self.y * cell_size
        if self.walls['top']:
            pygame.draw.line(screen, (0, 0, 0), (x, y), (x + cell_size, y), 2)
        if self.walls['right']:
            pygame.draw.line(screen, (0, 0, 0), (x + cell_size, y), (x + cell_size, y + cell_size), 2)
        if self.walls['bottom']:
            pygame.draw.line(screen, (0, 0, 0), (x + cell_size, y + cell_size), (x, y + cell_size), 2)
        if self.walls['left']:
            pygame.draw.line(screen, (0, 0, 0), (x, y + cell_size), (x, y), 2)
        if self.is_obstacle:
            pygame.draw.rect(screen, (128, 128, 128), (x, y, cell_size, cell_size))

    def check_neighbors(self, grid, cols, rows):
        neighbors = []
        if self.x > 0:
            left = grid[self.y][self.x - 1]
            if not left.visited:
                neighbors.append(left)
        if self.x < cols - 1:
            right = grid[self.y][self.x + 1]
            if not right.visited:
                neighbors.append(right)
        if self.y > 0:
            top = grid[self.y - 1][self.x]
            if not top.visited:
                neighbors.append(top)
        if self.y < rows - 1:
            bottom = grid[self.y + 1][self.x]
            if not bottom.visited:
                neighbors.append(bottom)
        if neighbors:
            return random.choice(neighbors)
        else:
            return None


# 移除两个单元格之间的墙
def remove_walls(current, next_cell):
    dx = current.x - next_cell.x
    if dx == 1:
        current.walls['left'] = False
        next_cell.walls['right'] = False
    elif dx == -1:
        current.walls['right'] = False
        next_cell.walls['left'] = False
    dy = current.y - next_cell.y
    if dy == 1:
        current.walls['top'] = False
        next_cell.walls['bottom'] = False
    elif dy == -1:
        current.walls['bottom'] = False
        next_cell.walls['top'] = False


# 生成迷宫
def generate_maze(grid, cols, rows):
    stack = []
    current = grid[0][0]
    current.visited = True
    stack.append(current)
    while stack:
        current = stack[-1]
        next_cell = current.check_neighbors(grid, cols, rows)
        if next_cell:
            next_cell.visited = True
            stack.append(next_cell)
            remove_walls(current, next_cell)
        else:
            stack.pop()


# 随机添加障碍物
def add_obstacles(grid, cols, rows, obstacle_ratio=0.3):
    obstacle_cells = []
    num_obstacles = int(cols * rows * obstacle_ratio)
    while len(obstacle_cells) < num_obstacles:
        x = random.randint(0, cols - 1)
        y = random.randint(0, rows - 1)
        if (x, y) not in [(0, 0), (cols - 1, rows - 1)] and not grid[y][x].is_obstacle:
            grid[y][x].is_obstacle = True
            obstacle_cells.append((x, y))
    return obstacle_cells


# 检查从起点到终点是否有路径
def has_path(grid, start, end):
    path = find_path(grid, start, end)
    return bool(path)


# 移除障碍物直到有路径
def ensure_path_exists(grid, start, end, obstacle_cells):
    random.shuffle(obstacle_cells)
    while not has_path(grid, start, end) and obstacle_cells:
        x, y = obstacle_cells.pop()
        grid[y][x].is_obstacle = False


# 绘制迷宫
def draw_maze(screen, grid, cell_size, cols, rows):
    for i in range(rows):
        for j in range(cols):
            grid[i][j].draw(screen, cell_size)


# 绘制起点和终点
def draw_start_end(screen, cell_size, start, end):
    start_x = start[0] * cell_size + cell_size // 2
    start_y = start[1] * cell_size + cell_size // 2
    end_x = end[0] * cell_size + cell_size // 2
    end_y = end[1] * cell_size + cell_size // 2
    pygame.draw.circle(screen, (0, 255, 0), (start_x, start_y), cell_size // 3)
    pygame.draw.circle(screen, (255, 0, 0), (end_x, end_y), cell_size // 3)


# 绘制移动的物体
def draw_player(screen, cell_size, player_pos):
    player_x = player_pos[0] * cell_size + cell_size // 2
    player_y = player_pos[1] * cell_size + cell_size // 2
    pygame.draw.circle(screen, (0, 0, 255), (player_x, player_y), cell_size // 3)


# 检查是否可以移动
def can_move(grid, player_pos, direction):
    x, y = player_pos
    if direction == 'up':
        return y > 0 and not grid[y][x].walls['top'] and not grid[y - 1][x].is_obstacle
    elif direction == 'down':
        return y < len(grid) - 1 and not grid[y][x].walls['bottom'] and not grid[y + 1][x].is_obstacle
    elif direction == 'left':
        return x > 0 and not grid[y][x].walls['left'] and not grid[y][x - 1].is_obstacle
    elif direction == 'right':
        return x < len(grid[0]) - 1 and not grid[y][x].walls['right'] and not grid[y][x + 1].is_obstacle


# 广度优先搜索找到最优路径
def find_path(grid, start, end):
    queue = [(start, [start])]
    visited = set()
    while queue:
        (x, y), path = queue.pop(0)
        if (x, y) == end:
            return path
        if (x, y) not in visited:
            visited.add((x, y))
            if can_move(grid, (x, y), 'up'):
                new_path = list(path)
                new_path.append((x, y - 1))
                queue.append(((x, y - 1), new_path))
            if can_move(grid, (x, y), 'down'):
                new_path = list(path)
                new_path.append((x, y + 1))
                queue.append(((x, y + 1), new_path))
            if can_move(grid, (x, y), 'left'):
                new_path = list(path)
                new_path.append((x - 1, y))
                queue.append(((x - 1, y), new_path))
            if can_move(grid, (x, y), 'right'):
                new_path = list(path)
                new_path.append((x + 1, y))
                queue.append(((x + 1, y), new_path))
    return []


# 绘制虚线
def draw_dashed_line(screen, color, start_pos, end_pos, dash_length=5):
    dx = end_pos[0] - start_pos[0]
    dy = end_pos[1] - start_pos[1]
    distance = math.sqrt(dx ** 2 + dy ** 2)
    num_dashes = int(distance / dash_length)
    for i in range(num_dashes):
        if i % 2 == 0:
            start = (start_pos[0] + dx * i / num_dashes, start_pos[1] + dy * i / num_dashes)
            end = (start_pos[0] + dx * (i + 1) / num_dashes, start_pos[1] + dy * (i + 1) / num_dashes)
            pygame.draw.line(screen, color, start, end, 2)


# 显示提示信息
def show_message(screen, message, font, color, position):
    text = font.render(message, True, color)
    screen.blit(text, position)


# 主函数
def main():
    pygame.init()
    cols = 35
    rows = 35
    cell_size = 20
    width = cols * cell_size
    height = rows * cell_size
    screen = pygame.display.set_mode((width, height))
    pygame.display.set_caption("Random Maze")

    # 创建迷宫网格
    grid = [[Cell(j, i) for j in range(cols)] for i in range(rows)]

    # 生成迷宫
    generate_maze(grid, cols, rows)

    # 定义起点和终点
    start = (0, 0)
    end = (cols - 1, rows - 1)

    # 随机添加障碍物
    obstacle_cells = add_obstacles(grid, cols, rows)

    # 确保有路径
    ensure_path_exists(grid, start, end, obstacle_cells)

    # 初始化玩家位置
    player_pos = start

    font = pygame.font.Font(None, 36)
    success_text = font.render("Successfully!!!", True, (0, 255, 0))
    help_text = font.render("", True, (0, 0, 0))
    success = False
    auto_move = False

    running = True
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            elif event.type == pygame.KEYDOWN and not success:
                if event.key == pygame.K_UP:
                    if can_move(grid, player_pos, 'up'):
                        player_pos = (player_pos[0], player_pos[1] - 1)
                elif event.key == pygame.K_DOWN:
                    if can_move(grid, player_pos, 'down'):
                        player_pos = (player_pos[0], player_pos[1] + 1)
                elif event.key == pygame.K_LEFT:
                    if can_move(grid, player_pos, 'left'):
                        player_pos = (player_pos[0] - 1, player_pos[1])
                elif event.key == pygame.K_RIGHT:
                    if can_move(grid, player_pos, 'right'):
                        player_pos = (player_pos[0] + 1, player_pos[1])
                elif event.key == pygame.K_SPACE:
                    auto_move = True
                    path = find_path(grid, player_pos, end)
                    path_index = 0

        screen.fill((255, 255, 255))
        draw_maze(screen, grid, cell_size, cols, rows)
        draw_start_end(screen, cell_size, start, end)

        # 绘制路径
        if 'path' in locals() and path:
            for i in range(len(path) - 1):
                start_point = (path[i][0] * cell_size + cell_size // 2, path[i][1] * cell_size + cell_size // 2)
                end_point = (path[i + 1][0] * cell_size + cell_size // 2, path[i + 1][1] * cell_size + cell_size // 2)
                draw_dashed_line(screen, (255, 0, 0), start_point, end_point)

        draw_player(screen, cell_size, player_pos)

        # 显示提示信息
        show_message(screen, "", font, (0, 0, 0), (10, 10))

        if auto_move and 'path' in locals() and path_index < len(path):
            player_pos = path[path_index]
            path_index += 1
            if player_pos == end:
                auto_move = False

        if player_pos == end:
            success = True
            screen.blit(success_text,
                        (width // 2 - success_text.get_width() // 2, height // 2 - success_text.get_height() // 2))

        pygame.display.flip()
        pygame.time.delay(100)

    pygame.quit()


if __name__ == "__main__":
    main()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/980933.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【音视频】VLC播放器

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 一、vlc是什么&#xff1f; VLC Media Player&#xff08;简称VLC&#xff09;是一款免费、开源、跨平台的多媒体播放器&#xff0c;由非营利组织VideoLAN开发&#xff0c;最…

vue2+ele-ui实践

前言&#xff1a;真理先于实践&#xff0c;实践发现真理&#xff0c;再实践检验真理 环境&#xff1a;vue2 & element-ui 正片&#xff1a; Select 选择器 简称 下拉框 下拉框完整的使用循环 下拉框 → 点击下拉框 → 展示数据 → 选择数据 → 下拉框显示数据 核心具有…

刷题日记——部分二分算法题目分享

前言 咱们紧跟上一期结合时间复杂度浅谈二分法的好处, 并分享部分二分题目(将持续更新题目,绝对值你一个收藏)-CSDN博客 笔者接着分享一些刷过的关于二分算法的题目. 第一题 1283. 使结果不超过阈值的最小除数 - 力扣&#xff08;LeetCode&#xff09; 这道题就是典型的二…

excel 斜向拆分单元格

右键-合并单元格 右键-设置单元格格式-边框 在设置好分割线后&#xff0c;你可以开始输入文字。 需要注意的是&#xff0c;文字并不会自动分成上下两行。 为了达到你期望的效果&#xff0c;你可以通过 同过左对齐、上对齐 空格键或使用【AltEnter】组合键来调整单元格中内容的…

关于常规模式下运行VScode无法正确执行“pwsh”问题

前言&#xff1a; pwsh在系统环境中正确配置&#xff0c;且可以运行在cmd&#xff0c; powshell&#xff08;5.1&#xff09;--- 都需要在管理员权限下运行 &#xff08;打开setting&#xff09; 打开setting.json &#xff08;在vscode中添加 powershell 7 路径&…

企微审批中MySQL字段TEXT类型被截断的排查与修复实践

在MySQL中&#xff0c;TEXT类型字段常用于存储较大的文本数据&#xff0c;但在一些应用场景中&#xff0c;当文本内容较大时&#xff0c;TEXT类型字段可能无法满足需求&#xff0c;导致数据截断或插入失败。为了避免这种问题&#xff0c;了解不同文本类型&#xff08;如TEXT、M…

异常 PipeMapRed.waitOutputThreads(): subprocess failed with code 127

直接放问题异常 hadoop jar /opt/module/hadoop-3.3.2/share/hadoop/tools/lib/hadoop-streaming-3.3.2.jar \ -D mapreduce.map.memory.mb100 \ -D mapreduce.reduce.memory.mb100 \ -D mapred.map.tasks1 \ -D stream.num.map.output.key.fields2 \ -D num.key.fields.for.pa…

Focal Loss (聚焦损失) :解决类别不平衡与难易样本的利器,让模型学会“重点学习”

1. 为什么需要Focal Loss&#xff1f; 2. 交叉熵损失的问题 3.Focal Loss的智慧&#xff1a;给不同的错误“区别对待” 4.代码演示 1. 为什么需要Focal Loss&#xff1f; 在机器学习和深度学习中&#xff0c;类别不平衡&#xff08;Class Imbalance&#xff09; 是一个普遍…

算法系列之数据结构-二叉树

在计算机科学中&#xff0c;数据结构是组织和存储数据的方式&#xff0c;以便能够高效地访问和修改数据。树&#xff08;Tree&#xff09;是一种非常重要的非线性数据结构&#xff0c;广泛应用于各种算法和应用中。本文将详细介绍树的基本概念、常见类型以及用Java实现树的遍历…

进来了解一下python的深浅拷贝

深浅拷贝是什么&#xff1a;在Python中&#xff0c;理解深拷贝&#xff08;deep copy&#xff09;和浅拷贝&#xff08;shallow copy&#xff09;对于处理复杂的数据结构&#xff0c;如列表、字典或自定义对象&#xff0c;是非常重要的。这两种拷贝方式决定了数据在内存中的复制…

磁盘空间不足|如何安全清理以释放磁盘空间(开源+节流)

背景&#xff1a; 最近往数据库里存的东西有点多&#xff0c;磁盘不够用 查看磁盘使用情况 df -h /dev/sda5&#xff08;根目录 /&#xff09; 已使用 92% 咱们来开源节流 目录 背景&#xff1a; 一、开源 二、节流 1.查找 大于 500MB 的文件&#xff1a; 1. Snap 缓存…

vue3学习-2(深入组件)

vue3学习-2&#xff08;深入组件&#xff09; 1.开始2.基础3.深入组件注册全局注册局部注册组件名格式 PropsProps 声明响应式 Props 解构 3.5将解构的 props 传递到函数中单向数据流更改对象 / 数组类型的 propsProp 校验 事件触发与监听事件事件参数声明触发的事件事件校验 组…

Java 入门 (超级详细)

一、什么是Java Java是一种高级编程语言&#xff0c;由Sun Microsystems公司于1995年推出。Java具有跨平台性、面向对象、健壮性、安全性、可移植性等特点&#xff0c;被广泛应用于企业级应用开发、移动应用开发、大数据处理、云计算等领域。Java程序可以在不同的操作系统上运…

23种设计模式之工厂方法模式(Factory Method Pattern)【设计模式】

文章目录 一、工厂方法模式简介二、关键点三、代码示例3.1 定义抽象产品3.2 实现具体产品3.3 创建抽象工厂3.4 实现具体工厂3.5 客户端代码 四、解释五、优缺点5.1 优点5.2 缺点 六、适用场景 一、工厂方法模式简介 工厂方法模式&#xff08;Factory Method Pattern&#xff0…

io学习----->标准io

思维导图&#xff1a; 一.io的作用 io是实现对文件的操作&#xff0c;把运行结果存到文件中&#xff0c;读取文件的数据&#xff0c;方便后期查询。 二.io的概念 io是指系统 和外部设备或用户之间的数据交互 I:input 表示数据从外部设备输入到内存中&#xff1b; O:output…

从 R1 到 Sonnet 3.7,Reasoning Model 首轮竞赛中有哪些关键信号?

DeepSeek R1 催化了 reasoning model 的竞争&#xff1a;在过去的一个月里&#xff0c;头部 AI labs 已经发布了三个 SOTA reasoning models&#xff1a;OpenAI 的 o3-mini 和deep research&#xff0c; xAI 的 Grok 3 和 Anthropic 的 Claude 3.7 Sonnet。随着头部 Al labs 先…

FPGA开发,使用Deepseek V3还是R1(7):以“FPGA的整体设计框架”为例

以下都是Deepseek生成的答案 FPGA开发&#xff0c;使用Deepseek V3还是R1&#xff08;1&#xff09;&#xff1a;应用场景 FPGA开发&#xff0c;使用Deepseek V3还是R1&#xff08;2&#xff09;&#xff1a;V3和R1的区别 FPGA开发&#xff0c;使用Deepseek V3还是R1&#x…

正大杯攻略|非量表题数据分析基本步骤

在各类研究和调查场景中&#xff0c;非量表类问卷作为数据收集的重要工具&#xff0c;其分析方法涵盖多个关键环节&#xff0c;对于精准解读数据、提炼有价值的结论起着决定性作用。下面详细介绍非量表类问卷的分析方法。 一、样本背景分析 样本背景分析借助描述性统计方法&am…

SuperMap iClient3D for WebGL三维场景与二维地图联动

作者&#xff1a;Lzzzz 在城市规划&#xff0c;应急救援&#xff0c;旅游规划等项目场景中&#xff0c;普遍存在通过二维地图定位区域或路线&#xff0c;三维场景展示布局细节的情况&#xff0c;那么&#xff0c;如何使三维场景与二维地图联动起来呢&#xff0c;一起来看看如何…

3dsmax烘焙光照贴图然后在unity中使用

效果预览 看不清[完蛋&#xff01;] 实现步骤 使用 软件 软体名称地址photoshophttps://www.adobe.com/products/photoshop.htmlunity3Dhttps://unity.com/3dsmaxhttps://www.autodesk.com.cn/products/3ds-max/free-trialpacker-iohttps://www.uv-packer.com/HDR 贴图地址…