Python:solve";“n对n”;迷宫
我试图用python编写一个脚本来解决一个有多个起点和多个终点的迷宫。从起点沿直线获得正确的路径 例如,有4条路径的迷宫: 起初我想使用左/右规则,但由于迷宫的特点,它没有多大意义。我试着做一个算法,沿着四个方向(上、下、左、右)的直线走 我现在所拥有的:Python:solve";“n对n”;迷宫,python,image-processing,path-finding,maze,Python,Image Processing,Path Finding,Maze,我试图用python编写一个脚本来解决一个有多个起点和多个终点的迷宫。从起点沿直线获得正确的路径 例如,有4条路径的迷宫: 起初我想使用左/右规则,但由于迷宫的特点,它没有多大意义。我试着做一个算法,沿着四个方向(上、下、左、右)的直线走 我现在所拥有的: from PIL import Image UP='up' DOWN='down' LEFT='left' RIGHT='right' directionOld=RIGHT def checkAdjacents(im,x,y):
from PIL import Image
UP='up'
DOWN='down'
LEFT='left'
RIGHT='right'
directionOld=RIGHT
def checkAdjacents(im,x,y):
matrix=[]
for Y in range(y-1,y+2):
r=[]
for X in range(x-1,x+2):
if im.getpixel((X,Y))==255:
r.append(True)
else:
r.append(False)
matrix.append(r)
return matrix
def testDirection(adj,direction):
if direction==UP and adj[0][1]:
return False
if direction==LEFT and adj[1][0]:
return False
if direction==RIGHT and adj[1][2]:
return False
if direction==DOWN and adj[2][1]:
return False
return True
def changeDirection(adj,direction):
if direction==UP or direction==DOWN:
if adj[1][2]:
direction=RIGHT
else:
direction=LEFT
else:
if adj[2][1]:
direction=DOWN
else:
direction=UP
return direction
def move(im,im2,x,y,directionOld,color):
im2.putpixel((x,y),color)
adj=checkAdjacents(im,x,y)
change=testDirection(adj,directionOld)
directionNew=directionOld
if change:
directionNew=changeDirection(adj,directionOld)
print "New direction ->",directionNew
if directionNew==UP:
y-=1
elif directionNew==DOWN:
y+=1
elif directionNew==RIGHT:
x+=1
else:
x-=1
return (x,y,directionNew)
image_file = Image.open("maze.png") # open colour image
im = image_file.convert('1') # convert image to black and white
im.save("2.png")
im2=im.copy() #duplicate to store results
im2=im2.convert("RGB") #results in color
paths=[(114,110,(255,0,255)),#Path1
(114,178,(255,0,0)),#Path2
(114,250,(0,255,0)),#Path3
(114,321,(0,0,255)),#Path4
]
for path in paths:
print "------------------------------------"
print "----------------Path"+str(paths.index(path))+"---------------"
print "------------------------------------"
x,y,color=path
for i in range(0,750):#number of steps
x,y,directionOld=move(im,im2,x,y,directionOld,color)
im2.save("maze_solved.png")
输入图像是一个黑白图像,如下所示:
这将产生:
我曾想过使用类似的东西,但增加了4个方向更对应于对角线方向
还有什么办法可以取得好的效果吗?这是我提出的解决方案。我不认为打破它太难,但它在测试集上是有效的。此外,我还使用pygame和PIL来观察算法运行时输出路径的渲染。(Tkinter不会为我工作,所以我只选择pygame。) 导入系统 输入数学 从PIL导入图像 #从pygame导入* 导入pygame,pygame.gfxdraw #浮动范围实用程序-抓取堆栈溢出 def xfrange(启动、停止、步骤): 启动<停止时: 产量起点 开始+=步进 #测试像素的有效性-如果坐标在图像边界内,则全白色有效 def测试位置(im、x、y): #确保X位置有效 如果(x<0)或(x>=im.size[0]): 返回错误 #确保Y位置有效 如果(y<0)或(y>=im.size[1]): 返回错误 如果im.getpixel((x,y))==(255,255,255): 返回True; 返回False; #获取路径中的下一个点-这是蛮力。它看起来是最长的 #从当前点向所有方向延伸一条线的可能路径 #(除了它来自的角度-因此它不会返回路线)然后 #沿着最长的直线。 def getNextPoint(im、x、y、角度): strengthMap=[] #横扫整圈 #注意:“1”的原始步骤没有提供足够的角度分辨率 #为了解决这个问题。把这个换成一,解出紫罗兰色 #路径,它将沿着蓝色路径结束。对于较薄或较长的路径, #这个分辨率可能必须更高。 #此外,-120:120不是一般情况下的范围-它是对 #解决这个迷宫。更普遍的解决方案是+/-175英寸-重点是 #防止“最佳解决方案”成为最后一个位置(即回溯)。 #当角度=角度+180时,应发生这种情况 对于XFI范围内的i(角度-120.0,角度+120.0,0.25): #为此选择更好的起始值将是一个伟大的优化 距离=2 #在这个角度找到最长的线 尽管如此: nextX=int(x+距离*math.cos(math.radians(i))) nextY=int(y+距离*math.sin(math.radians(i))) 如果测试位置(im、nextX、nextY): 距离=距离+1 其他: #此距离失败,因此上一个距离是有效距离 距离=距离-1 打破 #将角度和距离附加到strengthMap 强度贴图附加((i,距离)) #根据距离按降序对strengthMap进行排序 sortedMap=sorted(strengthMap,key=lambda条目:条目[1],reverse=True) #选择已排序地图中的第一个点 nextX=int(x+sortedMap[0][1]*math.cos(math.radians(sortedMap[0][0])) nextY=int(y+sortedMap[0][1]*math.sin(math.radians(sortedMap[0][0])) 返回int(nextX)、int(nextY)、sortedMap[0][0] ##初始化环境 路径='c:\\迷宫问题\\'; 迷宫输入=“迷宫1.png”; 路径=[(114110,(255,0255)),#路径1 (114178,(255,0,0)),#路径2 (114250,(0255,0)),路径3 (114321,(0,0255)),#路径4 ] 默认角度=0 pathToSolve=3 pygame.init() image_file=image.open(路径+迷宫_输入)#打开彩色图像 im=图像_文件.convert('L'); im=im.point(λx:0,如果x<1,则为255,'1')#图像不是干净的黑白图像,所以使用一个简单的阈值 im=im.convert('RGB'); #工作全局 posX=路径[pathToSolve][0] posY=路径[pathToSolve][1] 颜色=(255、255、255) 角度=默认角度 #创建屏幕 window=pygame.display.set_模式((640480)) #加载要渲染到屏幕的图像-这不是用于处理的图像 maze=pygame.image.load(路径+maze\u输入) imagerect=maze.get_rect() window.blit(迷宫,imagerect) #解决方案不起作用时的迭代计数器 计数=0 处理=真 处理时: #处理事件以查找退出 对于pygame.event.get()中的事件: 如果event.type==pygame.QUIT: 系统出口(0) #获取路径中的下一个点 nextPosX,nextPosY,angle=getNextPoint(im,posX,posY,angle) pygame.gfxdraw.line(窗口、posX、posY、nextPosX、nextPosY、颜色) posX=nextPosX posY=nextPosY #把它画到屏幕上 pygame.display.flip() 计数=计数+1 如果计数>20或posX>550: 处理=假 以下是一个示例解决方案:
这似乎是一个有趣的问题。我认为关键的洞察力是“直线”意味着通过交叉点,而不一定是在基本方向。我正在使用一个实现,它从点X开始,沿着一条直线移动,直到路径沿该直线无效,此时它选择了一条新线。另一个有趣的方法是使用测线器并建立一个测线网络。谢谢!我找到了一个在初始代码上增加更多自由度的解决方案。然而,我必须承认,从一个点找到最长的线是一个更好的解决方案。我将尝试通过修改来调整我当前的解决方案。顺便说一下,我认为有一个缩进误差
import sys
import math
from PIL import Image
#from pygame import *
import pygame, pygame.gfxdraw
# Float range utility - grabbed off Stackoverflow
def xfrange(start, stop, step):
while start < stop:
yield start
start += step
# Test a pixel for validity - fully white is valid if coordinate is within the image bounds
def testLocation(im, x, y) :
# Make sure the X position is valid
if (x < 0) or (x >= im.size[0]):
return False
# Make sure the Y position is valid
if (y < 0) or (y >= im.size[1]):
return False
if im.getpixel((x, y)) == (255, 255, 255) :
return True;
return False;
# Get the next point in the path - this is brute force. It looks for the longest
# path possible by extending a line from the current point in all directions
# (except the angle it came from - so it doesn't retrace its route) and then
# follows the longest straight line.
def getNextPoint(im, x, y, angle) :
strengthMap = []
# Sweep across the whole circle
# Note: the original step of '1' did not provide enough angular resolution
# for solving this problem. Change this back to one and solve for the violet
# path and it will end up following the blue path. For thinner or longer paths,
# this resolution might have to be even finer.
# Also, -120:120 is not a general case range - it is a slight optimization to
# solve this maze. A more general solution would be +/- 175'ish - the point is
# to prevent the "best solution" to be the last position (i.e. back tracking).
# This should happen when the angle = angle + 180
for i in xfrange(angle - 120.0, angle + 120.0, 0.25) :
# Choosing a better starting value for this would be a great optimization
distance = 2
# Find the longest possible line at this angle
while True :
nextX = int(x + distance * math.cos(math.radians(i)))
nextY = int(y + distance * math.sin(math.radians(i)))
if testLocation(im, nextX, nextY) :
distance = distance + 1
else :
# This distance failed so the previous distance was the valid one
distance = distance - 1
break
# append the angle and distance to the strengthMap
strengthMap.append((i, distance))
# Sort the strengthMap based on the distances in descending order
sortedMap = sorted(strengthMap, key=lambda entry: entry[1], reverse=True)
# Choose the first point in the sorted map
nextX = int(x + sortedMap[0][1] * math.cos(math.radians(sortedMap[0][0])))
nextY = int(y + sortedMap[0][1] * math.sin(math.radians(sortedMap[0][0])))
return int(nextX), int(nextY), sortedMap[0][0]
## Init Environment
path = 'c:\\maze problem\\';
maze_input = "maze_1.png";
paths=[(114,110,(255,0,255)),#Path1
(114,178,(255,0,0)),#Path2
(114,250,(0,255,0)),#Path3
(114,321,(0,0,255)),#Path4
]
defaultAngle = 0
pathToSolve = 3
pygame.init()
image_file = Image.open(path + maze_input) # open color image
im = image_file.convert('L');
im = im.point(lambda x : 0 if x < 1 else 255, '1') # the image wasn't cleanly black and white, so do a simple threshold
im = im.convert('RGB');
# Working Globals
posX = paths[pathToSolve][0]
posY = paths[pathToSolve][1]
color = (255, 255, 255)
angle = defaultAngle
#create the screen
window = pygame.display.set_mode((640, 480))
# Load the image for rendering to the screen - this is NOT the one used for processing
maze = pygame.image.load(path + maze_input)
imagerect = maze.get_rect()
window.blit(maze, imagerect)
# Iteration counter in case the solution doesn't work
count = 0
processing = True
while processing:
# Process events to look for exit
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit(0)
# Get the next point in the path
nextPosX, nextPosY, angle = getNextPoint(im, posX, posY, angle)
pygame.gfxdraw.line(window, posX, posY, nextPosX, nextPosY, color)
posX = nextPosX
posY = nextPosY
#draw it to the screen
pygame.display.flip()
count = count + 1
if count > 20 or posX > 550:
processing = False