|

楼主 |
发表于 2020-6-5 20:17:15
|
显示全部楼层
所谓迷宫,结构上就是一棵树,没有环路,生成的方法,就是随机在图形中找一点,然后它有四个方向可以发展,这四个点加入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([50,70])
- steps_nodes = Maze.solve_maze(0,(49,69))
- 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()
复制代码 |
|