Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在python中使用递归解决迷宫_Python_Recursion_Maze - Fatal编程技术网

在python中使用递归解决迷宫

在python中使用递归解决迷宫,python,recursion,maze,Python,Recursion,Maze,所以,我有一个作业,要求我用递归解一个迷宫。我会把作业指导贴出来,这样你就能明白我在说什么了。教授没有对递归进行太多的解释,他给了我们一些递归的例子,我将在这里发布,但我希望有人能给我一个更深入的递归解释,以及我如何将其应用于解决迷宫。我不是要求任何人编写代码,我只是希望一些解释能让我走上正确的道路。感谢所有回答的人 以下是我的例子: def foo(): print("Before") bar() print("After")

所以,我有一个作业,要求我用递归解一个迷宫。我会把作业指导贴出来,这样你就能明白我在说什么了。教授没有对递归进行太多的解释,他给了我们一些递归的例子,我将在这里发布,但我希望有人能给我一个更深入的递归解释,以及我如何将其应用于解决迷宫。我不是要求任何人编写代码,我只是希望一些解释能让我走上正确的道路。感谢所有回答的人

以下是我的例子:

    def foo():
        print("Before")
        bar()
        print("After")

    def bar():
        print("During")


    def factorial(n):
        """n!"""
        product = 1
        for i in range(n,0,-1):
        product *= i
        return product

    def recFac(n):
        """n! = n * (n-1)!"""
        if(n == 1):
          return 1
        return n * recFac(n-1)

    def hello():
        """Stack overflow!"""
        hello()

    def fib(n):
        """f(n) = f(n-1) + f(n-2)
        f(0) = 0
        f(1) = 1"""
        if n == 0 or n == 1: #base case
           return n
        return fib(n-1) + fib(n-2) #recursive case

    def mult(a,b):
        """a*b = a + a + a + a ..."""
        #base case
        if (b == 1):
           return a
        #recursive case
        prod = mult(a,b-1)
        prod *= a
        return prod


    def exp(a,b):
        """a ** b = a* a * a * a * a *.... 'b times'"""
        #base case
        if (b==0):
           return 1
        if (b == 1):
           return a
        #recursive case
        return exp(a,b-1)*a

    def pallindrome(word):
        """Returns True if word is a pallindrome, False otherwise"""
        #base case
        if word == "" or len(word)==1:
           return True

        #recursive case
        if word[0] == word[len(word)-1]:
        word = word[1:len(word)-1]
        return pallindrome(word)
        else:
            return False
以下是指导原则:

    def foo():
        print("Before")
        bar()
        print("After")

    def bar():
        print("During")


    def factorial(n):
        """n!"""
        product = 1
        for i in range(n,0,-1):
        product *= i
        return product

    def recFac(n):
        """n! = n * (n-1)!"""
        if(n == 1):
          return 1
        return n * recFac(n-1)

    def hello():
        """Stack overflow!"""
        hello()

    def fib(n):
        """f(n) = f(n-1) + f(n-2)
        f(0) = 0
        f(1) = 1"""
        if n == 0 or n == 1: #base case
           return n
        return fib(n-1) + fib(n-2) #recursive case

    def mult(a,b):
        """a*b = a + a + a + a ..."""
        #base case
        if (b == 1):
           return a
        #recursive case
        prod = mult(a,b-1)
        prod *= a
        return prod


    def exp(a,b):
        """a ** b = a* a * a * a * a *.... 'b times'"""
        #base case
        if (b==0):
           return 1
        if (b == 1):
           return a
        #recursive case
        return exp(a,b-1)*a

    def pallindrome(word):
        """Returns True if word is a pallindrome, False otherwise"""
        #base case
        if word == "" or len(word)==1:
           return True

        #recursive case
        if word[0] == word[len(word)-1]:
        word = word[1:len(word)-1]
        return pallindrome(word)
        else:
            return False
你将要创建一个迷宫爬虫,能够解决任何你用递归的力量给它的迷宫

问题1-加载迷宫

在解迷宫之前,你必须先加载它。对于本作业,您将使用迷宫的简单文本格式。您可以使用此示例迷宫或创建自己的迷宫

这个问题的目的是加载任何给定的迷宫文件,并将其读入二维列表。 例如:loadMaze(“somemaze.maze”)应该加载somemaze.maze文件并创建如下列表

    [['#','#','#','#','#','#','#','#','#'], 
     ['#','S','#',' ',' ',' ','#','E','#'], 
     ['#',' ','#',' ','#',' ',' ',' ','#'], 
     ['#',' ',' ',' ','#',' ','#',' ','#'], 
     ['#', #','#','#','#','#','#','#','#']] 
请注意,列表中已删除所有“\r”和“\n”字符。为了简化下一个问题,可以将此列表设置为全局变量

接下来编写一个函数,以更好的格式打印迷宫:

例如:

继续之前,请使用不同的迷宫测试代码

问题2-准备解决迷宫

在解决迷宫之前,你需要找到起点!在代码中添加一个名为findStart()的函数,该函数将搜索迷宫(逐个字符),并返回“S”字符的x和y坐标。你可以假设迷宫中最多有一个这样的角色。如果在迷宫中未找到“S”,则返回-1作为x和y坐标

继续之前,在多个位置(包括无位置)使用“S”测试代码

问题3-解决迷宫

最后,您已经准备好递归求解迷宫了!您的解决方案应该只需要一种方法:solve(y,x)

solve方法的单个实例应该可以解决迷宫中的单个位置。参数y和x是要求解的当前坐标。有几件事你的解决方法应该完成。它应该检查当前是否正在解决“E”的位置。在这种情况下,您的求解方法已成功完成。否则,它应该尝试递归地求解右边的空间。注意,您的方法应该只尝试求解空间,而不是墙(“#”)。如果递归没有结束,那么尝试向下、向左和向上。如果所有这些都失败了,代码应该回溯一个步骤,然后尝试另一个方向

最后,在解决迷宫时,您的代码应该留下进度指标。如果它正在右侧搜索,则当前位置应该有一个“>”来代替空白。如果向下搜索,请输入“v”。如果搜索左'len(mazeList)或x>len(mazeList[y]): 返回错误 如果mazeList[y][x]=“E”: 返回真值 如果mazeList[y][x]!=" ": 返回错误 #标记 如果解算(x+1,y)=真:#右 mazeList[x][y]='>' elif solve(x,y+1)=真:#向下 mazeList[x][y]=“v” elif solve(x-1,y)=真:#左
mazeList[x][y]='递归实际上是一个简单的想法:为了解决问题,你将问题缩小一步,然后解决简化后的问题。这会一直持续到你遇到一个你知道如何完全解决的“基本问题”。返回基本解决方案,然后添加到每个步骤返回的解决方案中,直到得到完整的解决方案

所以要解n!,我们记住n并求(n-1)!。基本情况是1!,为此,我们返回1;然后在每个返回步骤中,我们乘以记忆中的数字(2*1!是2,3*2!是6,4*3!是24,5*4!是120),直到我们乘以n得到完整解。这实际上是一种相当苍白和贫血的复发;每个步骤只有一个可能的决定。这被称为“尾部递归”,非常容易从内到外转换为迭代解(从1开始,乘以每个数,直到n)

一种更有趣的递归方法是将问题一分为二,解决每一半,然后将两个一半的解决方案结合起来;例如,快速排序通过选取一个项目对列表进行排序,将列表分为“小于项目的所有项目”和“大于项目的所有项目”,每一半进行快速排序,然后返回快速排序(较小)+项目+快速排序(较大)。基本情况是“当我的列表只有一项时,它被排序”

对于迷宫,我们将把问题分为四种方式——如果我从当前位置向右、向左、向上和向下搜索,所有的解决方案都是可能的——特别的是,只有一种递归搜索会真正找到解决方案。基本情况是“我站在E上”,失败情况是“我在墙上”或“我在我已经访问过的空间上”


编辑:出于兴趣,这里有一个OO解决方案(与Python 2.x和3.x兼容):

请注意,给定的赋值有几个非音速元素:

  • 它要求使用
    camelCase
    函数名,而不是
    下划线\u分隔的
  • 它建议使用全局变量,而不是显式地传递数据
  • 它要求
    find\u start
    在失败时返回标志值,而不是引发异常
    • (和我自己约会时,我在高中的COBOL中确实遇到过这个问题。)

      你可以把解决迷宫看作是采取步骤

      当你迈出一步时,同样的规则每次都适用。因为每次都应用相同的规则,所以可以对每个步骤使用完全相同的指令集。什么时候
          main("somemaze.maze")
          ######### 
          #S#   #E# 
          # # #   # 
          #   # # # 
          #########
      
           ######### 
           #S#>>v#E# 
           #v#^#>>^# 
           #>>^# # # 
           #########
      
          def loadMaze():
              readIt = open('Maze.txt', 'r')
              readLines = readIt.readlines()
              global mazeList
              mazeList = [list(i.strip()) for i in readLines]
      
          def showMaze():
              for i in mazeList:
                  mazeprint = ''
              for j in i:
                  mazeprint = mazeprint + j
              print(mazeprint)
              print('\n')    
      
          def solve(x,y, mazeList):
              mazeList[x][y] = "o"
              #Base case  
              if y > len(mazeList) or x > len(mazeList[y]):
                 return False
              if mazeList[y][x] == "E":
                 return True 
              if mazeList[y][x] != " ":
                 return False
              #marking
              if solve(x+1,y) == True:  #right
                 mazeList[x][y]= '>'
              elif solve(x,y+1) == True:  #down
                   mazeList[x][y]= 'v'     
              elif solve(x-1,y) == True:  #left
                   mazeList[x][y]= '<'     
              elif solve(x,y-1) == True:  #up
                   mazeList[x][y]= '^'
              else:
                 mazeList[x][y]= ' '
              return (mazeList[x][y]!= ' ')
      
      from collections import namedtuple
      
      Dir = namedtuple("Dir", ["char", "dy", "dx"])
      
      class Maze:
          START = "S"
          END   = "E"
          WALL  = "#"
          PATH  = " "
          OPEN  = {PATH, END}  # map locations you can move to (not WALL or already explored)
      
          RIGHT = Dir(">",  0,  1)
          DOWN  = Dir("v",  1,  0)
          LEFT  = Dir("<",  0, -1)
          UP    = Dir("^", -1,  0)
          DIRS  = [RIGHT, DOWN, LEFT, UP]
      
          @classmethod
          def load_maze(cls, fname):
              with open(fname) as inf:
                  lines = (line.rstrip("\r\n") for line in inf)
                  maze  = [list(line) for line in lines]
              return cls(maze)
      
          def __init__(self, maze):
              self.maze = maze
      
          def __str__(self):
              return "\n".join(''.join(line) for line in self.maze)
      
          def find_start(self):
              for y,line in enumerate(self.maze):
                  try:
                      x = line.index("S")
                      return y, x
                  except ValueError:
                      pass
      
              # not found!
              raise ValueError("Start location not found")
      
          def solve(self, y, x):
              if self.maze[y][x] == Maze.END:
                  # base case - endpoint has been found
                  return True
              else:
                  # search recursively in each direction from here
                  for dir in Maze.DIRS:
                      ny, nx = y + dir.dy, x + dir.dx
                      if self.maze[ny][nx] in Maze.OPEN:  # can I go this way?
                          if self.maze[y][x] != Maze.START: # don't overwrite Maze.START
                              self.maze[y][x] = dir.char  # mark direction chosen
                          if self.solve(ny, nx):          # recurse...
                              return True                 # solution found!
      
                  # no solution found from this location
                  if self.maze[y][x] != Maze.START:       # don't overwrite Maze.START
                      self.maze[y][x] = Maze.PATH         # clear failed search from map
                  return False
      
      def main():
          maze = Maze.load_maze("somemaze.txt")
      
          print("Maze loaded:")
          print(maze)
      
          try:
              sy, sx = maze.find_start()
              print("solving...")
              if maze.solve(sy, sx):
                  print(maze)
              else:
                  print("    no solution found")
          except ValueError:
              print("No start point found.")
      
      if __name__=="__main__":
          main()
      
      Maze loaded:
          ####################################
          #S#  ##  ######## # #      #     # #
          # #   #             # #        #   #
          #   # ##### ## ###### # #######  # #
          ### # ##    ##      # # #     #### #
          #   #    #  #######   #   ###    #E#
          ####################################
      solving...
          ####################################
          #S#  ##  ######## # #>>>>>v#  >>v# #
          #v#>>v#    >>>v     #^#   >>>>^#>>v#
          #>>^#v#####^##v######^# #######  #v#
          ### #v##>>>^##>>>>>v#^# #     ####v#
          #   #>>>^#  #######>>^#   ###    #E#
          ####################################
      
       1. Start at the entrance.  
       2. Call the function solve(x,y) with the entrance co-ordinates  
       3. in solve, return false if the input point has already been handled or is a wall.  
       4. Mark the current point as handled (tag = 'o')  
       5. go to the right and call solve on that point. If it returns true, set tag to '>'  
       6 elif do the same for left and '<'  
       7 elif do the same for up and '^'  
       8 elif do the same for down and 'v'  
       9 else this is a false path, set tag = ' ' 
      10 set the current maze point to tag
      11 return (tag != ' ')
      
      return(tag != 'o')
      
      import sys
      sys.setrecursionlimit(5000)
      
      
      class Maze(object):
          FLOOR = ' '
          WALLS = '*'
          PATH = '+'
      
          def __init__(self):
              self.cols = 0
              self.rows = 0
              self.maze = []
      
          def walk_forward(self, current_k, r, c):
              self.maze[r][c] = current_k
              next_k = current_k + 1
              # up
              if r > 1:
                  up = self.maze[r - 1][c]
                  if up != self.WALLS:
                      if up == self.FLOOR or int(up) > current_k:
                          self.walk_forward(next_k, r - 1, c)
              # down
              if r < self.rows - 1:
                  down = self.maze[r + 1][c]
                  if down != self.WALLS:
                      if down == self.FLOOR or int(down) > current_k:
                          self.walk_forward(next_k, r + 1, c)
              # left
              if c > 1:
                  left = self.maze[r][c - 1]
                  if left != self.WALLS:
                      if left == self.FLOOR or int(left) > current_k:
                          self.walk_forward(next_k, r, c - 1)
              # right
              if c < self.cols - 1:
                  right = self.maze[r][c + 1]
                  if right != self.WALLS:
                      if right == self.FLOOR or int(right) > current_k:
                          self.walk_forward(next_k, r, c + 1)
      
          def walk_backward(self, r, c):
              current_k = self.maze[r][c]
              if not isinstance(current_k, int):
                  return False
              self.maze[r][c] = self.PATH
      
              up = self.maze[r - 1][c] if r > 0 else None
              down = self.maze[r + 1][c] if r < self.rows - 1 else None
              left = self.maze[r][c - 1] if c > 1 else None
              right = self.maze[r][c + 1] if c < self.cols else None
      
              passed = False
              if up and isinstance(up, int) and up == current_k - 1:
                  self.walk_backward(r - 1, c)
                  passed = True
              if down and isinstance(down, int) and down == current_k - 1:
                  self.walk_backward(r + 1, c)
                  passed = True
              if left and isinstance(left, int) and left == current_k - 1:
                  self.walk_backward(r, c - 1)
                  passed = True
              if right and isinstance(right, int) and right == current_k - 1:
                  self.walk_backward(r, c + 1)                    
      
          def cleanup(self, cleanup_path=False):
              for r in range(0, self.rows):
                  for c in range(0, self.cols):
                      if isinstance(self.maze[r][c], int):
                          self.maze[r][c] = self.FLOOR
                      if cleanup_path and self.maze[r][c] == self.PATH:
                          self.maze[r][c] = self.FLOOR
      
          def solve(self, start='up', show_path=True):
              # finding start and finish points
              upper = lower = None
              for c in range(0, self.cols):
                  if self.maze[0][c] == self.FLOOR:
                      upper = (0, c)
                      break
              for c in range(0, self.cols):
                  if self.maze[self.rows - 1][c] == self.FLOOR:
                      lower = (self.rows - 1, c)
                      break
              if start == 'up':
                  start = upper
                  finish = lower
              else:
                  start = lower
                  finish = upper
      
              self.cleanup(cleanup_path=True)
              self.walk_forward(1, start[0], start[1])
              length = self.maze[finish[0]][finish[1]]
              if not isinstance(length, int):
                  length = 0
              if show_path:
                  self.walk_backward(finish[0], finish[1])
                  self.cleanup(cleanup_path=False)
              else:
                  self.cleanup(cleanup_path=True)
              return length
      
          def save_to_file(self, filename):
              with open(filename, 'w') as f:
                  f.writelines(str(self))
      
          def load_from_file(self, filename):
              self.maze = []
              with open(filename, 'r') as f:
                  lines = f.readlines()
              for line in lines:
                  row = []
                  for c in line.strip():
                      row.append(c)
                  self.maze.append(row)
              self.rows = len(self.maze)
              self.cols = len(self.maze[0]) if self.rows > 0 else 0
      
          def get_maze(self):
              return copy.copy(self.maze)
      
          def __str__(self):
              as_string = u''
              for row in self.maze:
                  as_string += u''.join([str(s)[-1] for s in row]) + "\n"
              return as_string
      
      
      maze = Maze()
      maze.load_from_file(sys.argv[1])
      maze.solve(show_path=True)
      print str(maze)
      
      #import part
      import time
      import sys
      import os
      
      #global values
      load = 0                                 # set initial loading value
      walk = [(1,0),(-1,0),(0,1),(0,-1)]       # set movements
      backtracker = []                         # set backtracker (remember that this is a stack)
      gmainmaze = []                           # set initial blank maze
      
      def initialize():   #loading 
          sx = 0 # start x value
          sy = 0 # start y value
          ex = 0 # end x value
          ey = 0 # end y value
          while load == 0:    #just some cool animation
              sys.stdout.write("\rloading |")
              time.sleep(0.1)
              sys.stdout.write("\rloading /")
              time.sleep(0.1)
              sys.stdout.write("\rloading -")
              time.sleep(0.1)
              sys.stdout.write("\rloading \\")
              time.sleep(0.1)
              sys.stdout.write("\r")
              mainmaze = loadMaze("maze.txt") # IMPORTANT: load the maze under the same folder named "maze.txt"
              print("Maze Loaded")
              print(" ")
              time.sleep(1)
              print(" ")
              print("Locating start point...")
              sx, sy = spotter(5,mainmaze)
              time.sleep(1)
              print(" ")
              print("Locating end point...")
              ex, ey = spotter(3,mainmaze)
              print(" ")
              time.sleep(1)
              return sx, sy, ex, ey, mainmaze;
              break
          print(" ")
          sys.stdout.write("\rInitialized!")
          print(" ")
          time.sleep(3)
          os.system("cls")
      
      def loadMaze(filename):
          #load the data from the file into a 2D list
          with open(filename) as i:
              maze = []
              for line in i:
                  line = line.strip()
                  spawnmaze = line.split(", ")
                  maze.append(spawnmaze)
          return maze
      
      def spotter(num,maze):
          #Locate the 'element' in the maze (this can either be "5" or "3")
          num = str(num)
          rowcounter = -1
          linecounter = 0
          for rows in maze:
              rowcounter = rowcounter + 1
              if num in rows:
                  for element in rows:
                      if element == num:
                          print("Tango Spotted, Grid:", rowcounter, linecounter)
                          return rowcounter, linecounter;
                          break
                      linecounter = linecounter + 1
      
      def valid(maze,x,y): # check if valid
          height = len(maze) - 1
          width = len(maze[0]) - 1
          if 0 <= x <= height and 0 <= y <= width:
              return 1
          else: 
              return 0
      
      def solveMaze(sx,sy,ex,ey): # solve maze
          global gmainmaze
          for i in walk:          #try every direction
              x = sx + i[0]       #make the move
              y = sy + i[1]
              if valid(gmainmaze,x,y): # check if still in the maze
                  if x == ex and y == ey: #check if reached destination
                      print("SITREP:Destination Arrived")
                      print("The Logistic Path Is:\n",backtracker)
                      print(" ")
                      return 1
                  else:
                      if gmainmaze[x][y] == "0" and (x,y) not in backtracker: #add to the stack
                          backtracker.append((x,y))
                      else:
                          continue
              else:
                  continue
              if solveMaze(x,y,ex,ey) == 1: # Recursion (do the next step)
                  return 1
              else:
                  continue
          go = backtracker.pop(-1) #moveback while 
          return 0
      
      def printMaze(maze):
          for x in range(len(maze)):
              for y in range(len(maze[x])):
                  print(maze[x][y], end=' ')
              print("")
      
      def visualize(maze):    # a cool function to visualize the maze
          for x in range(len(maze)):
              for y in range(len(maze[x])):
                  if maze[x][y] == "5":
                      maze[x][y] = "╳"    # path
                  elif maze[x][y] == "0":
                      maze[x][y] = "░"    # unbeen path
                  elif maze[x][y] == "1":
                      maze[x][y] = "█"    # wall
                  elif maze[x][y] == "3":
                      maze[x][y] = "╳"    # basically path as well
                  print(maze[x][y], end=' ')
              print("")
      
      
      def main():
          #initialize the maze
          sx, sy, ex, ey, mainmaze = initialize()
          global gmainmaze
          gmainmaze = mainmaze
          load = 1
          #solve the maze
          gmainmaze[sx][sy] = "0"
          gmainmaze[ex][ey] = "0" # change the start and end into "0" to make it a way
          solveMaze(sx,sy,ex,ey)
          for i in backtracker:
              gmainmaze[i[0]][i[1]] = "5"
          gmainmaze[sx][sy] = "5"
          gmainmaze[ex][ey] = "3" # change the start and end back
          #print the maze
          width = len(gmainmaze[0]) - 1
          print("Check Your Map...")
          print("Map:")
          print("--"*(width+1))
          printMaze(gmainmaze)
          print("--"*(width+1))
          #visualize the maze uncomment to establish the function (btw check if your terminal can print these unicodes)
          #visualize(gmainmaze)
          time.sleep(5)
      
      main()
      © 2020 GitHub, Inc.