summaryrefslogblamecommitdiff
path: root/misc/maze.py
blob: b1d47f3a0cc3b4931b036f6a522a11e361885cbf (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12











                                                          





                                                          


































                                                                                               
               


















































                                                                                              




                                                            
              
                                               


                           
                                                     
 





                        
          
                                                          

                            
                     





                                               

                              







                                                                                                                                      

                            


                    

                         


                                                                                 
                             
                    


                                                                                                   
 

                

                       
 









                                                                                                                                                                     
                          

                     
                                                       
 
                                 


                                                             

                                      

                                                                   
 

                                             






                     
#!/usr/bin/python2

import numpy
from numpy.random import randint as rand
import sys

def tile():
    tiles=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
           1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,
           1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,10]
    return str(tiles[rand(len(tiles))])

def block20(txt=True):
    if txt:
        return "5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,";
    else:
        return [5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5];

def generate_maze(width=81, height=51, complexity=.75, density=.75):
    """Generate a maze using a maze generation algorithm."""
    # Only odd shapes
    shape = ((height // 2) * 2 + 1, (width // 2) * 2 + 1)
    # Adjust complexity and density relative to maze size
    complexity = int(complexity * (5 * (shape[0] + shape[1])))  # Number of components
    density    = int(density * ((shape[0] // 2) * (shape[1] // 2)))  # Size of components
    # Build actual maze
    Z = numpy.zeros(shape, dtype=int)
    # Fill borders
    Z[0, :] = Z[-1, :] = 1
    Z[:, 0] = Z[:, -1] = 1
    # Make aisles
    for i in range(density):
        x, y = rand(0, shape[1] // 2) * 2, rand(0, shape[0] // 2) * 2  # Pick a random position
        Z[y, x] = 1
        for j in range(complexity):
            neighbours = []
            if x > 1:             neighbours.append((y, x - 2))
            if x < shape[1] - 2:  neighbours.append((y, x + 2))
            if y > 1:             neighbours.append((y - 2, x))
            if y < shape[0] - 2:  neighbours.append((y + 2, x))
            if len(neighbours):
                y_, x_ = neighbours[rand(0, len(neighbours) - 1)]
                if Z[y_, x_] == 0:
                    Z[y_, x_] = 1
                    Z[y_ + (y - y_) // 2, x_ + (x - x_) // 2] = 1
                    x, y = x_, y_
    return Z

# Receive arguments from commandline
try:
    MaxMazes = int(sys.argv[1])
    x = int(sys.argv[2])
    y = int(sys.argv[3])
    ry = int(y)
except IndexError:
    print("Usage: ./maze.py <number of mazes> <width> <height>")
    print("")
    print("Creates random mazes. Must strip final comma and automap. Reorder.")
    exit(0)


# Base class
class dlist(list):
    def __setitem__(self, index, value):
        size = len(self)
        if index >= size:
            self.extend(0 for _ in range(size, index + 1))
        list.__setitem__(self, index, value)

def MakeMaze(maze):
    TRUEMAZE=[]
    xc=yc=1 # Cursors

    # Setup TRUEMAZE
    i=0
    while i < (y+1):
        # Three instances per Y
        TRUEMAZE.append(dlist())
        TRUEMAZE.append(dlist())
        TRUEMAZE.append(dlist())
        i+=1

    # Build TRUEMAZE
    for row in maze:
        for r in row:
            r=str(r)
            #print "(%d, %d) = %s" % (xc, yc, r)
            TRUEMAZE[max(0, yc-1)][max(0, xc-1)]=int(r.replace('1', '5').replace('0', tile()))
            TRUEMAZE[max(0, yc-1)][max(0, xc)]=int(r.replace('1', '5').replace('0', tile()))
            TRUEMAZE[max(0, yc-1)][max(0, xc+1)]=int(r.replace('1', '5').replace('0', tile()))

            TRUEMAZE[max(0, yc)][max(0, xc-1)]=int(r.replace('1', '5').replace('0', tile()))
            TRUEMAZE[max(0, yc)][max(0, xc)]=int(r.replace('1', '5').replace('0', tile()))
            TRUEMAZE[max(0, yc)][max(0, xc+1)]=int(r.replace('1', '5').replace('0', tile()))

            TRUEMAZE[max(0, yc+1)][max(0, xc-1)]=int(r.replace('1', '5').replace('0', tile()))
            TRUEMAZE[max(0, yc+1)][max(0, xc)]=int(r.replace('1', '5').replace('0', tile()))
            TRUEMAZE[max(0, yc+1)][max(0, xc+1)]=int(r.replace('1', '5').replace('0', tile()))

            xc+=3

        xc=1
        yc+=3
    return TRUEMAZE

def BuildLayer(LayerName, w, h, LayerData, invisible=False):
    if invisible:
        inv=' visible="0"'
    else:
        inv=""
    return("""
     <layer name="%s" width="%d" height="%d"%s>
      <data encoding="csv">
%s
      </data>
     </layer>""" % (LayerName, w, h, inv, LayerData))

# Begin
print "Begin!"

MazeID=0
while MazeID < MaxMazes:
    MazeID+=1
    y=ry+0
    print("Building Maze %02d/%02d!" % (MazeID, MaxMazes))
    maze=generate_maze(x, y)

    print(repr(maze))

    TRUEMAZE=MakeMaze(maze)
    width=len(TRUEMAZE[1])
    name="mz%03d_%02d%02d.tmx" % (MazeID, x, y)

    f=open(name, "w");
    print("open // %s" % name)

    # Generate Margins
    MZLINE=str(TRUEMAZE[0]).replace('[','').replace(']','').replace(' ','').replace("10", "5").replace("1", "5").replace("2", "5")+","
    MARGIN=""
    i=0
    while i < 20:
        i+=1
        MARGIN+=block20()+MZLINE+block20()+"\n"

    # Create the maze string
    MAZEDATA=""
    MAZEDATA+=MARGIN

    # Fill maze data
    for line in TRUEMAZE:
        if line != []:
            MAZEDATA+=block20()
            MAZEDATA+=(str(line).replace('[','').replace(']','').replace(' ',''))
            MAZEDATA+=","+block20()+"\n"
    # Clean MAZEDATA properly
    MAZEDATA+=MARGIN
    MAZEDATA=MAZEDATA[:-2]+"\n"
    #MAZEMPTY=MAZEDATA.replace("10", "1").replace("2", "1").replace("5", "0")
    MAZEMPTY=MAZEDATA.replace("10", "0").replace("1", "0").replace("2", "0").replace("5", "0")[:-1]

    # Margin fix
    width+=40
    height=((y+1)*3)+40
    y+=40

    # Write the TMX file
    f.write("""<?xml version="1.0" encoding="UTF-8"?>
    <map version="1.0" tiledversion="1.0.3" orientation="orthogonal" renderorder="right-down" width="%d" height="%d" tilewidth="32" tileheight="32" nextobjectid="1">
     <properties>
      <property name="AutomappingRadius" value="1"/>
      <property name="DeleteTiles" value="true"/>
     </properties>
     <tileset firstgid="1" name="set_cave" tilewidth="32" tileheight="32" tilecount="64" columns="8">
      <image source="../Rules/tilesets/set_cave.png" width="256" height="256"/>
     </tileset>
    """ % (width, height))

    # Build set layer
    f.write(BuildLayer("set", width, height, MAZEDATA))

    # Build the other tile layers
    f.write(BuildLayer("Ground",    width, height, MAZEMPTY))
    f.write(BuildLayer("Fringe",    width, height, MAZEMPTY))
    f.write(BuildLayer("Over",      width, height, MAZEMPTY))

    # Build the other invisible layers
    f.write(BuildLayer("Collision", width, height, MAZEMPTY, True))
    f.write(BuildLayer("Heights",   width, height, MAZEMPTY, True))

    # Close the mapfile
    f.write(""" <objectgroup name="Objects"/>
    </map>""")


    # And, we're done
    f.close()