Before you write a maze runner you have to write a maze generator.  Using the recursive backtracking approach I'll create a simple text maze.  Phase one of any maze implementation is defining a single cell in our maze.

The maze will be composed of an array of these cells.

import chalk

class Cell():
    row = 0
    column = 0
    start = False
    visited = False
    value = 0
    current = False
    walls = {
        'north':  True,
        'east':   True,
        'south':  True,
        'west':   True
    }

    def __init__(self, row, column):
        self.row = row
        self.column = column
        self.visited = False

    def __str__(self):
        cell = "[{0:03d}] ".format(self.value)
        if self.start:
            return chalk.green(cell)
        elif self.current:
            return chalk.red(cell)
        elif self.visited:
            return chalk.yellow(cell)
        return cell

    def set_current(self, value):
        self.current = value

    def set_value(self, value):
        self.value = value

    def set_walls(self, walls):
        self.walls.update(walls)

    def get_coordinates(self):
        return [self.row, self.column]

Next I define a Board class that can populate an array of cells fetch cells that are adjacent to a target cell.

import Cell


class Board():
    board = []
    max_rows = 0
    max_columns = 0

    def __str__(self):
        new_str = ''
        for row in range(self.max_rows):
            for col in range(self.max_columns):
                new_str += str(self.board[col + row * self.max_columns])
            new_str += "\n"
        return new_str

    def __init__(self, max_rows, max_columns):
        self.max_rows = max_rows
        self.max_columns = max_columns
        # make board
        for row in range(max_rows):
            for col in range(max_columns):
                self.board.append(Cell.Cell(row, col))

    def find_neighbour(self, target):
        neighbours = dict()
        # north
        if target.row + 1 < self.max_rows:
            index = (target.row + 1)*self.max_columns + target.column
            if not(self.board[index].visited):
                neighbours['north'] = self.board[index]

        # east
        if target.column + 1 < self.max_columns:
            index = (target.row * self.max_columns + (target.column + 1))
            if not(self.board[index].visited):
                neighbours['east'] = self.board[index]

        # south
        if target.row - 1 >= 0:
            index = ((target.row - 1)*self.max_columns + target.column)
            if not(self.board[index].visited):
                neighbours['south'] = self.board[index]

        # west
        if target.column - 1 >= 0:
            index = (target.row * self.max_columns + (target.column - 1))
            if not(self.board[index].visited):
                neighbours['west'] = self.board[index]

        return neighbours
     

Finally, we put the two together in our `main.py` and implement a MazeGenerator class.  This will construct a board and traverse it to make our maze.

import random
import Board
import os
import time

class MazeGenerator:
    current_path = []
    board_rows = 10
    board_columns = 10
    start_cell = None
    count = 0

    def __init__(self, rows, columns):
        self.board_rows = rows
        self.board_columns = columns
        self.my_board = Board.Board(self.board_rows, self.board_columns)
        self.start_cell = self.my_board.board[0]
        self.start_cell.start = True
        self.count = 0
        self.make_maze(self.start_cell)

    def make_maze(self, target):
        # time.sleep(0.25)
        target.current = True
        target.visited = True
        if target.value == 0:
            target.set_value(self.count)
            self.count += 1

        neighbours = self.my_board.find_neighbour(target)

        os.system('cls' if os.name == 'nt' else 'clear')
        print(self.my_board)

        if len(neighbours) > 0:
            # pick a neighbour to visit
            direction, next_cell = random.choice(list(neighbours.items()))
            print('visiting neighbour', next_cell)

            new_walls = dict()
            new_walls[direction] = False
            target.set_walls(new_walls)
            self.current_path.append(target)
            target.current = False
            return self.make_maze(next_cell)
        elif len(neighbours) == 0 and len(self.current_path) > 0:
            print('popping off')
            target.current = False
            next_cell = self.current_path.pop()
            return self.make_maze(next_cell)
        else:
            print('done')
            return target