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

news2025/3/3 13:48:42

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()

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

恶意 SSP 注入收集密码

SSP 安全服务提供者&#xff0c;是微软提供的与安全有关的函数接口&#xff0c;用户可根据自己的需求调用 SSP 接口实现高度自定义的身份验证等安全功能。攻击者注入恶意的 SSP 接口覆盖微软默认的某些安全功能&#xff0c;导致用户一旦进行身份验证&#xff0c;恶意的 SSP 将保…

Python----数据分析(Numpy:安装,数组创建,切片和索引,数组的属性,数据类型,数组形状,数组的运算,基本函数)

一、 Numpy库简介 1.1、概念 NumPy(Numerical Python)是一个开源的Python科学计算库&#xff0c;旨在为Python提供 高性能的多维数组对象和一系列工具。NumPy数组是Python数据分析的基础&#xff0c;许多 其他的数据处理库&#xff08;如Pandas、SciPy&#xff09;都依赖于Num…

Pytest之fixture的常见用法

文章目录 1.前言2.使用fixture执行前置操作3.使用conftest共享fixture4.使用yield执行后置操作 1.前言 在pytest中&#xff0c;fixture是一个非常强大和灵活的功能&#xff0c;用于为测试函数提供固定的测试数据、测试环境或执行一些前置和后置操作等&#xff0c; 与setup和te…

如何把网络ip改为动态:全面指南

在数字化时代&#xff0c;网络IP地址作为设备在网络中的唯一标识&#xff0c;扮演着至关重要的角色。随着网络环境的不断变化&#xff0c;静态IP地址的局限性逐渐显现&#xff0c;而动态IP地址则因其灵活性和安全性受到越来越多用户的青睐。那么&#xff0c;如何把网络IP改为动…

anythingLLM和deepseek4j和milvus组合建立RAG知识库

1、deepseek本地化部署使用 ollama 下载模型 Tags bge-m3 bge-m3:latest deepseek-r1:32b deepseek-r1:8b 2、安装好向量数据库 milvus docker安装milvus单机版-CSDN博客 3、安装 anythingLLM AnythingLLM | The all-in-one AI application for everyone …

和鲸科技推出人工智能通识课程解决方案,助力AI人才培养

2025年2月&#xff0c;教育部副部长吴岩应港澳特区政府邀请&#xff0c;率团赴港澳宣讲《教育强国建设规划纲要 (2024—2035 年)》。在港澳期间&#xff0c;吴岩阐释了教育强国目标的任务&#xff0c;并与特区政府官员交流推进人工智能人才培养的办法。这一系列行动体现出人工智…

当我删除word文件时无法删除,提示:操作无法完成,因为已在Microsoft Word中打开

现象&#xff1a; 查看电脑桌面下方的任务栏&#xff0c;明明已经关闭了WPS和WORD软件&#xff0c;但是打开word文档时还是提示&#xff1a; 解决方法步骤&#xff1a; 1、按一下键盘上的ctrl Shift Esc 键打开任务管理器 2、在进程中找到如下&#xff1a; 快速找到的方法…

高频面试题(含笔试高频算法整理)基本总结回顾3

目录 一、基本面试流程回顾 二、基本高频算法题展示 三、基本面试题总结回顾 &#xff08;一&#xff09;Java高频面试题整理 &#xff08;二&#xff09;JVM相关面试问题整理 &#xff08;三&#xff09;MySQL相关面试问题整理 &#xff08;四&#xff09;Redis相关面试…

Python中字符串的常用操作

一、r原样输出 在 Python 中&#xff0c;字符串前加 r&#xff08;即 r"string" 或 rstring&#xff09;表示创建一个原始字符串&#xff08;raw string&#xff09;。下面详细介绍原始字符串的特点、使用场景及与普通字符串的对比。 特点 忽略转义字符&#xff1…

卷积神经网络(cnn,类似lenet-1,八)

我们第一层用卷积核&#xff0c;前面已经成功&#xff0c;现在我们用两层卷积核&#xff1a; 结构如下&#xff0c;是不是很想lenet-1&#xff0c;其实我们24年就实现了sigmoid版本的&#xff1a; cnn突破九&#xff08;我们的五层卷积核bpnet网络就是lenet-1&#xff09;-CS…

Win32 C++ 电源计划操作

CPowerCfgUtils.h #pragma once#include <Windows.h> #include <powrprof.h>// https://learn.microsoft.com/zh-cn/windows/win32/api/powrprof/?sourcerecommendations//节能 //DEFINE_GUID(GUID_MAX_POWER_SAVINGS, 0xA1841308, 0x3541, 0x4FAB, 0xBC, 0x81, …

PH热榜 | 2025-03-01

1. Helix 标语&#xff1a;从想法到原型只需3分钟 介绍&#xff1a;Helix可以在几分钟内将你的创业想法变成一个准备好接受投资的原型。你可以创建功能齐全、可点击的用户界面和用户体验设计&#xff0c;完全不需要任何设计技能。 产品网站&#xff1a; 立即访问 Product H…

Tomcat基础知识及其配置

1.Tomcat简介 Tomcat是Apache软件基金会&#xff08;Apache Software Foundation&#xff09;的Jakarta 项目中的一个核心项目&#xff0c;由Apache、Sun和其他一些公司及个人共同开发而成。 Tomcat服务器是一个免费的开放源代码的Web应用服务器&#xff0c;属于轻量级应用服…

【LeetCode】739.每日温度

目录 题目描述输入输出示例及数据范围思路&#xff1a;单调栈C 实现 题目描述 给定一个整数数组 temperatures &#xff0c;表示每天的温度&#xff0c;返回一个数组 answer &#xff0c;其中 answer[i] 是指对于第 i 天&#xff0c;下一个更高温度出现在几天后。如果气温在这…

测试金蝶云的OpenAPI

如何使用Postman测试K3Cloud的OpenAPI 1. 引言 在本篇博客中&#xff0c;我将带你逐步了解如何使用Postman测试和使用K3Cloud的OpenAPI。内容包括下载所需的SDK文件、配置文件、API调用及测试等步骤。让我们开始吧&#xff01; 2. 下载所需的SDK文件 2.1 获取SDK 首先&…

SID History 域维权

SID History 域林攻击&#xff1a;域林攻击详解-CSDN博客 SID History 根据微软的描述&#xff0c;SID History 属性是微软对域内用户进行域迁移的支持而创建的。每当对象从一个域移动到另一个域时&#xff0c;都会创建一个新的 SID&#xff0c;并且该新 SID 将成为 objectSI…

1-kafka单机环境搭建

本文介绍kafka单机环境的搭建及可视化环境配置&#xff0c;虽然没有java代码&#xff0c;但是麻雀虽小五脏俱全&#xff0c;让大家在整体感官上对kafka有个认识。在文章的最后&#xff0c;我介绍了几个重要的配置参数&#xff0c;供大家参考。 0、环境 kafka&#xff1a;2.8.…

Qt常用控件之旋钮QDial

旋钮QDial QDial 表示一个旋钮控件。 1. QDial属性 属性说明value当前数值。minimum最小值。maximum最大值。singleStep按下方向键时改变的步长。pageStep按下 pageUp/pageDown 的时候改变的步长。sliderPosition界面上旋钮显示的初始位置。tracking外观是否会跟踪数值变化&…

基于DeepSeek,构建个人本地RAG知识库

经过一段使用DeepSeek后&#xff0c;感觉使用体验和ChatGPT基本差不多&#xff0c;回答问题的质量略有提升&#xff0c;因DeepSeek已开源&#xff0c;它的模型、模型参数权重从网上都可以下载到&#xff0c;所以可以基于开源的模型&#xff0c;在本地构建一个自己的知识库&…

散户如何实现自动化交易下单——篇1:体系介绍与获取同花顺资金账户和持仓信息

一、为什么要实现自动化交易 在瞬息万变的金融市场中&#xff0c;越来越多的散户投资者开始尝试构建自己的交易策略&#xff1a;有人通过技术指标捕捉趋势突破&#xff0c;有人利用基本面分析挖掘低估标的&#xff0c;还有人设计出复杂的网格交易或均值回归模型。然而&a…