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()
  • 相关阅读:
    LeetCode 32. 最长有效括号(Longest Valid Parentheses)
    LeetCode 141. 环形链表(Linked List Cycle)
    LeetCode 160. 相交链表(Intersection of Two Linked Lists)
    LeetCode 112. 路径总和(Path Sum)
    LeetCode 124. 二叉树中的最大路径和(Binary Tree Maximum Path Sum)
    LightGBM新特性总结
    sql service 事务与锁
    C#泛型实例详解
    C# 中的委托和事件(详解)
    C# DateTime日期格式化
  • 原文地址:https://www.cnblogs.com/nocomment/p/13046597.html
Copyright © 2011-2022 走看看