#! /usr/bin/python3
import sys
import random
import queue

INITIAL = '?'
START = 's'
GOAL = 'g'
WALL = 'X'
PATH = ' '

def get_neighbors(of, xlen, ylen):
    y = of[0]
    x = of[1]
    candidates = [(y, x+1), (y, x-1), (y-1, x), (y+1, x)]
    return filter(lambda a: (a[0] >= 0) and (a[0] < xlen) and (a[1] >= 0) and (a[1] < ylen), candidates)

def generate_maze(xlen, ylen, likelihood, unreachable_paths):
    maze = [[INITIAL for i in range(xlen)] for j in range(ylen)]
    start = (random.randint(0, xlen-1), random.randint(0, ylen-1))
    q = queue.Queue()
    reachables = []

    maze[start[1]][start[0]] = START
    q.put(start)

    # randomly create paths
    while len(reachables) == 0: # so we don't create a maze with no other spaces
        while not q.empty():
            cur = q.get()
            ns = get_neighbors(cur, xlen, ylen)

            for n in ns:
                if maze[n[1]][n[0]] == INITIAL:
                    if random.randint(0, 100) <= likelihood:
                        # wall
                        maze[n[1]][n[0]] = WALL
                    else:
                        # pathway
                        maze[n[1]][n[0]] = PATH
                        q.put(n)
                        reachables.append(n)

    # pick a reachable goal
    goal = reachables[random.randint(0, len(reachables) - 1)]
    maze[goal[1]][goal[0]] = GOAL

    # mark unreachable spots
    for y in range(ylen):
        for x in range(xlen):
            if maze[y][x] == INITIAL:
                if (not unreachable_paths) or (random.randint(0, 100) <= likelihood):
                    maze[y][x] = WALL
                else:
                    maze[y][x] = PATH
    return maze

def print_maze(maze):
    for row in maze:
        rowstr = "".join(row)
        print(rowstr)

if __name__ == "__main__":
    arglen = len(sys.argv)
    if (arglen != 3) and (arglen != 4) and (arglen != 5):
        sys.exit("Usage: mazegen.py <x-len> <y-len> [<wall-likelihood>] [-no-fill]")

    xlen = int(sys.argv[1])
    ylen = int(sys.argv[2])
    likelihood = int(sys.argv[3]) if (arglen == 4) else 33
    unreachable_paths = (arglen == 5) and (sys.argv[4] == "-no-fill")

    print_maze(generate_maze(xlen, ylen, likelihood, unreachable_paths))
