zoukankan      html  css  js  c++  java
  • python:迷宫生成,搜索(广度优先),图形界面演示搜索过程

    和之前八皇后问题用一样的框架:

    所谓迷宫,结构上就是一棵树,没有环路,生成的方法,就是随机在图形中找一点,然后它有四个方向可以发展,这四个点加入step1_nodes,然后再把step1_nodes设回step0_nodes,再次产生候选节点,这样的话,发展节点就呈现以开始节点为中心以菱形向四周扩展的形态。那么就不是迷宫了,实际从起始点有四个候选点,他随机发展一个,以后的发展都是从step0_nodes中选取一个,发展出来的节点加入step0_nodes,当一个节点四周都是已经发展的节点了,那么这个节点就从step0_nodes删除,最后图形中找不到一个可以发展的点,所有step0_nodes的节点也被删除了,结构上就是一棵树,也就是迷宫,设定一个起点,一个终点。

    查找就简单了,就是从出发点发展,这次不是造迷宫,可以用菱形扩散法,也就是广度优先。

    图形演示,和八皇后一样框架,这个程序的话,其中下面两句尤为重要,因为真的是画了很多线,虽然都很短,画完后,保存到图像,以后直接作为背景使用:

                select_rect = CMG.screen.subsurface(0,0,800,570)
                CMG.back_ground = select_rect.copy()
    import pygame
    import sys
    import os
    import random
    import time
    from pygame.locals import *
    import tkinter as tk
    from tkinter import *
    import tkinter.messagebox  # 要使用messagebox先要导入模块
    
    class Maze:
        size = None
        print_str=(('##','  '),('#',' '))
        map = None
        direct = ((-2,0),(2,0),(0,2),(0,-2),(-2,0),(2,0),(0,2))
    
        @staticmethod
        def check_move(map,yx):
            for d in range(0,4):
                if(map[yx[0]+Maze.direct[d][0]][yx[1]+Maze.direct[d][1]] == 0):
                    return True
            return False
        @staticmethod
        def create_maze(size_para):
            WAY = 1
            size=[size_para[0]*2+3,size_para[1]*2+3]
            Maze.size = size
            direct = Maze.direct
            center=[random.randint(1,size[0]-1)//2*2,random.randint(1,size[1]-1)//2*2]
            map= [[100]*size[1] for i in range(size[0])]
            for y in range(size_para[0]):
                for x in range(size_para[1]):
                    map[2*y+2][2*x+2] = 0
            step0_nodes = [center]
            map[center[0]][center[1]] = WAY
            step1_nodes = []
    
            while len(step0_nodes) > 0:
                node_no = random.randint(0,len(step0_nodes)-1)
                yx= step0_nodes[node_no]
                if not Maze.check_move(map,yx):
                    step0_nodes.pop(node_no)
                    continue
                direct_start = random.randint(0,3)
                for d in range(direct_start,direct_start+4):
                    y=yx[0]+direct[d][0]
                    x=yx[1]+direct[d][1]
                    if(map[y][x] == 0):
                        step1_nodes.append((y,x))
                        map[yx[0]+direct[d][0]//2][yx[1]+direct[d][1]//2] = WAY
                        map[y][x] = WAY
                        break
                step0_nodes.extend(step1_nodes)
                step1_nodes.clear()
            Maze.map = map
    
        @staticmethod
        def solve_maze(startY,endYX):
            WAY = 1
            direct = Maze.direct
            center=(startY*2+2,2,-1)
            map = Maze.map
            steps_nodes = []
            step0_nodes = [center]
            map[center[0]][center[1]] = 0
            step1_nodes = []
    
            while len(step0_nodes) > 0:
                steps_nodes.append(step0_nodes)
                for n in range(0,len(step0_nodes)):
                    yx= step0_nodes[n]
                    for d in range(0,4):
                        y=yx[0]+direct[d][0]
                        x=yx[1]+direct[d][1]
                        y3=yx[0]+direct[d][0]//2
                        x3=yx[1]+direct[d][1]//2
                        if(map[y3][x3] != 100 and map[y][x] == WAY ):
                            step1_nodes.append((y,x,n))
                            map[yx[0]+direct[d][0]][yx[1]+direct[d][1]] = 0
                            if y == endYX[0]*2 and x== endYX[1]*2:
                                steps_nodes.append(step1_nodes)
                                return steps_nodes
                step0_nodes = step1_nodes[:]
                step1_nodes.clear()
            return None
    
    class CMG: #画面显示管理
        screen = None
        map = None
        gameAnswer = None
        WHITE = (255, 255, 255)
        GREEN = (0, 255, 0)
        RED = (255, 0, 0)
        BLUE = (0, 0, 255)
        blocksize = 0
        step = 0
        back_ground = None
    
        def __init__(self,screen,map,gameAnswer):
            if CMG.screen == None:
                #print("#############OS.PATH=%s"% os.path.dirname(os.path.abspath(__file__)))
                CMG.screen = screen
                CMG.map = map
                CMG.gameAnswer = gameAnswer
                if 800//len(map[0]) > 570//len(map):
                    CMG.blocksize = 570//len(map)
                else:
                    CMG.blocksize = 800//len(map[0])
            #如果存在对象成员
            self.init_game_info()
    
        def init_game_info(self):
            pass
    
        def printAll(self):
            if CMG.step > len(CMG.gameAnswer):
                return
            CMG.screen.fill((0, 0, 0))
            size = Maze.size
            if CMG.back_ground == None:
                for y in range(1,size[0]-1):
                    for x in range(1,size[1]-1):
                        val = CMG.map[y][x]
                        if y%2==1 and x%2==0 and val == 100:
                            #start_pos = [(y*CMG.blocksize,x*CMG.blocksize)]
                            end_pos = [((x-1)*CMG.blocksize,y*CMG.blocksize),((x+1)*CMG.blocksize,y*CMG.blocksize)]
                            pygame.draw.lines(CMG.screen, CMG.GREEN,0 , end_pos, 2)
                        elif y%2==0 and x%2==1 and val == 100:
                            end_pos = [(x*CMG.blocksize,(y-1)*CMG.blocksize),(x*CMG.blocksize,(y+1)*CMG.blocksize)]
                            pygame.draw.lines(CMG.screen, CMG.GREEN,0 , end_pos, 2)
                select_rect = CMG.screen.subsurface(0,0,800,570)
                CMG.back_ground = select_rect.copy()
            else:
                self.screen.blit(CMG.back_ground,(0,0))
            if CMG.step == len(CMG.gameAnswer):
                step = CMG.step - 1
                step_node = CMG.gameAnswer[step]
                yx = step_node[len(step_node)-1]
                while(yx[2]!=-1):
                    y = yx[0]
                    x = yx[1]
                    step -= 1
                    step_node = CMG.gameAnswer[step]
                    yx = step_node[yx[2]]
                    pygame.draw.rect(CMG.screen, CMG.WHITE, (((x-1)*CMG.blocksize+2,(y-1)*CMG.blocksize+2), (CMG.blocksize*2-4, CMG.blocksize*2-4)), 0)
            else:
                step_node = CMG.gameAnswer[CMG.step]
                for s in range(0,len(step_node)):
                    yx = step_node[s]
                    y = yx[0]
                    x = yx[1]
                    #pygame.draw.rect(background, (0, 255, 0), ((200, 5), (100, 100)), 3)
                    pygame.draw.rect(CMG.screen, CMG.WHITE, (((x-1)*CMG.blocksize+2,(y-1)*CMG.blocksize+2), (CMG.blocksize*2-4, CMG.blocksize*2-4)), 0)
    
            CMG.step += 1
    
        def moveAll(self):
            pass
    
    #------------------------------------------------
    #tkinter,pygame混合区 START
    #------------------------------------------------
    root = tk.Tk()
    root.resizable(0,0)
    
    embed = tk.Frame(root, width = 800, height = 570) #creates embed frame for pygame window
    embed.grid(columnspan = (800), rowspan = 730) # Adds grid
    embed.pack(side = TOP) #packs window to the left
    
    buttonwin = tk.Frame(root, width = 800, height = 150)
    buttonwin.pack(side = BOTTOM)
    
    os.environ['SDL_WINDOWID'] = str(embed.winfo_id())
    os.environ['SDL_VIDEODRIVER'] = 'windib'
    
    screen = pygame.display.set_mode((800,570))
    
    #pygame.init()
    pygame.display.init()
    pygame.mixer.init()
    #------------------------------------------------
    #tkinter,pygame混合区 END
    #------------------------------------------------
    
    #参数,因为函数内要使用之外的变量,需要globe,因此全部打包
    class PARAM:
        STATUS = 0
        TICK_NORMAL = 5
    
    #按钮动作区 =====================================
    def exit_game():
        global param
        param.STATUS = 100
    #控件定义区 =====================================
    button_exit_b = Button(buttonwin,text = '退出画面', width=7, command=exit_game)
    button_exit_b.place(x=740,y=100)
    
    
    #状态,参数,循环中使用,比如STATUS=0:初次进入,1:...100:退出
    param = PARAM()
    Maze.create_maze([30,50])
    steps_nodes = Maze.solve_maze(0,(25,49))
    param.cmg = CMG(screen,Maze.map,steps_nodes)
    #------------------------------------------------
    #主函数,使用pygame框架,无限LOOP对各种事件然后相应处理
    #------------------------------------------------
    def main():
        global param
        #pygame.mixer.music.play(-1)
        clock = pygame.time.Clock()
    
        while True:
            #这段event代码是必须的,哪怕在这个程序中不需要,不执行的话整个框架转不动
            for event in pygame.event.get():
                if event.type == QUIT:
                    sys.exit()
    
            #画面按钮按下后,修改param.STATUS,实际动作这里实现
            if  param.STATUS == 100:
                #退出按钮
                if tk.messagebox.askokcancel('提示', '要退出画面吗'):
                    break
                param.STATUS = 0
            elif param.STATUS == 10:
                pass
                
            param.cmg.printAll()
    
            #显示游戏画面
            pygame.display.flip()
            #设置帧率:长期画面不操作,设置成最闲
            clock.tick(param.TICK_NORMAL)
                
            root.update()
    
    main()
  • 相关阅读:
    MySQL 约束
    MySQL 基础
    LeetCode-Backtracking-Easy 回溯算法
    cookie session区别
    mac环境下支持PHP调试工具xdebug,phpstorm监听
    dede修改移动文档的js
    ajax是怎么发请求的和浏览器发的请求一样吗?cookie
    linux命令
    mysql里的sql函数
    nginx启动
  • 原文地址:https://www.cnblogs.com/nocomment/p/13046597.html
Copyright © 2011-2022 走看看