BuildFun và SolveFun
Chà, điều này mất khá nhiều thời gian và tôi không hoàn toàn chắc chắn liệu người giải có gian lận hay không. Mặc dù nó có quyền truy cập vào toàn bộ mê cung mọi lúc, nó chỉ nhìn vào tế bào trong đó, các bức tường bao quanh nó và, nếu không có một bức tường giữa chúng, các tế bào nằm cạnh nó. Nếu điều này trái với quy tắc, xin vui lòng cho tôi biết và tôi sẽ cố gắng thay đổi nó.
Dù sao, đây là mã:
#Architect function
def BuildFun(size,seed):
#Initialise grid and ensure inputs are valid
if size<15:size=15
if size>50:size=50
if seed<4:seed=4
if seed>size:seed=size
grid=[]
for x in range(size):
gridbuilder=[]
for y in range(size):gridbuilder.append([0,1,1])
grid.append(gridbuilder)
coords=[0,0]
grid[0][0][0]=1
#Generate maze
while 1:
#Choose a preffered direction based on location in grid and seed
pref=((((coords[0]+coords[1]+2)*int(size/2))%seed)+(seed%(abs(coords[0]-coords[1])+1)))%4
#Find legal moves
opt=[]
if coords[0]>0:opt+=[0] if grid[coords[0]-1][coords[1]][0]==0 else []
if coords[1]<size-1:opt+=[1] if grid[coords[0]][coords[1]+1][0]==0 else []
if coords[0]<size-1:opt+=[2] if grid[coords[0]+1][coords[1]][0]==0 else []
if coords[1]>0:opt+=[3] if grid[coords[0]][coords[1]-1][0]==0 else []
#There are legal moves
if len(opt)>0:
moved=False
while not moved:
#Try to move in preffered direction
if pref in opt:
if pref==0:
coords[0]-=1
grid[coords[0]][coords[1]][0]=1
grid[coords[0]][coords[1]][2]=0
elif pref==1:
grid[coords[0]][coords[1]][1]=0
coords[1]+=1
grid[coords[0]][coords[1]][0]=1
elif pref==2:
grid[coords[0]][coords[1]][2]=0
coords[0]+=1
grid[coords[0]][coords[1]][0]=1
else:
coords[1]-=1
grid[coords[0]][coords[1]][0]=1
grid[coords[0]][coords[1]][1]=0
moved=True
#Change preferred direction if unable to move
else:
pref+=1
if pref==4:pref=0
#There aren't legal moves
else:
moved=False
#Return to a previously visited location
if not moved:
try:
if grid[coords[0]-1][coords[1]][0]==1 and grid[coords[0]-1][coords[1]][2]==0:
grid[coords[0]][coords[1]][0]=2
coords[0]-=1
moved=True
except:pass
if not moved:
try:
if grid[coords[0]][coords[1]+1][0]==1 and grid[coords[0]][coords[1]][1]==0:
grid[coords[0]][coords[1]][0]=2
coords[1]+=1
moved=True
except:pass
if not moved:
try:
if grid[coords[0]+1][coords[1]][0]==1 and grid[coords[0]][coords[1]][2]==0:
grid[coords[0]][coords[1]][0]=2
coords[0]+=1
moved=True
except:pass
if not moved:
try:
if grid[coords[0]][coords[1]-1][0]==1 and grid[coords[0]][coords[1]-1][1]==0:
grid[coords[0]][coords[1]][0]=2
coords[1]-=1
moved=True
except:pass
#Check if finished
fin=True
for x in grid:
for y in x:
if y[0]==0:
fin=False
break
if not fin:break
if fin:break
for x in grid:
for y in x:
y[0]=0
#Find positions for start and finish such that the route between them is as long as possible
lsf=[[0,0],[0,0],0]
for y in range(size):
for x in range(size):
#Check all start positions
lengths=[]
coords=[[y,x,4,0]]
while len(coords)>0:
#Spread tracers out from start to the rest of the maze
for coord in coords:
opt=[]
if coord[0]>0:opt+=[0] if grid[coord[0]-1][coord[1]][2]==0 else []
opt+=[1] if grid[coord[0]][coord[1]][1]==0 else []
opt+=[2] if grid[coord[0]][coord[1]][2]==0 else []
if coord[1]>0:opt+=[3] if grid[coord[0]][coord[1]-1][1]==0 else []
try:opt.remove(coord[2])
except:pass
#Dead end, tracer dies and possible end point is recorded along with length
if len(opt)==0:
lengths.append([coord[0],coord[1],coord[3]])
coords.remove(coord)
else:
#Create more tracers at branch points
while len(opt)>1:
if opt[0]==0:coords.append([coord[0]-1,coord[1],2,coord[3]+1])
elif opt[0]==1:coords.append([coord[0],coord[1]+1,3,coord[3]+1])
elif opt[0]==2:coords.append([coord[0]+1,coord[1],0,coord[3]+1])
else:coords.append([coord[0],coord[1]-1,1,coord[3]+1])
del opt[0]
if opt[0]==0:
coord[0]-=1
coord[2]=2
coord[3]+=1
elif opt[0]==1:
coord[1]+=1
coord[2]=3
coord[3]+=1
elif opt[0]==2:
coord[0]+=1
coord[2]=0
coord[3]+=1
else:
coord[1]-=1
coord[2]=1
coord[3]+=1
#Find furthest distance and, if it's longer than the previous one, the start/end positions get updated
lengths=sorted(lengths,key=lambda x:x[2],reverse=True)
if lengths[0][2]>lsf[2]:lsf=[[y,x],[lengths[0][0],lengths[0][1]],lengths[0][2]]
#Find number of walls and output maze
w=draw(grid,size,lsf[0],lsf[1])
#Output maze information
print('Start = '+str(lsf[0]))
print('End = '+str(lsf[1]))
print('Distance = '+str(lsf[2]))
print('Walls = '+str(w))
print('Score = '+str(float(lsf[2])/float(w))[:5])
#Convert array grid to binary strings horizontal and vertical
horizontal=vertical=''
for y in range(size):
for x in range(size-1):vertical+=str(grid[y][x][1])
for y in range(size-1):
for x in range(size):horizontal+=str(grid[y][x][2])
#Save maze information to text file for use with SolveFun
save=open('Maze.txt','w')
save.write(str(size)+'\n'+str(lsf[0][0])+' '+str(lsf[0][1])+'\n'+str(lsf[1][0])+' '+str(lsf[1][1])+'\n'+horizontal+'\n'+vertical)
save.close()
#Solver function
def SolveFun():
try:
#Get maze information from text file
save=open('Maze.txt','r')
data=save.readlines()
save.close()
size=int(data[0])
s=data[1].rsplit(' ')
start=[int(s[0]),int(s[1])]
e=data[2].rsplit(' ')
end=[int(e[0]),int(e[1])]
horizontal=data[3].rstrip('\n')
vertical=data[4]
#Build maze from information
grid=[]
for y in range(size):
grid.append([])
for x in range(size):
grid[y].append([0,1,1])
for y in range(size):
for x in range(size-1):
grid[y][x][1]=int(vertical[y*(size-1)+x])
for y in range(size-1):
for x in range(size):
grid[y][x][2]=int(horizontal[y*size+x])
path=''
cpath=''
bs=0
pos=start[:]
grid[pos[0]][pos[1]][0]=1
while pos!=end:
#Want to move in direction of finish
if end[0]<pos[0] and pos[0]-end[0]>=abs(pos[1]-end[1]):pref=0
elif end[1]>pos[1] and end[1]-pos[1]>=abs(pos[0]-end[0]):pref=1
elif end[0]>pos[0] and end[0]-pos[0]>=abs(pos[1]-end[1]):pref=2
else:pref=3
#Find legal moves
opt=[]
if pos[0]>0:
if grid[pos[0]-1][pos[1]][2]==0:opt+=[0]if grid[pos[0]-1][pos[1]][0]==0 else[]
if pos[1]>0:
if grid[pos[0]][pos[1]-1][1]==0:opt+=[3]if grid[pos[0]][pos[1]-1][0]==0 else[]
if grid[pos[0]][pos[1]][2]==0:opt+=[2]if grid[pos[0]+1][pos[1]][0]==0 else[]
if grid[pos[0]][pos[1]][1]==0:opt+=[1]if grid[pos[0]][pos[1]+1][0]==0 else[]
if len(opt)>0:
moved=False
while not moved:
#Try to move in preferred direction
if pref in opt:
if pref==0:
pos[0]-=1
path+='0'
cpath+='0'
elif pref==1:
pos[1]+=1
path+='1'
cpath+='1'
elif pref==2:
pos[0]+=1
path+='2'
cpath+='2'
else:
pos[1]-=1
path+='3'
cpath+='3'
grid[pos[0]][pos[1]][0]=1
moved=True
#Change preferred direction by 1
else:
pref=(pref+1)%4
#No legal moves, backtrack
else:
bs+=1
grid[pos[0]][pos[1]][0]=2
if int(cpath[len(cpath)-1])==0:
pos[0]+=1
path+='2'
elif int(cpath[len(cpath)-1])==1:
pos[1]-=1
path+='3'
elif int(cpath[len(cpath)-1])==2:
pos[0]-=1
path+='0'
else:
pos[1]+=1
path+='1'
cpath=cpath[:len(cpath)-1]
#Output maze with solution as well as total steps and wasted steps
draw(grid,size,start,end)
print('\nPath taken:')
print(str(len(path))+' steps')
print(str(bs)+' backsteps')
print(str(bs*2)+' wasted steps')
except:print('Could not find maze')
def draw(grid,size,start,end):
#Build output in string d
d=' '
for x in range(size):d+=' '+str(x)[0]
d+='\n '
for x in range(size):d+=' ' if len(str(x))==1 else ' '+str(x)[1]
d+='\n '+'_'*(size*2-1)
w=0
for y in range(size):
d+='\n'+str(y)+' |' if len(str(y))==1 else '\n'+str(y)+' |'
for x in range(size):
if grid[y][x][2]:
if start==[y,x]:d+=UL.S+'S'+UL.E
elif end==[y,x]:d+=UL.S+'F'+UL.E
elif grid[y][x][0]==1:d+=UL.S+'*'+UL.E
else:d+='_'
w+=1
else:
if start==[y,x]:d+='S'
elif end==[y,x]:d+='F'
elif grid[y][x][0]==1:d+='*'
else:d+=' '
if grid[y][x][1]:
d+='|'
w+=1
else:d+=' '
#Output maze and return number of walls
print(d)
w-=size*2
return w
#Underlines text
class UL:
S = '\033[4m'
E = '\033[0m'
Tôi nhận ra rằng nó dài vô lý và không dễ đọc, nhưng tôi lười nên đây là cách nó tồn tại.
BuildFun
Kiến trúc sư, BuildFun, là một chương trình tạo mê cung khá đơn giản, sẽ luôn tạo ra một mê cung 'hoàn hảo' (một không có vòng lặp và trong đó hai điểm sẽ luôn có chính xác một đường giữa chúng). Nó dựa vào logic của nó từ đầu vào hạt giống, nghĩa là các mê cung được tạo ra là giả ngẫu nhiên với những gì thường xuất hiện là các mẫu lặp lại và, với cùng một hạt giống và kích thước, cùng một mê cung sẽ được tạo ra.
Khi mê cung được tạo, chương trình sẽ cố gắng tối đa hóa điểm số của mê cung bằng cách tìm kiếm điểm bắt đầu và điểm kết thúc dẫn đến con đường dài nhất giữa chúng. Để làm điều này, nó chạy qua mọi điểm bắt đầu, trải ra các bộ theo dõi để tìm điểm cuối xa nhất từ nó và chọn kết hợp với con đường dài nhất.
Sau đó, nó vẽ mê cung, đếm các bức tường và đưa ra thông tin của mê cung. Đây là điểm bắt đầu, điểm kết thúc, khoảng cách giữa chúng, số lượng tường và điểm số. Nó cũng định dạng thông tin này thành kiểu được mô tả ở trên về kích thước, bắt đầu và kết thúc, tường ngang và tường dọc và lưu thông tin này vào tệp văn bản có tên Maze.txt để sử dụng sau.
Giải quyết
Bộ giải, SolveFun, sử dụng tệp văn bản Maze.txt làm đầu vào và hoạt động theo cách rất giống với kiến trúc sư. Đối với mỗi di chuyển, nó sẽ chọn một hướng mà nó muốn đi dựa trên vị trí tương đối của nó đến cuối và sau đó nó sẽ nhìn vào các bức tường xung quanh nó. Nếu một bức tường không có ở đó, nó sẽ kiểm tra xem nó đã ở trong ô liền kề với nó chưa, và nếu không, nó sẽ được thêm vào tùy chọn có thể. Sau đó, nó sẽ di chuyển theo hướng gần nhất với hướng ưa thích với điều kiện nó có các tùy chọn. Nếu nó không có tùy chọn, nó sẽ quay lại cho đến khi có. Điều này tiếp tục cho đến khi nó kết thúc.
Khi nó di chuyển, nó ghi lại đường dẫn mà nó đang thực hiện trong đường dẫn biến được sử dụng ở cuối để xuất tổng số bước. Nó cũng ghi lại số lần phải quay lại được sử dụng để tính các bước lãng phí ở cuối. Khi đến điểm cuối, nó sẽ xuất ra mê cung với con đường ngắn nhất từ đầu đến cuối được đánh dấu bằng *
s.
Cách chạy
Do phương thức xuất ra mê cung (bao gồm gạch chân một số ký tự nhất định), điều này phải được chạy từ một dòng lệnh trong biểu mẫu
python -c 'import filename;filename.BuildFun(Size, Seed)'
và
python -c 'import filename;filename.SolveFun()'
trong đó Kích thước là một số nguyên từ 15 đến 50 (đã bao gồm) và Seed là một số nguyên giữa 4 và Kích thước (đã bao gồm).