input: Write a python function to find the paths from a given start point to end point in a maze.
  assert maze_search([['0', '0', '0', '0'], ['0', '0', '1', '0'], ['1', '1', '1', '0'], ['0', '1', '0', '0']], (0, 0), (3, 2)) == [(0, 0), (0, 1), (0, 2), (0, 3), (1, 3), (2, 3), (3, 3), (3, 2)]
  assert maze_search([['0', '1'], ['0', '0']], (0, 0), (1, 1)) == [(0, 0), (1, 0), (1, 1)]
  assert maze_search([['0', '1'], ['1', '0']], (0, 0), (1, 1)) == 'End point is unreachable'
  assert maze_search([['0', '0'], ['0', '0']], (0, 0), (1, 1)) == [(0, 0), (0, 1), (1, 1)]
output: def maze_search(maze, start, end):
      def is_valid_move(x, y):
          return 0 <= x < len(maze) and 0 <= y < len(maze[0]) and maze[x][y] == '0'
  
      def find_paths(x, y, path):
          if (x, y) == end:
              return path
          maze[x][y] = 'v'
          for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
              nx, ny = x + dx, y + dy
              if is_valid_move(nx, ny):
                  result = find_paths(nx, ny, path + [(nx, ny)])
                  if result:
                      return result
          maze[x][y] = '0'
          return None
  
      if not is_valid_move(*start) or not is_valid_move(*end):
          return 'End point is unreachable'
  
      path = find_paths(start[0], start[1], [start])
      return path if path else 'End point is unreachable'