game_matrix_def_file.py

#! /usr/bin/python3
# ==================================================================
# 3D Matrix Game - Load Matrix Definition File
# ==================================================================

import game_matrix_config as cfg
import game_matrix_menu   as mnu
import game_matrix01      as gm1


# ---- global data -------------------------------------------------
# CurrentNode  matrix current (working) node
# Debug        flag - print debug messages
# EndNode      matrix path end node
# MatrixEdge   nodes per matrix dimensions (x,y,z)
# StartNode    matrix path start node
# Verbose      flag - print verbose messages
# ------------------------------------------------------------------

global CurrentNode
global Debug
global EndNode
global MatrixEdge
global StartNode
global Verbose

# ----- matrix definition file data --------------------------------
#
# ------------------------------------------------------------------

df_current_node = None
df_end_node     = None
df_matrix_edge  = None
df_node         = []
df_start_node   = None
df_wormhole     = []


# ---- local data --------------------------------------------------
# directions   allowed movement directions
# ------------------------------------------------------------------

directions = [ 'forward', 'backward', 'left', 'right',
               'up', 'down' ]


# ---- matrix definition file error message ------------------------

def def_file_error(lcount,line):
    '''
    Display matrix definition file error message.
    '''
    mnu.clear_screen()
    print('=======================================================')
    print('Error in matrix definition file\n(line={}) ({})'.
          format(lcount,line))
    print('=======================================================')
    mnu.pause_program()


# ---- matrix definition internal error ----------------------------

def df_file_internal_error(mgs):
    mnu.clear_screen()
    print('=======================================================')
    print('Internal Error')
    print('{}'.format(msg))
    print('=======================================================')
    mnu.pause_program()


# ---- convert string to integer -----------------------------------

def convert_str_to_int(str,lcount,line):
    '''
    Convert string to integer.
    Return integer if ok or None if an error.
    '''
    sstr = str.strip()
    if sstr == '':
        def_file_error(lcount,line)
        return None
    if sstr.isdigit() != True:
        def_file_error(lcount,line)
        return None
    return int(sstr)


# ---- process matrixedge ------------------------------------------

def process_matrixedge(llist,lcount,line):
    '''
    Process matrix edge definition.
    Return True if ok or False if an error.
    '''

    # ---- matrix edge parameters

    if len(llist) != 2:
       def_file_error(lcount,line)
       return False

    # ---- matrixside length

    l = convert_str_to_int(llist[1],lcount,line)
    if l == None:
        return False

    # ---- save data

    global df_matrix_edge
    df_matrix_edge = l

    return True


# ---- process startnode -------------------------------------------

def process_startnode(llist,lcount,line):
    '''
    Process start node definition.
    Return True if ok or False if an error.
    '''

    # ---- start node parameters

    if len(llist) != 4:
       def_file_error(lcount,line)
       return False

    # ---- start node coordinates

    x = convert_str_to_int(llist[1],lcount,line)
    if x == None:
        return False

    y = convert_str_to_int(llist[2],lcount,line)
    if y == None:
        return False

    z = convert_str_to_int(llist[3],lcount,line)
    if z == None:
        return False

    # ---- save data

    global df_start_node
    df_start_node = (x,y,z)

    return True


# ---- process endnode ---------------------------------------------

def process_endnode(llist,lcount,line):
    '''
    Process end node definition.
    Return True if ok or False if an error.
    '''

    # ---- end node parameters

    if len(llist) != 4:
       def_file_error(lcount,line)
       return False

    # ---- end node coordinates

    x = convert_str_to_int(llist[1],lcount,line)
    if x == None:
        return False

    y = convert_str_to_int(llist[2],lcount,line)
    if y == None:
        return False

    z = convert_str_to_int(llist[3],lcount,line)
    if z == None:
        return False

    # ---- save data

    global df_end_node
    df_end_node = (x,y,z)

    return True


# ---- process currentnode -----------------------------------------

def process_currentnode(llist,lcount,line):
    '''
    Process current node definition.
    Return True if ok or False if an error.
    '''

    # ---- current node parameters

    if len(llist) != 4:
       def_file_error(lcount,line)
       return False

    # ---- current node coordinates

    x = convert_str_to_int(llist[1],lcount,line)
    if x == None:
        return False

    y = convert_str_to_int(llist[2],lcount,line)
    if y == None:
        return False

    z = convert_str_to_int(llist[3],lcount,line)
    if z == None:
        return False

    # ---- save data

    global df_current_node
    df_current_node = (x,y,z)

    return True


# ---- process wormhole --------------------------------------------

def process_wormhole(llist,lcount,line):
    '''
    Process wormhole definition.
    Return True if ok or False if an error.
    '''

    # ---- wormhole parameters

    if len(llist) < 7:
       def_file_error(lcount,line)
       return False

    # ---- wormhole source node coordinates

    sx = convert_str_to_int(llist[1],lcount,line)
    if sx == None:
        return False

    sy = convert_str_to_int(llist[2],lcount,line)
    if sy == None:
        return False

    sz = convert_str_to_int(llist[3],lcount,line)
    if sz == None:
        return False

    # ---- wormhole destination node coordinates

    dx = convert_str_to_int(llist[4],lcount,line)
    if dx == None:
        return False

    dy = convert_str_to_int(llist[5],lcount,line)
    if dy == None:
        return False

    dz = convert_str_to_int(llist[6],lcount,line)
    if dz == None:
        return False

    # --- test for one way / two way

    if len(llist) < 7:
        w = 'oneway'
    elif llist[7] == 'oneway':
        w = 'oneway'
    elif llist[7] == 'twoway':
        w = 'twoway'
    else:
        def_file_error(lcount,line)
        return False

    # --- save data

    global def_wormhole
    df_wormhole.append((sx,sy,sz,dx,dy,dz,w))

    return True


# ---- process node ------------------------------------------------

def process_node(llist,lcount,line):
    '''
    Process node definition.
    Return True if ok or False if an error.
    '''

    # ---- node parameters

    if len(llist) < 5:
       def_file_error(lcount,line)
       return False

    # ---- node coordinates

    x = convert_str_to_int(llist[1],lcount,line)
    if x == None:
        return False

    y = convert_str_to_int(llist[2],lcount,line)
    if y == None:
        return False

    z = convert_str_to_int(llist[3],lcount,line)
    if z == None:
        return False

    # ---- movement direction

    d = llist[4]
    if d not in directions:
        def_file_error(lcount,line)
        return False

    # --- test for one way / two way

    if len(llist) < 6:
        w = 'oneway' 
    elif llist[5] == 'oneway':
        w = 'oneway'
    elif llist[5] == 'twoway':
        w = 'twoway'
    else:
        def_file_error(lcount,line)
        return False

    # ---- save data

    global df_wormhole
    df_node.append((x,y,z,d,w))

    return True


# ---- read matrix definition file ---------------------------------

def read_matrix_definition(filename):
    '''
    Read a matrix definition file and save the data.
    Return True if successful and False if not.
    '''

    if cfg.Debug:
        print('read_matrix_definition({})'.format(filename))

    # ---- initialize matrix definition data

    df_current_node = None
    df_end_node     = None
    df_matrix_edge  = None
    df_node         = []
    df_start_node   = None
    df_wormhole     = []

    # ---- open matrix definition file

    inFile = open(filename,'r')

    # ---- process each line of the file

    lcount = 0

    for line in inFile:

        lcount += 1

        # ---- strip leading and trailing whitespace

        sline = line.strip()
        ##print(sline)
        ##print('line  type={}  len={}'.format(type(sline),len(sline)))

        # ---- blank line?

        if not sline:
            ##print('blank line')
            continue

        # ---- comment line?
        # ---- (first non-space char is '#')

        if sline[0][:1] == '#':
            ##print('comment line')
            continue

        # ---- split line

        llist = sline.split()

        # ---- process line

        if cfg.Debug:
            print(llist)

        if llist[0] == 'matrixedge':
            if process_matrixedge(llist,lcount,line) == False:
                inFile.close()
                return False
        elif llist[0] == 'startnode':
            if process_startnode(llist,lcount,line) == False:
                inFile.close()
                return False
        elif llist[0] == 'endnode':
            if process_endnode(llist,lcount,line) == False:
                inFile.close()
                return False
        elif llist[0] == 'currentnode':
            if process_currentnode(llist,lcount,line) == False:
                inFile.close()
                return False
        elif llist[0] == 'node':
            if process_node(llist,lcount,line) == False:
                inFile.close()
                return False
        elif llist[0] == 'wormhole':
            if process_wormhole(llist,lcount,line) == False:
                inFile.close()
                return False
        else:
            def_file_error(lcount,line)
            inFile.close()
            return False

    # ---- close input file

    inFile.close()
    return True


# ---- read matrix definition file ---------------------------------

def load_matrix_definition(filename):
    '''
    Load a matrix definition file's data and create the matrix.
    Return the matrix if successful and None if not.
    '''

    # ---- read matrix definition file

    if read_matrix_definition(filename) != True:
        return False

    # ---- create matrix

    mtrx = gm1.create_matrix(df_matrix_edge,100)

    if mtrx == None:
        return False

    # ---- add path nodes

    for n in df_node:
        x = n[0]
        y = n[1]
        z = n[2]
        d = n[3]
        w = n[4]

        if w != 'oneway' and w != 'twoway':
            msg = 'bad twoway direction ({})'.format(w)
            df_file_internal_error(msg)
            return None


        if d == 'forward':
            mtrx[x][y][z].forward         = mtrx[x][y][z+1]
            if w == 'twoway':
                mtrx[x][y][z+1].backward  = mtrx[x][y][z]

        elif d == 'backward':
            mtrx[x][y][z].backward        = mtrx[x][y][z-1]
            if w == 'twoway':
                mtrx[x][y][z-1].forward   = mtrx[x][y][z]

        elif d == 'up':
            mtrx[x][y][z].up              = mtrx[x][y+1][z]
            if w == 'twoway':
                mtrx[x][y+1][z].down      = mtrx[x][y][z]

        elif d == 'down':
            mtrx[x][y][z].down            = mtrx[x][y-1][z]
            if w == 'twoway':
                mtrx[x][y-1][z].up        = mtrx[x][y][z]

        elif d == 'left':
            mtrx[x][y][z].left            = mtrx[x-1][y][z]
            if w == 'twoway':
                mtrx[x-1][y][z].right     = mtrx[x][y][z]

        elif d == 'right':
            mtrx[x][y][z].right           = mtrx[x+1][y][z]
            if w == 'twoway':
                mtrx[x+1][y][z].left      = mtrx[x][y][z]

        else:
            msg = 'bad node movement direction ({})'.format(d)
            df_file_internal_error(msg)
            return None

    # ---- add path wormholes

    for w in df_wormhole:
        sx = w[0]
        sy = w[1]
        sz = w[2]
        ex = w[3]
        ey = w[4]
        ez = w[5]
        ww = w[6]
        mtrx[sx][sy][sz].wormhole = mtrx[ex][ey][ez]
        if ww == 'twoway':
            mtrx[ex][ey][ez].wormhole = mtrx[sx][sy][sz]

    # ---- update configuration information

    cfg.MatrixEdge = df_matrix_edge

    x = df_current_node[0]
    y = df_current_node[1]
    z = df_current_node[2]

    cfg.CurrentNode = mtrx[x][y][z]

    x = df_start_node[0]
    y = df_start_node[1]
    z = df_start_node[2]

    cfg.StartNode = mtrx[x][y][z]

    x = df_end_node[0]
    y = df_end_node[1]
    z = df_end_node[2]

    cfg.EndNode = mtrx[x][y][z]

    # ---- return matrix

    return mtrx


# ------------------------------------------------------------------
# ---- main --------------------------------------------------------
# ------------------------------------------------------------------

if __name__ == '__main__':

    cfg.Debug = True 

    ##filename = 'game_matrix_01.txt'
    filename   = 'game_matrix_02.txt'
    ##filename = 'game_matrix_03.txt'

    load_matrix_definition(filename)

    print('EOF')

    print('\n---- Definition File Data -----------------')

    print('df_matrix_edge  = {}'.format(df_matrix_edge))
    print('df_current_node = {}'.format(df_current_node))
    print('df_end_node     = {}'.format(df_end_node))
    print('df_start_node   = {}'.format(df_start_node))

    print('df_node (len={})'.format(len(df_node)))
    for x in df_node:
        print('   node {}'.format(x))

    print('df_wormhole (len={})'.format(len(df_wormhole)))
    for x in df_wormhole:
        print('   wormhole {}'.format(x))