maze_gif.py

'''Maze Image Class.

Coder@Sonnack.com
September 16, 2014
'''
####################################################################################################
from sys import argv
from PIL import ImageImageDraw
import colors
from maze_obj import MazeObject
####################################################################################################

HorzSpace = 20
VertSpace = 20

WallColor = colors.ixColorBlack
GridColor = colors.ixColorLightBlue

ImagePalette = []

for c in colors.ColorPalette:
    ImagePalette.extend(c)


##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
## MAZE IMAGE
##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
class MazeImage (object):
    '''|
Maze Image class.

properties:
    mz          - Maze object
    im          - Image object
    draw        - ImageDraw object
    pixels      - Pixel dimensions of image
    pmin,pmax   - ULC,LRC of Maze plot area
    p0,p1       - ULC,LRC of current cell

methods:
    draw_maze           ()
    show                ()
    save                (fn, mode='GIF')

    set_current_cell    (row, col)      - required first before using paint methods
    paint_cell          (color)         - set cell color
    paint_north_wall    ()              - set cell north wall
    paint_east_wall     ()              - set cell east wall
    paint_south_wall    ()              - set cell south wall
    paint_west_wall     ()              - set cell west wall

    str(obj)                            - properties string
    repr(obj)                           - JSON-like string

'''
    def __init__ (selfmz):
        '''Create new Maze Image instance.  NOTE: x=cols, y=rows!'''
        self.mz = mz
        # Calculate pixel parameters based on rows and columns...
        self.pixels = (HorzSpace * (self.mz.dims[1]+2), VertSpace * (self.mz.dims[0]+2))
        self.pmin = (HorzSpaceVertSpace)
        self.pmax = (self.pixels[0] - HorzSpaceself.pixels[1] - VertSpace)
        # current square is ULC...
        self.p0 = (self.pmin[0]               , self.pmin[1])
        self.p1 = (self.pmin[0]+HorzSpaceself.pmin[1]+VertSpace)
        # Create image object...
        self.im = Image.new('P'self.pixelscolors.ixColorWhite)
        self.im.putpalette(ImagePalette)
        self.draw = ImageDraw.Draw(self.im)
        # Draw outer border...
        self.draw.rectangle((0,0)+(self.pixels[0]-1,self.pixels[1]-1), outline=colors.ixColorBlack)
        self.draw.rectangle((1,1)+(self.pixels[0]-2,self.pixels[1]-2), outline=colors.ixColorGray100)
        self.draw.rectangle((2,2)+(self.pixels[0]-3,self.pixels[1]-3), outline=colors.ixColorGray200)
        # Draw vertical rules...
        for ix in range(1self.mz.dims[1]):
            pp = ix * HorzSpace
            self.draw.line([(self.pmin[0]+ppself.pmin[1]), (self.pmin[0]+ppself.pmax[1])], fill=GridColor)
        # Draw horizontal rules...
        for ix in range(1self.mz.dims[0]):
            pp = ix * VertSpace
            self.draw.line([(self.pmin[0], self.pmin[1]+pp), (self.pmax[0], self.pmin[1]+pp)], fill=GridColor)
        # Draw cell corners...
        for row in range(1self.mz.dims[0]+2):
            py = row * VertSpace
            for col in range(1self.mz.dims[1]+2):
                px = col * HorzSpace
                self.draw.rectangle((px-1,py-1)+(px+1,py), fill=colors.ixColorBlackoutline=colors.ixColorBlack)
        # Draw margins
        self.draw.line([(self.pmin[0], self.pmin[1]), (self.pmax[0], self.pmin[1])], fill=colors.ixColorDarkBluewidth=2# th
        self.draw.line([(self.pmin[0], self.pmax[1]), (self.pmax[0], self.pmax[1])], fill=colors.ixColorDarkBluewidth=2# bh
        self.draw.line([(self.pmin[0], self.pmin[1]), (self.pmin[0], self.pmax[1])], fill=colors.ixColorDarkBluewidth=2# lv
        self.draw.line([(self.pmax[0], self.pmin[1]), (self.pmax[0], self.pmax[1])], fill=colors.ixColorDarkBluewidth=2# rv

    def draw_maze (self):
        '''Draw a maze.'''
        # Cells...
        for row in range(self.mz.dims[0]):
            for col in range(self.mz.dims[1]):
                # Paint the cell...
                v = self.mz.cell(rowcol)
                if 0 < v:
                    self.set_current_cell(rowcol)
                    self.paint_cell(v)
        # Walls...
        for row in range(self.mz.dims[0]):
            for col in range(self.mz.dims[1]):
                # Set current cell...
                self.set_current_cell(rowcol)
                # Paint North and West walls...
                if self.mz.wall_n(rowcol):
                    self.paint_north_wall()
                if self.mz.wall_w(rowcol):
                    self.paint_west_wall()
            # Paint East wall...
            if self.mz.wall_e(rowcol):
                self.paint_east_wall()
        # Paint South-most walls...
        for col in range(self.mz.dims[1]):
            # Set current cell...
            self.set_current_cell(rowcol)
            if self.mz.wall_s(rowcol):
                self.paint_south_wall()

    def set_current_cell (selfrowcol):
        '''Set current cell for drawing operations.'''
        if (row < 0or (self.mz.dims[0] <= row):
            raise Exception("Row is out of bounds!")
        if (col < 0or (self.mz.dims[1] <= col):
            raise Exception("Col is out of bounds!")
        cx = self.pmin[0] + (col * HorzSpace)
        cy = self.pmin[1] + (row * VertSpace)
        self.p0 = (cx,cy)
        self.p1 = (cx+HorzSpacecy+VertSpace)

    def paint_cell (selfcolor):
        self.draw.rectangle([self.p0self.p1], fill=coloroutline=colors.ixColorBlack)

    def paint_north_wall (self):
        '''Draw north wall in current cell.'''
        self.draw.line([(self.p0[0], self.p0[1]), (self.p1[0], self.p0[1])], fill=WallColorwidth=2)

    def paint_south_wall (self):
        '''Draw south wall in current cell.'''
        self.draw.line([(self.p0[0], self.p1[1]), (self.p1[0], self.p1[1])], fill=WallColorwidth=2)

    def paint_west_wall (self):
        '''Draw west wall in current cell.'''
        self.draw.line([(self.p0[0], self.p0[1]), (self.p0[0], self.p1[1])], fill=WallColorwidth=2)

    def paint_east_wall (self):
        '''Draw east wall in current cell.'''
        self.draw.line([(self.p1[0], self.p0[1]), (self.p1[0], self.p1[1])], fill=WallColorwidth=2)

    def show (self):
        self.im.show()
        return self

    def save (selffnmode='GIF'):
        self.im.save(fnmode)
        return self

    def __str__ (self):
        s = '%s (%d,%d) %s'
        t = (self.im.formatself.im.size[0], self.im.size[1], self.im.mode)
        return s % t

    def __repr__ (self):
        s = '{MazeImage:{format:"%s", size:%s, mode:"%s", addr:%x}}'
        t = (self.im.formatstr(self.im.size), self.im.modeself.__hash__())
        return s % t




####################################################################################################
if __name__ == '__main__':
    print('autorun: %s' % argv[0])

    mz = MazeObject(1216)
    mi = MazeImage(mz)

    mi.set_current_cell(1,0)
    mi.paint_north_wall()
    mi.paint_west_wall()

    mi.set_current_cell(1,1)
    mi.paint_cell(colors.ixColorLightRed)
    mi.paint_north_wall()
    mi.paint_east_wall()
    mi.paint_south_wall()
    mi.paint_west_wall()

    mi.set_current_cell(1,2)
    mi.paint_north_wall()

    mi.set_current_cell(0,2)
    mi.paint_north_wall()
    mi.paint_west_wall()

    mi.set_current_cell(2,2)
    mi.paint_west_wall()

    mi.show()
    mi.save('maze_gif.gif')

####################################################################################################
'''eof'''