# L-12 MCS 275 Mon 6 Feb 2017 : maze.py
"""
A maze M is represented as a list of lists.
The position of square [i][j] is represented by M[i][j]
= -1 if the square is blocked,
= 0 if the square is free and not visited on a path,
= k > 0 if visited as the k-th square in a path.
"""

def show_maze(maze):
    """
    Writes the maze to screen, spaces if free, # is blocked.
    """
    outs = '     '
    for j in range(len(maze)):
        outs = outs + '%3d' % j
    print(outs)
    for i in range(len(maze)):
        outs = '%3d :' % i
        for j in range(len(maze[i])):
            if maze[i][j] == 0:
                outs = outs + '   '
            elif maze[i][j] == -1:
                outs = outs + '###'
            else:
                outs = outs + '%3d' % maze[i][j]
        print(outs)

def random_maze(rows, cols):
    """
    Returns a list of lists, as many lists as the value of rows,
    and every list has as many elements as the value of cols.
    A zero value indicates a free position,
    occupied positions are marked by -1.
    Positions [0][0] and [rows-1][cols-1] are free.
    """
    from random import randint
    maze = []
    for _ in range(rows):
        row = [randint(-1, 0) for _ in range(cols)]
        maze.append(row)
    maze[0][0] = 0
    maze[rows-1][cols-1] = 0
    return maze

def make_maze(rows, cols):
    """
    Generates a random maze of the dimensions specified by rows
    and cols.  The user can change the generated configuration.
    """
    maze = random_maze(rows, cols)
    while True:
        show_maze(maze)
        row = int(input('to change, give row index (-1 to exit) : '))
        if row < 0:
            break
        col = int(input('to change, give column index (-1 to exit) : '))
        if col < 0:
            break
        maze[row][col] = (-1 if maze[row][col] == 0 else 0)
    return maze

def search_path(maze, i, j, k):
    """
    Given a maze and a current free position [i][j],
    marks the position in the maze with the value of k.
    Searches a path to the position [rows-1][columns-1]
    where rows is the number of rows in maze and
    where columns is the number of elements in all rows.
    Visited tiles are marked with increasing numbers.
    Returns the maze and a boolean indicating the arrival.
    """
    maze[i][j] = k
    if i == len(maze)-1 and j == len(maze[i]) - 1:
        return (maze, True)
    else:
        arrived = False
        if i < len(maze)-1:
            if maze[i+1][j] == 0:
                (maze, arrived) = search_path(maze, i+1, j, k+1)
        if not arrived and j < len(maze[i])-1:
            if maze[i][j+1] == 0:
                (maze, arrived) = search_path(maze, i, j+1, k+1)
        if not arrived and i > 0:
            if maze[i-1][j] == 0:
                (maze, arrived) = search_path(maze, i-1, j, k+1)
        if not arrived and j > 0:
            if maze[i][j-1] == 0:
                (maze, arrived) = search_path(maze, i, j-1, k+1)
        return (maze, arrived)

def main():
    """
    Prompts for the dimensions of a grid,
    generates a random maze and starts a search.
    """
    rows = int(input('give the number of rows : '))
    cols = int(input('give the number of columns : '))
    maze = make_maze(rows, cols)
    show_maze(maze)
    (maze, found) = search_path(maze, 0, 0, 1)
    if found:
        print('path found')
    else:
        print('no path found')
    show_maze(maze)

main()
