"""
$RCSfile: common.py,v $ $Revision: 1.2 $
Author: Trevor R.H. Clarke <retrev@csh.rit.edu>
Description: common defines, functions, etc.
"""
import re
import game

# Crossover constants
#
C_ONE = 1
C_TWO = 2

# verbose?
#
v = 0
PRINTEVERY = 10 # when in verbose mode, print information about
		# the hero every PRINTEVERY generations

# GA Controls
#
CTYPE = C_ONE
MRATE_C = 0.10 # the chance an allele changes
MRATE_A = 0.05 # the chance alleles are added
MRATE_D = 0.05 # the chance alleles are deleted
MRATE_F = 0.20 # the chance to reverse 2 alleles
MADD_MIN = 1
MADD_MAX = 10  # min and max to add
PSIZE = 10     # population size
MAXGENS = 250  # number of generations to run for
MIN_GEN0 = 2   # minimum length of gen 0 string
MAX_GEN0 = 10  # maximum length of gen 0 string


def fill_list(size, val):
    """
	create a list of length size and initialize it with val
        if val == None then initialize the list with numbers from 0 to size-1
	   this is done for efficiency as the only loop will be the one
	   internal to range()
    """
    l = []
    if val == None:
	l = range(size)
    else:
	for x in range(size):
	    l.append(val)
    return l


class tarray:
    """
	this is an x by y array of values
	v is the value to initialize the array to
    """
    def __init__(self,x,y,v=None):
	"""
	    initalize the array (data) and size (size) variables
	"""
	self.data = fill_list(x*y,v)
	self.size = (x,y)
    
    def __getitem__(self,p): # (x,y)
	"""
	    tarray[[x,y]]
	    this returns the [x,y]'th element in the array and raise's
	    an exception when an invalid index is given
	"""
	if p[0] >= self.size[0] or p[1] >= self.size[1]:
	    raise IndexError,"Index too large"
	elif p[0] < 0 or p[1] < 0:
	    raise IndexError,"Index too small"
	return self.data[(p[1] * self.size[0]) + p[0]]

    def __setitem__(self,p,v): # (x,y)
	"""
	    tarray[[x,y]] = v
	    this sets the [x,y]'th element in the array to v
	    it raise's an exception when an invalid index is given
	"""
	if p[0] >= self.size[0] or p[1] >= self.size[1]:
	    raise IndexError,"Index too large"
	elif p[0] < 0 or p[1] < 0:
	    raise IndexError,"Index too small"
	self.data[(p[1] * self.size[0]) + p[0]] = v



def filter_string(st,fit,grid):
    """
	this function tries to find extraneous moves in a string
    """
    tmps = st
    tmpf = fit

    # find occurances of NS,SN,EW,WE since these combinations move you nowhere
    #
    p1 = re.compile('(NS)|(SN)|(EW)|(WE)')
    m = p1.search(tmps)
    while m != None:
	m = p1.search(tmps)
	tmps2 = tmps[:m.span()[0]] + tmps[m.span()[1]:]
	tmpf2 = game.play_game(grid,tmps2)
	if tmpf2 >= tmpf:
	    tmps,tmpf = tmps2,tmpf2
	else:
	    break
    
    # find patters of the form
    #   sl = len(string); x is all divisors of sl; y = sl/x
    #   ([NSEW]{x}){y}
    #
    sl = len(tmps)
    tmps2 = tmps
    for i in range(1,sl / 2 + 1):
	if sl % i == 0:
	    g1 = tmps2[:i]
	    tmps2 = tmps2[i:]
	    match = 1
	    while len(tmps2) > 0:
		g = tmps2[:i]
		tmps2 = tmps2[i:]
		if g != g1:
		    match = 0
		    break
	    if match:
		tmps2 = g1
		break
	    else:
		tmps2 = tmps
    tmpf2 = game.play_game(grid,tmps2)
    if tmpf2 >= tmpf:
	tmps,tmpf = tmps2,tmpf2

    return tmps,tmpf
