Labirent Tasarlama ve Çözme [korumalı alanda beklemede]


14

Göreviniz bu sahnede her iki karakterin rolünü Inception'dan oynamaktır . İçinde Cobb, Ariadne'ye bir meydan okuma verir:

Çözmeniz gereken bir labirent tasarlamak için iki dakikanız var.

Bu açıklamada bazı özgürlükler ele alınacaktır. En önemlisi, bu meydan okuma zamana dayalı değildir, daha çok puanlar labirentlerinizin ve labirentlerinizin etkinliğine dayanır.

Kolay ve adil bir formatta yinelediğimiz için bu meydan okumadaki birçok düzenleme için özür dilerim

Bölüm I: Labirent biçimi

Tüm labirentler kare şeklindedir. Labirentteki bir hücre, sıfır indeksli bir demet olarak temsil edilir row column.

Duvarlar iki ikili dizeyle temsil edilir: biri yatay duvarlar (sıralar arasındaki hareketi engelleyen) ve dikey duvarlar için (tam tersi). Bir NxNlabirentte, Nx(N-1)her türden olası duvarlar vardır . Hücrelerin etiketlendiği 3x3 örneğini ele alalım:

A   B | C
   ---
D | E   F
   ---
G   H | I

tüm olası düşey duvarları şunlardır: AB BC DE EF GH HI. Bir ipe çevrilmiş olarak gösterilen 011001duvarlar dikey duvarlar ve 010010yatay duvarlar içindir. Ayrıca, "ikili karakter dizisi" ile "0" ve "1" karakterlerini kastediyorum.

Tam labirent biçimi şu sırayı içeren bir dizedir:

  • Genişlik
  • hücre demetini başlat
  • son hücre grubu
  • yatay duvarlar
  • dikey duvarlar

Örneğin, bu labirent:

   0 1 2 3 4
   _________
0 | |  E|  _|
1 |  _|_|_  |
2 |_ _ _  | |
3 |  _ _  | |
4 |____S|___|
start:(4,2)
end:(0,2)

şu şekilde biçimlendirilir:

5
4 2
0 2
00001011101110001100
10100110000100010010

Bölüm II: Mimar

Mimar programı labirent oluşturur. Kurallara göre oynamalı ve geçerli bir labirent sağlamalıdır (bir çözümün var olduğu ve sonun başlangıcın üstünde olmadığı).

Girdi: İki pozitif tamsayı:

size [random seed]

Nerede sizeolacak [15, 50]. Rastgele tohumdan yararlanmanız önerilir, böylece eşleşmeler zorunlu olmasa da tekrarlanabilir.

Çıktı: Bölüm I'de açıklanan biçimi kullanan geçerli bir boyut x boyut (kare) labirent "geçerli", bir çözümün var olduğu ve başlangıç ​​hücresinin bitiş hücresine eşit olmadığı anlamına gelir.

Belirli bir labirentte bir Mimarın puanı

   # steps taken to solve
–––––––––––––––––––––––––––––
max(dist(start,end),(# walls))

Bu nedenle mimarlar karmaşık labirentler için ödüllendirilir, ancak inşa edilen her duvar için cezalandırılır (bu, Ariadne'nin zaman kısıtlamasının yerini alır). dist()Hiçbir duvarlı bir labirent sonsuz puanı almaz işlev olmasını sağlar. Labirentin dış sınırları duvar sayısına katkıda bulunmaz.

Bölüm III: Çözücü

Çözücü, başkalarının mimarları tarafından üretilen labirenteri çözmeye çalışır. Bir çeşit savaş sisi var: sadece ziyaret edilen hücrelere bitişik duvarlar dahil edildi (diğerlerinin tümü '?' İle değiştirildi)

girdi: aynı labirent biçiminde, ancak '?' duvarların bilinmediği, geçerli konum için fazladan bir satır ve bu konumdan virgülle ayrılmış geçerli seçimler listesi. (Bu, bir labirent ayrıştırma işlevi yazmayı kolaylaştırmak için yapılmış büyük bir düzenlemedir)

örnek (bir adım sola gittikten sonra yukarıdaki 5x5 labirentiyle aynı)

5
4 2
0 2
???????????????011??
????????????????001?
4 1
4 0,4 2

Hangisi buna benzer ?, sis nerede :

   0 1 2 3 4
   _________
0 |????E????|
1 |?????????|
2 |?????????|
3 | ?_?_????|
4 |__C_S|_?_|

çıktı: Geçerli seçenekler listesindeki tupleslardan biri

Her Çözücünün puanı Mimar'ın puanının tersidir.

Bölüm IV: Tepenin Kralı

Mimarlara ve Çözücülere ayrı puanlar verilir, bu yüzden potansiyel olarak iki kazanan olabilir.

Her bir mimar ve çözücü çifti birbirinden üstün olma şansına sahip olacak. Tüm testler ve rakipler üzerinden skorların ortalaması alınacaktır. Golf kurallarını kodlamanın aksine, en yüksek ortalama puan kazanır!

Bunun devam etmesini planlıyorum, ama sonsuza kadar süren testlerin garantisini veremiyorum! Şimdilik bir kazananın bir hafta içinde ilan edileceğini varsayalım.

Bölüm V: Gönderme

  • Tüm başvurularda veto gücünü koruyorum - akıllılık teşvik edilir, ancak rekabeti veya bilgisayarımı bozarsa değil! (Kodunuzun ne yaptığını söyleyemezsem, muhtemelen veto edeceğim)
  • Mimar / Çözücü çiftiniz için bir ad verin. Kodunuzu, nasıl çalıştırılacağına ilişkin talimatlarla birlikte gönderin.

Yakında: yeni format için güncellenmiş bir python test kiti. Dil gönderimlerine izin vermek için büyük değişiklikler oldu.


10
Python ile sınırlamak yerine, yarışmacılar tarafından yaratılacak / okunacak bir labirent formatı tanımlayamadınız mı? Bu muhtemelen daha fazla insanın ilgisini çekecektir.
Geobits

Kısıtlayıcı olmak için iki nedenim vardı: Birincisi koşu karşılaşmalarını kolay ve güvenli bir şekilde otomatikleştirmek. İkincisi, her dil için bir okuma ve yazma kütüphanesine ihtiyaç duymamaktır. Kimse python kullanmak istemiyorsa, bir veya her ikisini de
bırakmak zorunda kalacağım

1
Şu anda bir alt programı çalıştıran ve stdin / stdout üzerinden iletişim kuran bir sarmalayıcı yazıyorum. Bu şekilde istediğiniz dili kullanabilirsiniz. Buna izin verir misiniz?
IchBinKeinBaum

Kesinlikle! Tüm soru biçimini yeniden yazmanın ortasındaydım. Bekleyeyim mi?
wrongu

1
Bunun bir şey olduğunu bilmiyordum. Sanırım şimdilik beklemeye alacağım ..
wrongu

Yanıtlar:


1

BuildFun ve SolveFun

Bu biraz zaman aldı ve çözücünün hile yapıp yapmadığından emin değilim. Her zaman tüm labirente erişebilse de, sadece içinde bulunduğu hücreye, onu çevreleyen duvarlara ve aralarında bir duvar yoksa, komşu hücrelere bakar. Bu kurallara aykırı ise lütfen bana bildirin, değiştirmeye çalışacağım.

Her neyse, işte kod:

#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'

Bunun gülünç derecede uzun olduğunu ve özellikle okunması kolay olmadığını anlıyorum, ama tembelim, bu yüzden böyle kalıyor.

BuildFun

Mimar, BuildFun, her zaman 'mükemmel' bir labirent yaratacak oldukça basit bir labirent üreten programdır (biri döngüsüz ve iki noktanın aralarında tam olarak bir yol olacağı). Mantıkını tohum girişinden alır, yani üretilen labirentler genellikle yinelenen desenler gibi görünen ve aynı tohum ve büyüklükte aynı labirent oluşturulacak sözde rastgele olur.

Labirent oluşturulduktan sonra program, aralarındaki en uzun yolla sonuçlanan başlangıç ​​noktasını ve bitiş noktasını arayarak labirentin puanını en üst düzeye çıkarmaya çalışır. Bunu yapmak için, her başlangıç ​​noktasından geçer, en uzak uç noktasını bulmak için izleyicileri yayar ve en uzun yolla kombinasyonu seçer.

Bundan sonra, labirent çizer, duvarları sayar ve labirent bilgilerini verir. Bu başlangıç ​​noktası, bitiş noktası, aralarındaki mesafe, duvar sayısı ve skor. Ayrıca bu bilgileri boyut, başlangıç ​​ve bitiş, yatay duvarlar ve dikey duvarlar için yukarıda açıklanan stile biçimlendirir ve daha sonra kullanmak için Maze.txt adlı bir metin dosyasına kaydeder.

SolveFun

Çözücü SolveFun, giriş olarak Maze.txt metin dosyasını kullanır ve mimarla çok benzer bir şekilde çalışır. Her hareket için, sonuna kadar göreceli konumuna dayanarak gitmek istediği bir yönü seçecek ve daha sonra etrafını çevreleyen duvarlara bakacaktır. Bir duvar orada değilse, ona bitişik hücrede olup olmadığını kontrol edecek ve eğer değilse, mümkün olduğunca eklenecektir. Daha sonra, seçenekleri olması koşuluyla tercih edilen yöne en yakın yönde hareket edecektir. Seçenekleri yoksa, geri gelene kadar geri döner. Bu, sonuna kadar devam eder.

Hareket ettikçe, toplam adım sayısını çıkarmak için sonunda kullanılan değişken yolda izlediği yolu kaydeder. Ayrıca, sonunda boşa giden adımları hesaplamak için kullanılan geri izlemenin kaç kez kaydedildiğini de kaydeder. Sonuna ulaştığında, labirente *s ile işaretlenmiş başından sonuna kadar en kısa yolla çıkacaktır .

Nasıl Çalışır

Labirenti çıktılama yöntemi nedeniyle (belirli karakterlerin altını çizen), bunun formdaki bir komut satırından çalıştırılması gerekir

python -c 'import filename;filename.BuildFun(Size, Seed)'

ve

python -c 'import filename;filename.SolveFun()'

burada Boyut 15 ile 50 (dahil) arasında bir tam sayı ve Tohum 4 ile Boyut (dahil) arasında bir tam sayıdır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.