सैंडबॉक्स करते समय [भूलभुलैया पर डिजाइन और हल करें]


14

आपका कार्य इस दृश्य में दोनों पात्रों की भूमिकाएँ निभाना है । इसमें, कोब ने अराडने को एक चुनौती दी:

आपके पास एक भूलभुलैया डिजाइन करने के लिए दो मिनट हैं जिन्हें हल करने में एक मिनट लगता है।

उस विवरण पर कुछ स्वतंत्रता ली जाएगी। सबसे महत्वपूर्ण बात, यह चुनौती समय-आधारित नहीं है, बल्कि स्कोर आपके mazes और भूलभुलैया-सॉवर्स की प्रभावशीलता पर आधारित हैं।

मैं इस चुनौती के लिए कई संपादन के लिए माफी माँगता हूँ क्योंकि हम एक आसान और निष्पक्ष प्रारूप की ओर बढ़ते हैं।

भाग I: भूलभुलैया प्रारूप

सभी मजार चौकोर हैं। भूलभुलैया में एक सेल को शून्य-अनुक्रमित टपल के रूप में दर्शाया गया है row column

दीवारों को दो बाइनरी स्ट्रिंग्स द्वारा दर्शाया गया है: एक क्षैतिज दीवारों के लिए (जो पंक्तियों के बीच आंदोलन को रोकती है) और ऊर्ध्वाधर दीवारें (इसके विपरीत)। एक NxNभूलभुलैया पर, Nx(N-1)प्रत्येक प्रकार की संभव दीवारें हैं । चलो एक 3x3 उदाहरण लेते हैं जहां कोशिकाओं को लेबल किया जाता है:

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

सभी संभव ऊर्ध्वाधर दीवारें हैं AB BC DE EF GH HI:। एक तार में अनुवादित, दिखाई गई दीवारें 011001ऊर्ध्वाधर दीवारों के लिए और 010010क्षैतिज दीवारों के लिए हैं। इसके अलावा, "बाइनरी स्ट्रिंग" से मेरा मतलब है "वर्ण '0' और '1'"।

पूर्ण भूलभुलैया प्रारूप एक स्ट्रिंग है जिसमें इस क्रम में शामिल है:

  • चौड़ाई
  • सेल टपल शुरू करें
  • एंड सेल टुपल
  • क्षैतिज दीवारें
  • ऊर्ध्वाधर दीवारों

उदाहरण के लिए, यह भूलभुलैया:

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

इसे स्वरूपित किया गया है:

5
4 2
0 2
00001011101110001100
10100110000100010010

भाग II: वास्तुकार

आर्किटेक्ट प्रोग्राम भूलभुलैया बनाता है। इसे नियमों से खेलना चाहिए और एक वैध भूलभुलैया प्रदान करना चाहिए (जहां एक समाधान मौजूद है, और अंत शुरू के शीर्ष पर नहीं है)।

इनपुट: दो सकारात्मक पूर्णांक:

size [random seed]

कहाँ sizeमें हो जाएगा [15, 50]। आपको यादृच्छिक बीज का उपयोग करने के लिए प्रोत्साहित किया जाता है ताकि मैचों को फिर से दोहराया जा सके, हालांकि इसकी आवश्यकता नहीं है।

आउटपुट: भाग I "वैध" में वर्णित प्रारूप का उपयोग करके एक मान्य आकार x आकार (वर्ग) भूलभुलैया का मतलब है कि एक समाधान मौजूद है, और प्रारंभ सेल अंत सेल के बराबर नहीं है।

किसी दिए गए भूलभुलैया पर एक वास्तुकार का स्कोर है

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

इसलिए आर्किटेक्ट्स को जटिल माज़ों के लिए पुरस्कृत किया जाता है, लेकिन निर्मित प्रत्येक दीवार के लिए दंडित किया जाता है (यह अरैडने के समय के प्रतिबंध का एक विकल्प है)। dist()समारोह सुनिश्चित करें कि कोई दीवारों के साथ एक भूलभुलैया एक अनंत स्कोर नहीं प्राप्त करता है। भूलभुलैया की बाहरी सीमाएं दीवार की गिनती में योगदान नहीं करती हैं।

भाग III: सॉल्वर

सॉल्वर दूसरों के आर्किटेक्ट द्वारा उत्पन्न mazes को हल करने का प्रयास करता है। एक प्रकार का कोहरा-युद्ध होता है: केवल विज़िट की गई कोशिकाओं से सटे दीवारों को शामिल किया जाता है (अन्य सभी को '?' से बदल दिया जाता है)

इनपुट: एक ही भूलभुलैया प्रारूप, लेकिन 'के साथ?' जहां दीवारें अज्ञात हैं, वर्तमान स्थान के लिए एक अतिरिक्त रेखा और इस स्थान से मान्य विकल्पों की अल्पविराम से अलग सूची। (यह एक बड़ा संपादन है, जो भूलभुलैया-पार्सिंग फ़ंक्शन लिखने के लिए सरल बनाने के लिए है)

उदाहरण (एक कदम छोड़ देने के बाद उपरोक्त 5x5 भूलभुलैया के समान)

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

जो कुछ इस तरह से मेल खाता है, जहां ?कोहरा है:

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

आउटपुट: मान्य विकल्पों की सूची में से एक tuples

प्रत्येक सॉल्वर का स्कोर आर्किटेक्ट के स्कोर का विलोम है।

भाग IV: पहाड़ी के राजा

आर्किटेक्ट और सॉल्वर को अलग-अलग अंक दिए गए हैं, इसलिए संभावित रूप से दो विजेता हो सकते हैं।

आर्किटेक्ट और सॉल्वर की प्रत्येक जोड़ी में एक-दूसरे को पछाड़ने के कई मौके होंगे। सभी परीक्षणों और विरोधियों पर स्कोर औसत किया जाएगा। कोड गोल्फ सम्मेलनों के विपरीत, उच्चतम औसत स्कोर जीत!

मैं इसे जारी रखने का इरादा रखता हूं, लेकिन मैं निरंतर परीक्षण की गारंटी नहीं दे सकता! अभी के लिए मान लीजिए कि एक सप्ताह में एक विजेता घोषित किया जाएगा।

भाग V: प्रस्तुत करना

  • मैं सभी सबमिशन पर वीटो पावर बनाए रखता हूं - चतुराई को प्रोत्साहित किया जाता है, लेकिन यह नहीं कि यह प्रतियोगिता या मेरे कंप्यूटर को तोड़ दे! (यदि मैं नहीं बता सकता कि आपका कोड क्या करता है, तो मैं शायद इसे वीटो करूंगा)
  • अपने वास्तुकार / सॉल्वर जोड़ी के लिए एक नाम के साथ आओ। इसे चलाने के निर्देशों के साथ अपना कोड भी पोस्ट करें।

जल्द ही आ रहा है: नए प्रारूप के लिए एक अद्यतन अजगर परीक्षण किट। किसी भी भाषा प्रस्तुतियाँ की अनुमति देने के लिए बड़े परिवर्तन हुए।


10
इसे अजगर तक सीमित रखने के बजाय, क्या आप प्रतियोगियों द्वारा बनाए / पढ़े जाने वाले भूलभुलैया प्रारूप को परिभाषित नहीं कर सकते थे? यह शायद अधिक लोगों को दिलचस्पी होगी।
14:14

मेरे पास प्रतिबंधात्मक होने के दो कारण थे: पहला है आसानी से और सुरक्षित रूप से चल रहे मैचों को स्वचालित करना। दूसरा प्रत्येक भाषा के लिए एक पढ़ने और लेखन पुस्तकालय की आवश्यकता से बचने के लिए है। मुझे लगता है कि अगर कोई भी अजगर का उपयोग नहीं करना चाहता, तो मुझे एक या दोनों को छोड़ना होगा ...
गलत

1
मैं वर्तमान में एक रैपर लिख रहा हूं जो एक उप कार्यक्रम चलाता है और स्टडिन / स्टडआउट पर संचार करता है। इस तरह आप अपनी इच्छानुसार किसी भी भाषा का उपयोग कर सकते हैं। क्या आप इसकी अनुमति देंगे?
IchBinKeinBaum

पूर्ण रूप से! मैं पूरे प्रश्न प्रारूप को फिर से लिखने के बीच में था। क्या मैं इंतज़ार करूं?
गलत

1
मुझे नहीं पता था कि यह एक बात है। मुझे लगता है कि मैं इसे अभी के लिए रोक कर
रखूँगा

जवाबों:


1

BuildFun और SolveFun

खैर, इसमें काफी समय लगा और मुझे पूरी तरह से यकीन नहीं है कि सॉल्वर धोखा दे रहा है या नहीं। जबकि इसकी हर समय पूरी भूलभुलैया तक पहुँच होती है, यह केवल उस कक्ष को देखता है, जिसके चारों ओर की दीवारें हैं, और यदि उनके बीच कोई दीवार नहीं है, तो इससे सटे हुए कक्ष। अगर यह नियमों के खिलाफ है तो कृपया मुझे बताएं और मैं इसे बदलने की कोशिश करूंगा।

वैसे भी, यहाँ कोड है:

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

मुझे पता है कि यह हास्यास्पद रूप से लंबा है और विशेष रूप से पढ़ने में आसान नहीं है, लेकिन मैं आलसी हूं इसलिए यह कैसे रह रहा है।

BuildFun

वास्तुकार, बिल्डफुन, एक काफी सरल भूलभुलैया पैदा करने वाला कार्यक्रम है जो हमेशा एक 'परफेक्ट' भूलभुलैया बनाता है (कोई लूप नहीं है और जहां किसी भी दो बिंदुओं के बीच हमेशा एक ही रास्ता होगा)। यह बीज इनपुट के अपने तर्क को आधार बनाता है जिसका अर्थ है कि उत्पन्न हुए छद्म यादृच्छिक हैं जो अक्सर पैटर्न दोहराते हुए दिखाई देते हैं और, एक ही बीज और आकार के साथ, एक ही भूलभुलैया बनाया जाएगा।

एक बार भूलभुलैया उत्पन्न होने के बाद, प्रोग्राम स्टार्ट पॉइंट और अंत बिंदु की खोज करके भूलभुलैया के स्कोर को अधिकतम करने का प्रयास करेगा, जिसके परिणामस्वरूप उनके बीच सबसे लंबा रास्ता तय होगा। ऐसा करने के लिए, यह हर शुरुआत बिंदु से गुजरता है, इससे अंत बिंदु को दूर करने के लिए ट्रेसर को फैलाता है, और सबसे लंबे पथ के साथ संयोजन चुनता है।

इसके बाद, यह भूलभुलैया खींचता है, दीवारों को गिनता है और भूलभुलैया की जानकारी को आउटपुट करता है। यह प्रारंभ बिंदु, अंत बिंदु, उनके बीच की दूरी, दीवारों की संख्या और स्कोर है। यह आकार, प्रारंभ और अंत, क्षैतिज दीवारों और ऊर्ध्वाधर दीवारों के लिए ऊपर वर्णित शैली में भी इस जानकारी को प्रारूपित करता है और इसे बाद में उपयोग के लिए भूलभुलैया.टैक्स नामक एक पाठ फ़ाइल में सहेजता है।

SolveFun

Solver, SolveFun, इनपुट के रूप में पाठ फ़ाइल Maze.txt का उपयोग करता है और आर्किटेक्ट के समान तरीके से काम करता है। हर चाल के लिए, यह एक दिशा का चयन करेगा कि यह अंत तक अपनी सापेक्ष स्थिति के आधार पर जाना चाहता है और फिर यह आसपास की दीवारों को देखेगा। यदि एक दीवार नहीं है, तो यह देखने के लिए जांच करेगा कि क्या यह उसके बगल में सेल में है और यदि नहीं, तो इसे संभव विकल्प के रूप में जोड़ा जाएगा। यह तब अपनी पसंदीदा दिशा के सबसे निकट होगा, बशर्ते उसके पास विकल्प हों। यदि इसके पास विकल्प नहीं हैं, तो यह तब तक पीछे हट जाएगा, जब तक यह ऐसा नहीं करता। यह तब तक जारी रहता है जब तक यह अंत तक नहीं पहुंच जाता है।

जैसा कि यह चलता है, यह चर पथ में ले जाने वाले पथ को रिकॉर्ड करता है जिसका उपयोग चरणों की कुल संख्या को आउटपुट करने के लिए अंत में किया जाता है। यह अंत में व्यर्थ चरणों की गणना करने के लिए उपयोग किए जाने वाले बैकट्रैक की मात्रा को भी रिकॉर्ड करता है। जब यह अंत तक पहुंचता है, तो यह शुरुआत से अंत तक सबसे छोटे रास्ते के साथ भूलभुलैया का उत्पादन करेगा *

कैसे चलाना है

भूलभुलैया के उत्पादन की विधि के कारण (जिसमें कुछ वर्णों को रेखांकित करना शामिल है), इसे प्रपत्र में एक कमांड लाइन से चलाया जाना है

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

तथा

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

जहां आकार 15 और 50 (समावेशी) के बीच एक पूर्णांक है और बीज 4 और आकार (समावेशी) के बीच एक पूर्णांक है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.