Python implementation of recursive method to solve the maze problem example code

Time:2021-2-20

Maze problem

Problem Description:

Maze can be represented by square matrix [M, n], 0 means that it can pass, 1 means that it cannot pass. If the upper left corner (0, 0) is required to enter, the algorithm is designed to find a path that can go out from the lower right corner (m-1, n-1).

Example figure:

期望输出路径图

The basic parameters of this example diagram are as follows:

  • m: Correspondence
  • X-axis n: corresponding to y-axis
  • The green line represents the path of the desired output

Algorithm thinking

  1. Mark current location
  2. If the position at this time is the end point, it means that you can reach the end point and exit recursion;

Otherwise, there are four possible moving directions, i.e. up, down, left and right. Traverse these four directions. If there are points with adjacent value of 0 in these four directions, mark the current point coordinate as the point coordinate with adjacent value of 0, and enter recursion

Intuitive understanding is as follows:

递归理解图

In the figure above, if there are three points with the adjacent value of 0 in the red circle, they will traverse the three points in turn to seek a certain condition and enter recursion

Implementation process

Marker function

def mark(maze, pos):
  """
  Mark function, used to mark the location of the history
  : param maze: an M * n-size two-dimensional matrix maze
  : param pos: the current position coordinates to be marked POS = (x, y), x = POS [0], y = POS [1]
  """
  Make [POS [0] [POS [1]] = 2

Moving function

def move(maze, pos):
  """
  The move function is used to test whether the current position can continue to move. The move condition is that the current position is 0
  : param maze: an M * n-size two-dimensional matrix maze
  : param pos: the current position coordinates to be marked POS = (x, y), x = POS [0], y = POS [1]
  : Return: bool type
  """
  return maze[pos[0]][pos[1]] == 0

Core function path lookup function

def find_path(maze, start, end):
  """
  Path lookup function
  : param maze: an M * n-size two-dimensional matrix maze
  : param start: start point position coordinates, start = (1,1)
  : param end: end coordinates, end = (m, n)
  : Return: bool type
  """
  Mark (make, start) ා mark the starting position
  If start = = end: # the end condition of path lookup (recursion) is to reach the end point
    move_path.append(start)
    return True

  #Before reaching the destination, there are four possible moving directions: up (- 1,0), down (1,0), left (0, - 1), right (0,1)
  move_direction = [
    (-1, 0), (1, 0), (0, -1), (0, 1)
  ]
  direction = ['↑', '↓', '←', '→']
  For I in range (4): # traverse four possible directions
    next_ start = (start[0] + move_ direction[i][0], start[1] + move_ Direction [i] [1]) the next possible starting point coordinates
    if move(maze, next_ Start): # find out the coordinates of the next starting point that can be moved when there is 0, and enter recursion
      if find_path(maze, next_start, end):
        #The reason why the starting point coordinates are still added here is that when the next position is the end point or reachable end point, the current position is recorded
        move_path.append(start)
        path_ direction.append (direction [i]) record the path direction
        return True
  Return false # if you can't reach the destination after traversing four possible directions, you can't walk out of the maze

So far, the algorithm has been basically completed, and it is not too complicated on the whole

Beautify output

Generating maze matrix with moving path data

def path_maze(maze, directions_map):
  """
  Generating maze matrix with moving path
  : param maze: an M * n-size two-dimensional matrix maze
  :param directions_ Map: a dictionary to record the coordinates of the moving direction, with ↑, ↓, ←, → 4 elements
  :return: path_maze
  """
  n, m = len(maze[0]), len(maze)
  for x in range(1, m-1):
    for y in range(1, n-1):
      Maze [x] [y] = maze [x] [y] if maze [x] [y]! = 2 else 0 # restore marked 2 to 0

  for x in range(m):
    for i in range(1, 2 * n - 1, 2):
      Maze [x]. Insert (I, ') ා reinitialize maze, and insert three spaces between every two elements

  for x in range(1, 2 * m - 1, 2):
    maze.insert (x, [','] * (n-1) + [']) #

  for direction in directions_map:
    for directions_position in directions_map[direction]:
      i, j = directions_position
      i = 2 * i
      j = 2 * j
      if direction == "↑":
        maze[i - 1][j] = "↑"
      if direction == "↓":
        maze[i + 1][j] = "↓"
      if direction == "←":
        maze[i][j] = " ← "
      if direction == "→":
        maze[i][j + 1] = " → "
  return maze

The generated partial data screenshot of maze matrix with path data is as follows:

带路径数据的矩阵

Beautify printing maze matrix

def print_ Maze (maze, text ='the original maze is: ', end1 =', end2 = ', XS = 0, Xe = 0, ys = 0, ye = 0):'
  """
  Output labyrinth matrix, not necessary, can be deleted
  : param maze: an M * n-size two-dimensional matrix maze
  : param text: output prompt
  : param end1: controls the end of each line
  : param end2: controls the end of each line
  : param XS: control whether to output the top 1 loop, 0 is output, 1 is not output
  : param Xe: control whether to output the top 1 loop, 0 is output, 1 is not output
  : paramys: control whether to output the top 1 loop, 0 is output, 1 is not output
  : param ye: control whether to output the top 1 loop, 0 is output, 1 is not output
  """
  print(text)
  n, m = len(maze[0]), len(maze)
  for x in range(xs, m-xe):
    for y in range(ys, n-ye):
      print(maze[x][y], end=end1)
    print(end=end2)

The final output results are as follows

美化打印

The effect is acceptable

Complete code

# -*- coding: utf-8 -*-
"""
Created on 2020/1/11 10:51
Author : zxt
File  : maze_recursion.py
Software: PyCharm
"""


from random import randint


def mark(maze, pos):
  """
  Mark function, used to mark the location of the history
  : param maze: an M * n-size two-dimensional matrix maze
  : param pos: the current position coordinates to be marked POS = (x, y), x = POS [0], y = POS [1]
  """
  Make [POS [0] [POS [1]] = 2


def move(maze, pos):
  """
  The move function is used to test whether the current position can continue to move. The move condition is that the current position is 0
  : param maze: an M * n-size two-dimensional matrix maze
  : param pos: the current position coordinates to be marked POS = (x, y), x = POS [0], y = POS [1]
  : Return: bool type
  """
  return maze[pos[0]][pos[1]] == 0


move_ Path = [] # record the moving path coordinates that can successfully reach the exit
path_ Direction = [] # record the direction of the moving path that can successfully reach the exit


def find_path(maze, start, end):
  """
  Path lookup function
  : param maze: an M * n-size two-dimensional matrix maze
  : param start: start point position coordinates, start = (1,1)
  : param end: end coordinates, end = (m, n)
  : Return: bool type
  """
  Mark (make, start) ා mark the starting position
  If start = = end: # the end condition of path lookup (recursion) is to reach the end point
    move_path.append(start)
    return True

  #Before reaching the destination, there are four possible moving directions: up (- 1,0), down (1,0), left (0, - 1), right (0,1)
  move_direction = [
    (-1, 0), (1, 0), (0, -1), (0, 1)
  ]
  direction = ['↑', '↓', '←', '→']
  For I in range (4): # traverse four possible directions
    next_ start = (start[0] + move_ direction[i][0], start[1] + move_ Direction [i] [1]) the next possible starting point coordinates
    if move(maze, next_ Start): # find out the coordinates of the next starting point that can be moved when there is 0, and enter recursion
      if find_path(maze, next_start, end):
        #The reason why the starting point coordinates are still added here is that when the next position is the end point or reachable end point, the current position is recorded
        move_path.append(start)
        path_ direction.append (direction [i]) record the path direction
        return True
  Return false # if you can't reach the destination after traversing four possible directions, you can't walk out of the maze


def gen_maze(m, n):
  """
  Generating random maze array
  : param: int type
  : param n: int type
  :return: maze
  """
  m += 2
  N + = 2 # m and N are both + 2 in order to construct the outermost 1
  Maze = [[1 for I in range (n)] for J in range (m)] # initialize a two-dimensional matrix with size m * N and all values 1
  for x in range(1, m-1):
    for y in range(1, n-1):
      """
      Here, the value range of X and Y is x ∈ [1, m-1), y ∈ [1, n-1) because we make the outermost layer (all around) of the maze 1
      A possible array of 3 * 3 matrices is as follows
      [
       _ |←--- n:y ---→|
       ↑ [1, 1, 1, 1, 1],
       | [1, 0, 1, 0, 1],
      m:x [1, 0, 0, 1, 1],
       | [1, 1, 0, 0, 1],
       ↓ [1, 1, 1, 1, 1] 
      ]
      """
      if (x == 1 and y == 1) or (x == m - 2 and y == n - 2):
        Maze [x] [y] = 0
      else:
        Maze [x] [y] = randInt (0,1) # if the outermost layer is all 1, take 0,1 randomly
  return maze


def print_ Maze (maze, text ='the original maze is: ', end1 =', end2 = ', XS = 0, Xe = 0, ys = 0, ye = 0):'
  """
  Output labyrinth matrix, not necessary, can be deleted
  : param maze: an M * n-size two-dimensional matrix maze
  : param text: output prompt
  : param end1: controls the end of each line
  : param end2: controls the end of each line
  : param XS: control whether to output the top 1 loop, 0 is output, 1 is not output
  : param Xe: control whether to output the top 1 loop, 0 is output, 1 is not output
  : paramys: control whether to output the top 1 loop, 0 is output, 1 is not output
  : param ye: control whether to output the top 1 loop, 0 is output, 1 is not output
  """
  print(text)
  n, m = len(maze[0]), len(maze)
  for x in range(xs, m-xe):
    for y in range(ys, n-ye):
      print(maze[x][y], end=end1)
    print(end=end2)


def path_maze(maze, directions_map):
  """
  Generating maze matrix with moving path
  : param maze: an M * n-size two-dimensional matrix maze
  :param directions_ Map: a dictionary to record the coordinates of the moving direction, with ↑, ↓, ←, → 4 elements
  :return: path_maze
  """
  n, m = len(maze[0]), len(maze)
  for x in range(1, m-1):
    for y in range(1, n-1):
      Maze [x] [y] = maze [x] [y] if maze [x] [y]! = 2 else 0 # restore marked 2 to 0

  for x in range(m):
    for i in range(1, 2 * n - 1, 2):
      Maze [x]. Insert (I, ') ා reinitialize maze, and insert three spaces between every two elements

  for x in range(1, 2 * m - 1, 2):
    maze.insert (x, [','] * (n-1) + [']) #

  for direction in directions_map:
    for directions_position in directions_map[direction]:
      i, j = directions_position
      i = 2 * i
      j = 2 * j
      if direction == "↑":
        maze[i - 1][j] = "↑"
      if direction == "↓":
        maze[i + 1][j] = "↓"
      if direction == "←":
        maze[i][j] = " ← "
      if direction == "→":
        maze[i][j + 1] = " → "
  return maze


def main():
  # maze = gen_maze(m=10, n=12)
  maze = \
    [
      [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
      [1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1],
      [1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1],
      [1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1],
      [1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1],
      [1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1],
      [1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1],
      [1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1],
      [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1],
      [1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1],
      [1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1],
      [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
    ]Input style matrix, where the outermost layer is surrounded by a ring, in order to facilitate subsequent processing, you can use Gen_ Self generation of maze() function
  print_maze(maze)
  if find_path(maze, start=(1, 1), end=(10, 12)):
    mp = move_path[::-1]
    pd = path_direction[::-1]
    #Here, both POS [0] and POS [1] need - 1 because there is an outermost 1-ring in the original recursive computation
    Print ('coordinate moving order: ', [(POS [0] - 1, POS [1] - 1) for POS in MP])
    path_direction_map = {
      '↑': [],
      '↓': [],
      '←': [],
      '→': []
    }Mapping table of path direction
    for i in range(len(pd)):
      path_direction_map[pd[i]].append(mp[i])
    maze = path_maze(maze, path_direction_map)
    print_ Maze (maze, text ='maze moving path is: ', end1 =', end2 = ', XS = 1, Xe = 1, ys = 1, ye = 1)
  else:
    Print ('There is no solution to this maze ')


if __name__ == '__main__':
  main()

The above is the whole content of this article, I hope to help you learn, and I hope you can support developer more.