和之前八皇后问题用一样的框架:
所谓迷宫,结构上就是一棵树,没有环路,生成的方法,就是随机在图形中找一点,然后它有四个方向可以发展,这四个点加入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()