'''
maze.py

A Python program that constructs a maze from a text file and then proceeds
to find a solution to that maze, if one exists.

by Joshua R. Davis
and !!

'''

import bopa
import re
import random
from OpenGL.GL import *

def arrayFromFile(fileName):
    # Read the file into a list of \n-terminated lines.
    file = open(fileName, 'r')
    lines = file.readlines()
    file.close()
    # Dissect each line into a list of characters.
    array = [re.findall(r'[\w ]', line) for line in lines]
    # Return the rows from bottom to top rather than top-to-bottom.
    array.reverse()
    return array

def randomArray(width, height, density):
    """Given integers width and height, returns a two-dimensional array of characters, of that width and height. The periphery is filled in with Xs, and some fraction (up to density, a float) of the interior squares are filled with walls. You must add starting and ending squares yourself."""
    # Construct array of empty spaces.
    array = []
    for i in range(height):
        row = []
        for j in range(width):
            row.append(' ')
        array.append(row)
    # Fill in periphery with walls.
    for j in range(width):
        array[0][j] = 'X'
    for i in range(height):
        array[i][0] = 'X'
        array[i][width - 1] = 'X'
    for j in range(width):
        array[height - 1][j] = 'X'
    # Place a bunch of random walls.
    for k in range(int(density * width * height)):
        i = random.randint(1, height - 2)
        j = random.randint(1, width - 2)
        array[i][j] = 'X'
    return array

class Maze(bopa.Overlay):
    """A rectangular maze of square tiles, some of which are empty, some of which are walls, one of which is the starting point, at least one of which is an ending point, some of which are step points, and some of which are failed step points."""
    
    def __init__(self, array, size=50.0):
        """Initializes the maze from the indicated two-dimensional array of characters as returned by arrayFromFile()."""
        bopa.Overlay.__init__(self)
        self.maze = array
        self.size = float(size)
    
    def draw(self):
        """Draws the maze with open spaces in white."""
        for i in range(len(self.maze)):
            for j in range(len(self.maze[i])):
                if self.maze[i][j] == ' ':
                    glColor3f(1.0, 1.0, 1.0)
                elif self.maze[i][j] == 's':
                    glColor3f(0.0, 1.0, 0.0)
                elif self.maze[i][j] == 'e':
                    glColor3f(1.0, 0.0, 0.0)
                elif self.maze[i][j] == 'o':
                    glColor3f(0.0, 0.0, 1.0)
                elif self.maze[i][j] == '.':
                    glColor3f(0.5, 0.5, 1.0)
                else:
                    glColor3f(0.0, 0.0, 0.0)
                glBegin(GL_QUADS)
                glVertex2f(self.size * j, self.size * i)
                glVertex2f(self.size * (j + 1), self.size * i)
                glVertex2f(self.size * (j + 1), self.size * (i + 1))
                glVertex2f(self.size * j, self.size * (i + 1))
                glEnd()
    
    def setSquare(self, i, j, char):
        """Sets the square in row i, column j (counting from (0, 0) in the lower-left corner) to the given character, which should be 'X', ' ', 's', 'e', 'o', or '.'. Returns nothing."""
        self.maze[i][j] = char
    
    def getSquare(self, i, j):
        """Returns the character stored in the square in row i, column j (counting from (0, 0) in the lower-left corner)."""
        return self.maze[i][j]
    
    def __str__(self):
        """Returns a string representation of the maze."""
        result = ''
        for row in self.maze:
            rowstring = ''
            for char in row:
                rowstring = rowstring + char
            result = rowstring + '\n' + result
        return result

# Set the maze file.
array = arrayFromFile('firstmaze.txt')
# Set the display size per square in pixels (an integer).
size = 20
# Make a window of appropriate size, with overlay dragging disabled.
height = size * len(array)
width = size * len(array[0])
mywindow = bopa.Window(width, height)
mywindow.setOverlayDragHandler(None)
# Make the maze overlay.
maze = Maze(array, size)
# !! You solve the maze here.
# Run the user interface.
mywindow.beginLoop()
