Example #1
0
def lookforkeys(event, deltax, deltay):
    global oldcells, selrect, selpatt

    # look for keys used to flip/rotate selection
    if event == "key x none" or event == "key y none":
        # flip floating selection left-right or top-bottom
        if len(oldcells) > 0:
            g.clear(0)
            g.putcells(selpatt, deltax, deltay)
        if " x " in event:
            g.flip(0)
        else:
            g.flip(1)
        selpatt = g.transform(g.getcells(selrect), -deltax, -deltay)
        if len(oldcells) > 0:
            g.clear(0)
            g.putcells(oldcells)
            g.putcells(selpatt, deltax, deltay)
        g.update()
        return

    if event == "key > none" or event == "key < none":
        # rotate floating selection clockwise or anticlockwise;
        # because we use g.rotate below we have to use the exact same
        # calculation (see Selection::Rotate in wxselect.cpp) for rotrect:
        midx = selrect[0] + int((selrect[2]-1)/2)
        midy = selrect[1] + int((selrect[3]-1)/2)
        newleft = midx + selrect[1] - midy
        newtop = midy + selrect[0] - midx
        rotrect = [ newleft, newtop, selrect[3], selrect[2] ]
        if not rectingrid(rotrect):
            g.warn("Rotation is not allowed if selection would be outside grid.")
            return
        g.clear(0)
        if len(oldcells) > 0: g.putcells(oldcells)
        oldcells = g.join(oldcells, g.getcells(rotrect))
        g.clear(0)
        g.select(rotrect)
        g.clear(0)
        g.select(selrect)
        g.putcells(selpatt, deltax, deltay)
        if " > " in event:
            g.rotate(0)
        else:
            g.rotate(1)
        selrect = g.getselrect()
        if selrect != rotrect: g.warn("Bug: selrect != rotrect")
        selpatt = g.transform(g.getcells(selrect), -deltax, -deltay)
        if len(oldcells) > 0:
            g.clear(0)
            g.putcells(oldcells)
            g.putcells(selpatt, deltax, deltay)
        g.update()
        return

    if event == "key h none":
        showhelp2()
        return

    g.doevent(event)
Example #2
0
    def saverule(self, name, comments, table, colours):
        
        ruledir = g.getdir("rules")
        filename = ruledir + name + ".rule"

        results = "@RULE " + name + "\n\n"
        results += "*** File autogenerated by saverule. ***\n\n"
        results += comments
        results += "\n\n@TABLE\n\n"
        results += table
        results += "\n\n@COLORS\n\n"
        results += colours
        results += "\n\n@ICONS\n\n"
        results += "circles\n"

        # Only create a rule file if it doesn't already exist; this avoids
        # concurrency issues when booting an instance of apgsearch whilst
        # one is already running.
        if not os.path.exists(filename):
            try:
                f = open(filename, 'w')
                f.write(results)
                f.close()
            except:
                g.warn("Unable to create rule table:\n" + filename)
Example #3
0
def savegen(filename, gen):
    try:
        f = open(filename, 'w')
        f.write(gen)
        f.close()
    except:
        g.warn("Unable to save given gen in file:\n" + filename)
Example #4
0
def savegen(filename, gen):
    try:
        f = open(filename, 'w')
        f.write(gen)
        f.close()
    except:
        g.warn("Unable to save given gen in file:\n" + filename)
def lookforkeys(event, deltax, deltay):
   global oldcells, selrect, selpatt
   
   # look for keys used to flip/rotate selection
   if event == "key x none" or event == "key y none":
      # flip floating selection left-right or top-bottom
      if len(oldcells) > 0:
         g.clear(0)
         g.putcells(selpatt, deltax, deltay)
      if " x " in event:
         g.flip(0)
      else:
         g.flip(1)
      selpatt = g.transform(g.getcells(selrect), -deltax, -deltay)
      if len(oldcells) > 0:
         g.clear(0)
         g.putcells(oldcells)
         g.putcells(selpatt, deltax, deltay)
      g.update()
      return
   
   if event == "key > none" or event == "key < none":
      # rotate floating selection clockwise or anticlockwise;
      # because we use g.rotate below we have to use the exact same
      # calculation (see Selection::Rotate in wxselect.cpp) for rotrect:
      midx = selrect[0] + int((selrect[2]-1)/2)
      midy = selrect[1] + int((selrect[3]-1)/2)
      newleft = midx + selrect[1] - midy
      newtop = midy + selrect[0] - midx
      rotrect = [ newleft, newtop, selrect[3], selrect[2] ]
      if not rectingrid(rotrect):
         g.warn("Rotation is not allowed if selection would be outside grid.")
         return
      g.clear(0)
      if len(oldcells) > 0: g.putcells(oldcells)
      oldcells = g.join(oldcells, g.getcells(rotrect))
      g.clear(0)
      g.select(rotrect)
      g.clear(0)
      g.select(selrect)
      g.putcells(selpatt, deltax, deltay)
      if " > " in event:
         g.rotate(0)
      else:
         g.rotate(1)
      selrect = g.getselrect()
      if selrect != rotrect: g.warn("Bug: selrect != rotrect")
      selpatt = g.transform(g.getcells(selrect), -deltax, -deltay)
      if len(oldcells) > 0:
         g.clear(0)
         g.putcells(oldcells)
         g.putcells(selpatt, deltax, deltay)
      g.update()
      return

   if event == "key h none":
      showhelp2()
      return
   
   g.doevent(event)
def lookforkeys(event):
   global oldcells, object
   
   # look for keys used to flip/rotate object
   if event == "key x none" or event == "key y none":
      # flip floating object left-right or top-bottom
      g.putcells(object, 0, 0, 1, 0, 0, 1, "xor")  # erase object
      if len(oldcells) > 0: g.putcells(oldcells)
      obox = getminbox(object)
      if event == "key x none":
         # translate object so that bounding box doesn't change
         xshift = 2 * (obox.left + int(obox.wd/2))
         if obox.wd % 2 == 0: xshift -= 1
         object = g.transform(object, xshift, 0, -1, 0, 0, 1)
      else:
         # translate object so that bounding box doesn't change
         yshift = 2 * (obox.top + int(obox.ht/2))
         if obox.ht % 2 == 0: yshift -= 1
         object = g.transform(object, 0, yshift, 1, 0, 0, -1)
      oldcells = underneath(object)
      g.putcells(object)
      g.update()
      return
   
   if event == "key > none" or event == "key < none":
      # rotate floating object clockwise or anticlockwise
      # about the center of the object's bounding box
      obox = getminbox(object)
      midx = obox.left + int(obox.wd/2)
      midy = obox.top + int(obox.ht/2)
      newleft = midx + obox.top - midy
      newtop = midy + obox.left - midx
      rotrect = [ newleft, newtop, obox.ht, obox.wd ]
      if not rectingrid(rotrect):
         g.warn("Rotation is not allowed if object would be outside grid.")
         return
      g.putcells(object, 0, 0, 1, 0, 0, 1, "xor")  # erase object
      if len(oldcells) > 0: g.putcells(oldcells)
      if event == "key > none":
         # rotate clockwise
         object = g.transform(object, 0, 0, 0, -1, 1, 0)
      else:
         # rotate anticlockwise
         object = g.transform(object, 0, 0, 0, 1, -1, 0)
      # shift rotated object to same position as rotrect
      obox = getminbox(object)
      object = g.transform(object, newleft - obox.left, newtop - obox.top)
      oldcells = underneath(object)
      g.putcells(object)
      g.update()
      return

   if event == "key h none":
      showhelp2()
      return
   
   g.doevent(event)
Example #7
0
def lookforkeys(event):
    global oldcells, object

    # look for keys used to flip/rotate object
    if event == "key x none" or event == "key y none":
        # flip floating object left-right or top-bottom
        g.putcells(object, 0, 0, 1, 0, 0, 1, "xor")  # erase object
        if len(oldcells) > 0: g.putcells(oldcells)
        obox = getminbox(object)
        if event == "key x none":
            # translate object so that bounding box doesn't change
            xshift = 2 * (obox.left + int(obox.wd / 2))
            if obox.wd % 2 == 0: xshift -= 1
            object = g.transform(object, xshift, 0, -1, 0, 0, 1)
        else:
            # translate object so that bounding box doesn't change
            yshift = 2 * (obox.top + int(obox.ht / 2))
            if obox.ht % 2 == 0: yshift -= 1
            object = g.transform(object, 0, yshift, 1, 0, 0, -1)
        oldcells = underneath(object)
        g.putcells(object)
        g.update()
        return

    if event == "key > none" or event == "key < none":
        # rotate floating object clockwise or anticlockwise
        # about the center of the object's bounding box
        obox = getminbox(object)
        midx = obox.left + int(obox.wd / 2)
        midy = obox.top + int(obox.ht / 2)
        newleft = midx + obox.top - midy
        newtop = midy + obox.left - midx
        rotrect = [newleft, newtop, obox.ht, obox.wd]
        if not rectingrid(rotrect):
            g.warn("Rotation is not allowed if object would be outside grid.")
            return
        g.putcells(object, 0, 0, 1, 0, 0, 1, "xor")  # erase object
        if len(oldcells) > 0: g.putcells(oldcells)
        if event == "key > none":
            # rotate clockwise
            object = g.transform(object, 0, 0, 0, -1, 1, 0)
        else:
            # rotate anticlockwise
            object = g.transform(object, 0, 0, 0, 1, -1, 0)
        # shift rotated object to same position as rotrect
        obox = getminbox(object)
        object = g.transform(object, newleft - obox.left, newtop - obox.top)
        oldcells = underneath(object)
        g.putcells(object)
        g.update()
        return

    if event == "key h none":
        showhelp2()
        return

    g.doevent(event)
Example #8
0
def main():
    apgcode = canonise()
    if not apgcode:
        g.warn(
            'Failed to detect periodic behaviour after {} generations.'.format(
                MAXPERIOD))

    # 2G collisions
    if apgcode in twoGcols:
        cols = twoGcols[apgcode]
    else:
        cols = []
    # 3G and 4G collisions
    for cFile in compFiles:
        with open(cFile) as cF:
            found_code = False
            for l in cF:
                line = l.strip()
                if not found_code:
                    if line == apgcode:
                        found_code = True
                    continue
                elif '>' in line:
                    in_code, gstr, _ = line.split(">")
                    if in_code:
                        g.warn(
                            'Non-empty starting target in glider collision - Not implemented'
                        )
                    else:
                        cols.append(gstr)
                else:
                    break

    Ncols = len(cols)
    if Ncols:
        try:
            cols = [reconstruct(col) for col in cols]
        except Exception:
            g.note(str(cols))
        g.new("solutions")
        g.show("{} collisions found".format(Ncols))
        g.setname(apgcode)
        if Ncols <= 20:
            N = 5
        else:
            N = math.ceil(math.sqrt(Ncols)) + 1
        offset = 100
        for i, col in enumerate(cols):
            g.putcells(col, int((i % N) * offset), int((i // N) * offset))
        g.fit()
    else:
        g.note(
            "No glider collisions found for constellation {}. Better luck next time"
            .format(apgcode))
Example #9
0
def firstdiffs(values):
    if len(values) < 1:
        g.warn("No polynomial entered, apparently.")
        g.exit()
        return  # Just for good measure.
    if len(values) == 1:
        return [values[0]]
    if len(values) > 1:
        diffs = []
        for n in xrange(len(values) - 1):
            diffs.append(values[n + 1] - values[n])
        return firstdiffs(diffs) + [values[0]]
Example #10
0
def firstvalues(terms):
    vals = []
    for x in xrange(len(terms)):
        sum = 0
        for exp, coef in enumerate(terms):
            sum += coef * x**exp
        if sum != int(sum):
            g.warn(
                "Polynomial must produce integer values when x is an integer.")
            g.exit()
            return
        vals.append(int(sum))
    return vals
def TriangularTransitionsToRuleTree_CheckerboardMethod(neighborhood, n_states,
                                                       transitions, rule_name):

    # Background state 0 has no checkerboard, we infer it from its neighboring cells.
    def encode_lower(s):
        return s

    def encode_upper(s):
        ### AKT: this code causes syntax error in Python 2.3:
        ### return [0 if se==0 else n_states+se-1 for se in s]
        temp = []
        for se in s:
            if se == 0:
                temp.append(0)
            else:
                temp.append(n_states + se - 1)
        return temp

    total_states = n_states * 2 - 1
    if total_states > 256:
        golly.warn("Number of states exceeds Golly's limit of 256!")
        golly.exit()

    tree = RuleTree(total_states, 4)
    for t in transitions:
        # as lower
        tree.add_rule(
            [
                encode_lower(t[0]),  # C
                encode_upper(t[2]),  # S
                encode_upper(t[1]),  # E
                encode_upper(t[3]),  # W
                range(total_states)
            ],  # N
            encode_lower(t[4])[0])  # C'
        # as upper
        tree.add_rule(
            [
                encode_upper(t[0]),  # C
                range(total_states),  # S
                encode_lower(t[3]),  # E
                encode_lower(t[1]),  # W
                encode_lower(t[2])
            ],  # N
            encode_upper(t[4])[0])  # C'

    # output the rule tree
    golly.show("Compressing rule tree and saving to file...")
    tree.write(golly.getdir('rules') + rule_name + '.tree')
def parse_hex(hexstr):
    # parse a string like "FF00EE" or "FFFF0000EEEE"
    R, G, B = (0, 0, 0)
    if len(hexstr) == 6:
        R = int(hexstr[0:2], 16)
        G = int(hexstr[2:4], 16)
        B = int(hexstr[4:6], 16)
    elif len(hexstr) == 12:
        # only use upper 2 hex digits
        R = int(hexstr[0:2], 16)
        G = int(hexstr[4:6], 16)
        B = int(hexstr[8:10], 16)
    else:
        g.warn("Unexpected hex string: " + hexstr)
    return (R, G, B)
Example #13
0
def parse_hex(hexstr):
    # parse a string like "FF00EE" or "FFFF0000EEEE"
    R, G, B = (0, 0, 0)
    if len(hexstr) == 6:
        R = int(hexstr[0:2],16)
        G = int(hexstr[2:4],16)
        B = int(hexstr[4:6],16)
    elif len(hexstr) == 12:
        # only use upper 2 hex digits
        R = int(hexstr[0:2],16)
        G = int(hexstr[4:6],16)
        B = int(hexstr[8:10],16)
    else:
        g.warn("Unexpected hex string: " + hexstr)
    return (R,G,B)
def TriangularTransitionsToRuleTree_CheckerboardMethod(neighborhood,n_states,transitions,rule_name):

    # Background state 0 has no checkerboard, we infer it from its neighboring cells.
    def encode_lower(s):
        return s
    def encode_upper(s):
        ### AKT: this code causes syntax error in Python 2.3:
        ### return [0 if se==0 else n_states+se-1 for se in s]
        temp = []
        for se in s:
            if se==0:
                temp.append(0)
            else:
                temp.append(n_states+se-1)
        return temp

    total_states = n_states*2 - 1
    if total_states>256:
        golly.warn("Number of states exceeds Golly's limit of 256!")
        golly.exit()
    
    tree = RuleTree(total_states,4)
    for t in transitions:
        # as lower
        tree.add_rule([encode_lower(t[0]),   # C
                       encode_upper(t[2]),   # S
                       encode_upper(t[1]),   # E
                       encode_upper(t[3]),   # W
                       range(total_states)],   # N
                      encode_lower(t[4])[0]) # C'
        # as upper
        tree.add_rule([encode_upper(t[0]),   # C
                       range(total_states),    # S
                       encode_lower(t[3]),   # E
                       encode_lower(t[1]),   # W
                       encode_lower(t[2])],  # N
                      encode_upper(t[4])[0]) # C'
        
    # output the rule tree
    golly.show("Compressing rule tree and saving to file...")
    tree.write(golly.getdir('rules') + rule_name + '.tree')
Example #15
0
    def saverule(self, name, comments, table, colours, icons):

        ruledir = g.getdir("rules")
        filename = ruledir + name + ".rule"

        results = "@RULE " + name + "\n\n"
        results += "*** File autogenerated by saverule. ***\n\n"
        results += comments
        results += "\n\n@TABLE\n\n"
        results += table
        results += "\n\n@COLORS\n\n"
        results += colours
        results += "\n\n@ICONS\n\n"
        results += icons

        # Change in behavior:  always create rule table,
        #   silently overwriting any file with the same name
        try:
            f = open(filename, 'w')
            f.write(results)
            f.close()
        except:
            g.warn("Unable to create rule table:\n" + filename)
Example #16
0
def run_pattern_in_golly(pattern, comments, extended):
    if extended:
        try:
            extended = int(pattern[pattern.index('%')+1:])
        except ValueError: #sometimes there's a % sign in the comments
            extended = False
    pattern_rle = pattern
    pattern = g.parse(pattern)
    if len(pattern) % 2 == 1: #multistate rule for some reason
        g.warn(pattern_rle)
        g.warn(str(pattern))
    initial_pattern = pattern.copy()
    xs = pattern[::2]
    ys = pattern[1::2]
    min_x = 0
    max_x = max(xs)
    min_y = 0
    max_y = max(ys)
    min_min_x = min_x #these four are the permanent minima and maxima, used for determining maximum pattern size
    max_max_x = max_x
    min_min_y = min_y
    max_max_y = max_y
    for period in range(1, 1000): #maximum oscillator period
        if period == 999 and extended:
            pattern = g.evolve(pattern, extended - 999)
        pattern = g.evolve(pattern,1)
        if not pattern:
            g.warn('Not an oscillator, dies out completely: %s' % initial_pattern)
            return
        xs = pattern[::2]
        ys = pattern[1::2]
        min_min_x = min(min_min_x, min(xs)) #sets new absolute minima and maxima
        max_max_x = max(max_max_x, max(xs))
        min_min_y = min(min_min_y, min(ys))
        max_max_y = max(max_max_y, max(ys))
        if pattern == initial_pattern:
            if extended:
                return (comments + convert_grid_to_rle(pattern), extended, max_max_x-min_min_x+1, max_max_y-min_min_y+1, -min_min_x, -min_min_y)
            else:
                return (comments + convert_grid_to_rle(pattern), period, max_max_x-min_min_x+1, max_max_y-min_min_y+1, -min_min_x, -min_min_y)
            #0: RLE. 1: period. 2, 3: maximum bounding box for x and y. 4, 5: Greatest negative for calculating offset.
        #if extended == 'file': #one at a time
        #    return pattern
    g.warn('Not an oscillator, maximum generations reached: %s' % initial_pattern)
    return
l_binstring = []


def rev(s):
    return "".join(reversed(s))


d_inst2lineno = {}
d_lineno2inst = {}

for line in parsed:
    lineno, opcode, (d_1, n_1), (d_2, n_2), (d_3, n_3) = line

    if int(n_1) >= (1 << 8):
        g.warn(
            "Error: The first operand {} at line {} from instruction {} has a bitlength larger than 8. The first operand must have a bitlength less than 8 bits."
            .format(n_1, lineno, line))
        g.exit("Bitlength error.")

    d_1, d_2, d_3 = map(
        lambda n: int2binstr((n + (1 << 16)) % (1 << 16), length=2),
        [d_1, d_2, d_3])
    # n_1, n_2 = map(lambda n: int2binstr((n + (1 << 16)) % (1 << 16), length=16), [n_1, n_2])
    n_1 = int2binstr((n_1 + (1 << 16)) % (1 << 16), length=8)
    n_2 = int2binstr((n_2 + (1 << 16)) % (1 << 16), length=16)
    n_3 = int2binstr((n_3 + (1 << 16)) % (1 << 16), length=8)
    bins = [opcode, n_1, d_1, n_2, d_2, n_3, d_3]
    linestr = "".join([rev(s) for s in bins])
    rom_width = 3 + 8 + 2 + 16 + 2 + 8 + 2
    # rom_width = 3+18+18+8+2
Example #18
0
n_states = len(action_table)
n_colors = len(action_table[0])
# (N.B. The terminology 'state' here refers to the internal state of the finite
#       state machine that each Turmite is using, not the contents of each Golly
#       cell. We use the term 'color' to denote the symbol on the 2D 'tape'. The
#       actual 'Golly state' in this emulation of Turmites is given by the
#       "encoding" section below.)
n_dirs = 3

# TODO: check table is full and valid

total_states = n_colors+n_colors*n_states*3

# problem if we try to export more than 255 states
if total_states > 128: # max allowed using checkerboard emulation (see EmulateTriangular)
    golly.warn("Number of states required exceeds Golly's limit of 255.")
    golly.exit()

# encoding:
# (0-n_colors: empty square)
def encode(c,s,d):
    # turmite on color c in state s facing away from direction d
    return n_colors + 3*(n_states*c+s) + d

# http://rightfootin.blogspot.com/2006/09/more-on-python-flatten.html
def flatten(l, ltypes=(list, tuple)):
    ltype = type(l)
    l = list(l)
    i = 0
    while i < len(l):
        while isinstance(l[i], ltypes):
Example #19
0
def ConvertTreeToRule(rule_name, total_states, icon_pixels):
    '''
    Convert rule_name.tree to rule_name.rule and delete the .tree file.
    
    If rule_name.colors exists then use it to create an @COLORS section
    and delete the .colors file.
    
    If icon_pixels is supplied then add an @ICONS section.
    Format of icon_pixels (in this example there are 4 icons at each size):
    
    ---------------------------------------------------------
    |             |             |             |             |
    |             |             |             |             |
    |    31x31    |    31x31    |    31x31    |    31x31    |
    |             |             |             |             |
    |             |             |             |             |
    ---------------------------------------------------------
    |       |.....|       |.....|       |.....|       |.....|
    | 15x15 |.....| 15x15 |.....| 15x15 |.....| 15x15 |.....|
    |       |.....|       |.....|       |.....|       |.....|
    ---------------------------------------------------------
    |7x7|.........|7x7|.........|7x7|.........|7x7|.........|
    ---------------------------------------------------------
    
    The top layer of 31x31 icons is optional -- if not supplied (ie. the
    height is 22) then there are no gaps between the 15x15 icons.
    '''
    rulepath = golly.getdir('rules')+rule_name+'.rule'
    treepath = golly.getdir('rules')+rule_name+'.tree'
    colorspath = golly.getdir('rules')+rule_name+'.colors'

    # get contents of .tree file
    try:
        treefile = open(treepath,'r')
        treedata = treefile.read()
        treefile.close()
    except:
        golly.exit('Failed to open .tree file: '+treepath)
    
    # if the .rule file already exists then only replace the @TREE section
    # so we don't clobber any other info added by the user
    if os.path.isfile(rulepath):
        ReplaceTreeSection(rulepath, treedata)
        os.remove(treepath)
        if os.path.isfile(colorspath): os.remove(colorspath)
        return
    
    # create a new .rule file
    rulefile = open(rulepath,'w')
    rulefile.write('@RULE '+rule_name+'\n\n')
    rulefile.write('@TREE\n\n')
    
    # append contents of .tree file, then delete that file
    rulefile.write(treedata)
    os.remove(treepath)
    
    # if .colors file exists then append @COLORS section and delete file
    if os.path.isfile(colorspath):
        colorsfile = open(colorspath,'r')
        rulefile.write('\n@COLORS\n\n')
        for line in colorsfile:
            if line.startswith('color') or line.startswith('gradient'):
                # strip off everything before 1st digit
                line = line.lstrip('colorgadient= \t')
            rulefile.write(line)
        colorsfile.close()
        os.remove(colorspath)
    
    # if icon pixels are supplied then append @ICONS section
    if len(icon_pixels) > 0:
        wd = len(icon_pixels[0])
        ht = len(icon_pixels)
        iconsize = 15                   # size of icons in top row
        if ht > 22: iconsize = 31       # 31x31 icons are present
        numicons = wd / iconsize
        
        # get colors used in all icons (we assume each icon size uses the same set of colors)
        colors, multi_colored = GetColors(icon_pixels, wd, ht)
        if len(colors) > 256:
            golly.warn('Icons use more than 256 colors!')
            rulefile.flush()
            rulefile.close()
            return
        if multi_colored:
            # create @COLORS section using color info in icon_pixels (not grayscale)
            rulefile.write('\n@COLORS\n\n')
            if numicons >= total_states:
                # extra icon is present so use top right pixel to set the color of state 0
                R,G,B = icon_pixels[0][wd-1]
                rulefile.write('0 ' + str(R) + ' ' + str(G) + ' ' + str(B) + '\n')
                numicons -= 1
            # set colors for each live state to the average of the non-black pixels
            # in each icon on top row (note we've skipped the extra icon detected above)
            for i in xrange(numicons):
                nbcount = 0
                totalR = 0
                totalG = 0
                totalB = 0
                for row in xrange(iconsize):
                    for col in xrange(iconsize):
                        R,G,B = icon_pixels[row][col + i*iconsize]
                        if R > 0 or G > 0 or B > 0:
                            nbcount += 1
                            totalR += R
                            totalG += G
                            totalB += B
                if nbcount > 0:
                    rulefile.write(str(i+1) + ' ' + str(totalR / nbcount) + ' ' \
                                                  + str(totalG / nbcount) + ' ' \
                                                  + str(totalB / nbcount) + '\n')
                else:
                    # avoid div by zero
                    rulefile.write(str(i+1) + ' 0 0 0\n')
        
        # create @ICONS section using (r,g,b) triples in icon_pixels[row][col]
        rulefile.write('\n@ICONS\n')
        if ht > 22:
            # top row of icons is 31x31
            CreateXPMIcons(colors, icon_pixels, 31,  0, 31, numicons, rulefile)
            CreateXPMIcons(colors, icon_pixels, 15, 31, 31, numicons, rulefile)
            CreateXPMIcons(colors, icon_pixels,  7, 46, 31, numicons, rulefile)
        else:
            # top row of icons is 15x15
            CreateXPMIcons(colors, icon_pixels, 15,  0, 15, numicons, rulefile)
            CreateXPMIcons(colors, icon_pixels,  7, 15, 15, numicons, rulefile)
    
    rulefile.flush()
    rulefile.close()
Example #20
0
     movablepat+=basepat[i:i+2]+[1]
   elif cellcolor==4:
     output+=basepat[i:i+2]+[0]
   elif cellcolor==5:
     signal+=basepat[i:i+2]+[1]
   elif cellcolor==6:
     movablebb+=basepat[i:i+2]+[1]
   else:
     g.exit("Don't know that color: "+str(basepat[i+2]))
 errorstr = ""
 if len(fixedpat) == 0: errorstr += "fixed pattern (state 1, green) "
 if len(movablepat) == 0: errorstr += "movable pattern (state 3, white) "
 if len(output) == 0: errorstr += "output pattern (state 4, red) "
 if len(signal) == 0: errorstr += "signal pattern (state 5, yellow) "
 if errorstr != "":
   g.warn("Required cell states -- " +errorstr \
          + "-- not found in " + basegun + " template pattern:\n" + item)
 if len(fixedpat)%2 == 0: fixedpat+=[0]
 if len(movablepat)%2 == 0: movablepat+=[0]
 if len(fixedbb)%2 == 0 : fixedbb+=[0]
 if len(movablebb)%2 == 0 : movablebb+=[0]
 if len(output)%2 == 0: output+=[0]
 if len(signal)%2 == 0: signal+=[0]
 g.new(basegun)
 g.putcells(fixedpat)
 g.putcells(fixedbb)
 g.putcells(movablepat, iadjustment*dx, iadjustment*dy)
 g.putcells(movablebb, iadjustment*dx, iadjustment*dy)
 done = 0
 g.setrule("Life")
 r=g.getrect()
 while done == 0:
Example #21
0
            off_cells.append((x - ox - offset, y - oy))

results_layer = g.addlayer()
g.setname("Results")
g.setrule("Life")
g.setalgo("QuickLife")
work_layer = g.addlayer()
g.setname("Work area")

g.putcells(start_cells)
g.putcells(example_cells)
g.run(delay)

if not all(g.getcell(x, y)
           for x, y in on_cells) or any(g.getcell(x, y) for x, y in off_cells):
    g.warn("Warning: the example pattern is not a solution")

results = 0


def apply_sym(pat, symm):
    yield pat
    if "x" in symm: yield g.transform(pat, 0, 0, -1, 0, 0, 1)
    if "d" in symm: yield g.transform(pat, 0, 0, 0, 1, 1, 0)
    if "x" in symm and "d" in symm:
        yield g.transform(pat, 0, 0, 1, -1, 0)


def testkey():
    if results and g.getevent().startswith("key x"):
        g.setlayer(results_layer)
Example #22
0
turmite_spec = "{{"+','.join(['{'+str((i+1)%n_colors)+','+d[spec[i]]+',0}' for i in range(n_colors)])+"}}"
rule_name = prefix+'_'+spec
action_table = eval(turmite_spec.replace('}',']').replace('{','['))
n_states = len(action_table)
n_dirs=4
# (N.B. The terminology 'state' here refers to the internal state of the finite
#       state machine that each Turmite is using, not the contents of each Golly
#       cell. We use the term 'color' to denote the symbol on the 2D 'tape'. The
#       actual 'Golly state' in this emulation of Turmites is given by the 
#       "encoding" section below.)

total_states = n_colors+n_colors*n_states*n_dirs

# problem if we try to export more than 255 states
if total_states>255:
    golly.warn("Number of states required exceeds Golly's limit of 255\n\nMaximum 51 turns allowed.")
    golly.exit()

# what direction would a turmite have been facing to end up here from direction
# d if it turned t: would_have_been_facing[t][d]
would_have_been_facing={ 
1:[2,3,0,1], # no turn
2:[1,2,3,0], # right
4:[0,1,2,3], # u-turn
8:[3,0,1,2], # left
}

remap = [2,1,3,0] # N,E,S,W -> S,E,W,N

not_arriving_from_here = [range(n_colors) for i in range(n_dirs)] # (we're going to modify them)
for color in range(n_colors):
Example #23
0
import golly as g
base64dict = {}
for index, char in enumerate(
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"):
    base64dict[char] = "".join(
        ["1" if index & 2**(5 - j) else "0" for j in range(6)])
mapstr = g.getstring(
    "Enter MAP string to convert to a rule: ",
    "ARYXfhZofugWaH7oaIDogBZofuhogOiAaIDogIAAgAAWaH7oaIDogGiA6ICAAIAAaIDogIAAgACAAIAAAAAAAA"
)
if mapstr[:3] == "MAP": mapstr = mapstr[3:]
if len(mapstr) != 86:
    g.warn("Map string is the wrong length -- should be 86 characters.")
    g.exit()
s = "".join([base64dict[char] for char in mapstr])
ruletablestr="@RULE MAPblahblahblah\nRule table for nontotalistic rule MAPblahblahblah" \
            +"\n\n@TABLE\nn_states:2\nneighborhood:Moore\nsymmetries:none\n\n"
for i in range(512):
    binary = "{0:09b}".format(i)
    for j in binary[4] + binary[:4] + binary[5:]:
        ruletablestr += j + ","
    ruletablestr += s[i] + "\n"
g.setclipstr(ruletablestr.replace("blahblahblah", mapstr))
Example #24
0
        #    print('No "x =": ' + i)
        patterns.append(i)
        show_message("Pass 1 of 3: processing pattern #" + str(len(patterns)),0.001)
    show_message('Total number of patterns: %s' % len(patterns),0.5)

patterns = []
open_file2('oscillators.txt')
data = [(0,1234567,0,0,0,0)] #this period 1234567 marks the end of the file
count = 0
for i in patterns:
    count += 1
    show_message('Pass 2 of 3: %s of %s done, %s seconds ' % (count-1, len(patterns), int(time.time() - start_time)),0)
    try:
        data.append(run_pattern_in_golly(i[i.index('= B3/S23')+9:], i[:i.index('x =')], '%' in i)) #max period 1000 without %, 100000 with %
    except ValueError:
        g.warn('"= B3/S23" not found: ' + i)
show_message('All done, ' + str(int(time.time() - start_time)) + ' seconds',0.5)

while None in data: #non-oscillators:
    data.remove(None)
#for i in num_dict.values(): #digits from other files
#    if eval(i) in data:
#        data.remove(eval(i))
num_patterns = len(data)

data.sort(key=lambda a:(a[1],a[3])) #first by period, then height

num_periods = 0
comments = ''
lvcomments = '#C [[ COLOR LABEL Yellow LABELSIZE 30 LABELALPHA .75 LABELVIEWDIST 20 LABELZOOMRANGE 1 64 LABELANGLE 330 ]]\n'
grid = {}
Example #25
0
    "Moore":ConvertRuleTableTransitionsToRuleTree,
    "triangularVonNeumann":EmulateTriangular,
    "triangularMoore":EmulateTriangular,
    "Margolus":EmulateMargolus,
    "square4_figure8v":EmulateMargolus,
    "square4_figure8h":EmulateMargolus,
    "square4_cyclic":EmulateMargolus,
    "oneDimensional":EmulateOneDimensional,
    "hexagonal":EmulateHexagonal,
}

golly.show("Reading from rule table file...")
n_states, neighborhood, transitions = ReadRuleTable(filename)

if not neighborhood in Converters:
    golly.warn("Unsupported neighborhood: "+neighborhood)
    golly.show('')
    golly.exit()

# all converters now create a .rule file
golly.show("Building rule...")
rule_name = Converters[neighborhood]( neighborhood,
                                      n_states,
                                      transitions,
                                      filename )

golly.new(rule_name+'-demo.rle')
golly.setalgo('RuleLoader')
golly.setrule(rule_name)
golly.show('Created '+rule_name+'.rule and selected that rule.')
Example #26
0
    mode = lower(xym[2])
    if mode=="c": mode="copy"
    if mode=="o": mode="or"
    if mode=="x": mode="xor"
    if not (mode == "copy" or mode == "or" or mode == "xor"):
        g.exit("Unknown mode: " + xym[2] + " (must be copy/or/xor)")
else:
    mode = "or"

# given parameters are valid so save them for next run
try:
    f = open(INIFileName, 'w')
    f.write(answer)
    f.close()
except:
    g.warn("Unable to save given parameters in file:\n" + INIFileName)

# abort shift if the new selection would be outside a bounded grid
if g.getwidth() > 0:
    gridl = -int(g.getwidth()/2)
    gridr = gridl + g.getwidth() - 1
    newl = selrect[0] + x
    newr = newl + selrect[2] - 1
    if newl < gridl or newr > gridr:
        g.exit("New selection would be outside grid.")
if g.getheight() > 0:
    gridt = -int(g.getheight()/2)
    gridb = gridt + g.getheight() - 1
    newt = selrect[1] + y
    newb = newt + selrect[3] - 1
    if newt < gridt or newb > gridb:
def ReadRuleTable(filename):
    '''
    Return n_states, neighborhood, transitions
    e.g. 2, "vonNeumann", [[0],[0,1],[0],[0],[1],[1]]
    Transitions are expanded for symmetries and bound variables.
    '''
    f=open(filename,'r')
    vars={}
    symmetry_string = ''
    symmetry = []
    n_states = 0
    neighborhood = ''
    transitions = []
    numParams = 0
    for line in f:
        if line[0]=='#' or line.strip()=='':
            pass
        elif line[0:9]=='n_states:':
            n_states = int(line[9:])
            if n_states<0 or n_states>256:
                golly.warn('n_states out of range: '+n_states)
                golly.exit()
        elif line[0:13]=='neighborhood:':
            neighborhood = line[13:].strip()
            if not neighborhood in SupportedSymmetries:
                golly.warn('Unknown neighborhood: '+neighborhood)
                golly.exit()
            numParams = len(SupportedSymmetries[neighborhood].items()[0][1][0])
        elif line[0:11]=='symmetries:':
            symmetry_string = line[11:].strip()
            if not symmetry_string in SupportedSymmetries[neighborhood]:
                golly.warn('Unknown symmetry: '+symmetry_string)
                golly.exit()
            symmetry = SupportedSymmetries[neighborhood][symmetry_string]
        elif line[0:4]=='var ':
            line = line[4:] # strip var keyword
            if '#' in line: line = line[:line.find('#')] # strip any trailing comment
            # read each variable into a dictionary mapping string to list of ints
            entries = line.replace('=',' ').replace('{',' ').replace(',',' ').\
                replace(':',' ').replace('}',' ').replace('\n','').split()
            vars[entries[0]] = []
            for e in entries[1:]:
                if e in vars: vars[entries[0]] += vars[e] # vars allowed in later vars
                else: vars[entries[0]].append(int(e))
        else:
            # assume line is a transition
            if '#' in line: line = line[:line.find('#')] # strip any trailing comment
            if ',' in line:
                entries = line.replace('\n','').replace(',',' ').replace(':',' ').split()
            else:
                entries = list(line.strip()) # special no-comma format
            if not len(entries)==numParams:
                golly.warn('Wrong number of entries on line: '+line+' (expected '+str(numParams)+')')
                golly.exit()
            # retrieve the variables that repeat within the transition, these are 'bound'
            bound_vars = [ e for e in set(entries) if entries.count(e)>1 and e in vars ]
            # iterate through all the possible values of each bound variable
            var_val_indices = dict(zip(bound_vars,[0]*len(bound_vars)))
            while True:
                ### AKT: this code causes syntax error in Python 2.3:
                ### transition = [ [vars[e][var_val_indices[e]]] if e in bound_vars \
                ###                else vars[e] if e in vars \
                ###                else [int(e)] \
                ###                for e in entries ]
                transition = []
                for e in entries:
                    if e in bound_vars:
                        transition.append([vars[e][var_val_indices[e]]])
                    elif e in vars:
                        transition.append(vars[e])
                    else:
                        transition.append([int(e)])
                if symmetry_string=='permute' and neighborhood in PermuteLater:
                    # permute all but C,C' (first and last entries)
                    for permuted_section in permu2(transition[1:-1]):
                        permuted_transition = [transition[0]]+permuted_section+[transition[-1]]
                        if not permuted_transition in transitions:
                            transitions.append(permuted_transition)
                else:
                    # expand for symmetry using the explicit list
                    for s in symmetry:
                        tran = [transition[i] for i in s]
                        if not tran in transitions: 
                            transitions.append(tran)
                # increment the variable values (or break out if done)
                var_val_to_change = 0
                while var_val_to_change<len(bound_vars):
                    var_label = bound_vars[var_val_to_change]
                    if var_val_indices[var_label]<len(vars[var_label])-1:
                        var_val_indices[var_label] += 1
                        break
                    else:
                        var_val_indices[var_label] = 0
                        var_val_to_change += 1
                if var_val_to_change >= len(bound_vars):
                    break
    f.close()
    return n_states, neighborhood, transitions
Example #28
0
    "Moore":ConvertRuleTableTransitionsToRuleTree,
    "triangularVonNeumann":EmulateTriangular,
    "triangularMoore":EmulateTriangular,
    "Margolus":EmulateMargolus,
    "square4_figure8v":EmulateMargolus,
    "square4_figure8h":EmulateMargolus,
    "square4_cyclic":EmulateMargolus,
    "oneDimensional":EmulateOneDimensional,
    "hexagonal":EmulateHexagonal,
}

golly.show("Reading from rule table file...")
n_states, neighborhood, transitions = ReadRuleTable(filename)

if not neighborhood in Converters:
    golly.warn("Unsupported neighborhood: "+neighborhood)
    golly.show('')
    golly.exit()

# all converters now create a .rule file
golly.show("Building rule...")
rule_name = Converters[neighborhood]( neighborhood,
                                      n_states,
                                      transitions,
                                      filename )

golly.new(rule_name+'-demo.rle')
golly.setalgo('RuleLoader')
golly.setrule(rule_name)
golly.show('Created '+rule_name+'.rule and selected that rule.')
Example #29
0
    mode = lower(xym[2])
    if mode == "c": mode = "copy"
    if mode == "o": mode = "or"
    if mode == "x": mode = "xor"
    if not (mode == "copy" or mode == "or" or mode == "xor"):
        g.exit("Unknown mode: " + xym[2] + " (must be copy/or/xor)")
else:
    mode = "or"

# given parameters are valid so save them for next run
try:
    f = open(INIFileName, 'w')
    f.write(answer)
    f.close()
except:
    g.warn("Unable to save given parameters in file:\n" + INIFileName)

# abort shift if the new selection would be outside a bounded grid
if g.getwidth() > 0:
    gridl = -int(g.getwidth() / 2)
    gridr = gridl + g.getwidth() - 1
    newl = selrect[0] + x
    newr = newl + selrect[2] - 1
    if newl < gridl or newr > gridr:
        g.exit("New selection would be outside grid.")
if g.getheight() > 0:
    gridt = -int(g.getheight() / 2)
    gridb = gridt + g.getheight() - 1
    newt = selrect[1] + y
    newb = newt + selrect[3] - 1
    if newt < gridt or newb > gridb:
def EmulateTriangular(neighborhood,n_states,transitions_list,input_filename):
    '''Emulate a triangularVonNeumann or triangularMoore neighborhood rule table with a rule tree.'''

    input_rulename = os.path.splitext(os.path.split(input_filename)[1])[0]
    
    # read rule_name+'.colors' file if it exists
    force_background = False
    background_color = [0,0,0]
    cfn = os.path.split(input_filename)[0] + "/" + input_rulename + ".colors"
    try:
        cf = open(cfn,'r')
    except IOError:
        # use Golly's default random colours
        random_colors=[[0,0,0],[0,255,127],[127,0,255],[148,148,148],[128,255,0],[255,0,128],[0,128,255],[1,159,0],
            [159,0,1],[255,254,96],[0,1,159],[96,255,254],[254,96,255],[126,125,21],[21,126,125],[125,21,126],
            [255,116,116],[116,255,116],[116,116,255],[228,227,0],[28,255,27],[255,27,28],[0,228,227],
            [227,0,228],[27,28,255],[59,59,59],[234,195,176],[175,196,255],[171,194,68],[194,68,171],
            [68,171,194],[72,184,71],[184,71,72],[71,72,184],[169,255,188],[252,179,63],[63,252,179],
            [179,63,252],[80,9,0],[0,80,9],[9,0,80],[255,175,250],[199,134,213],[115,100,95],[188,163,0],
            [0,188,163],[163,0,188],[203,73,0],[0,203,73],[73,0,203],[94,189,0],[189,0,94]]
        colors = dict(zip(range(len(random_colors)),random_colors))
    else:
        # read from the .colors file
        colors = {0:[0,0,0]} # background is black
        for line in cf:
            if line[0:6]=='color ':
                entries = map(int,line[6:].replace('=',' ').replace('\n',' ').split())
                if len(entries)<4:
                    continue # too few entries, ignore
                if entries[0]==0:
                    force_background = True
                    background_color = [entries[1],entries[2],entries[3]]
                else:
                    colors.update({entries[0]:[entries[1],entries[2],entries[3]]})
        # (we don't support gradients in .colors)

    rule_name = input_rulename + '_emulated'
    # (we use a special suffix to avoid picking up any existing .colors or .icons)
    
    # make a rule tree and some icons
    if n_states <= 16:
        TriangularTransitionsToRuleTree_SplittingMethod(neighborhood,n_states,transitions_list,rule_name)
        MakeTriangularIcons_SplittingMethod(n_states,colors,force_background,rule_name)
        total_states = n_states * n_states
    elif neighborhood=='triangularVonNeumann' and n_states <= 128:
        TriangularTransitionsToRuleTree_CheckerboardMethod(neighborhood,n_states,transitions_list,rule_name)
        MakeTriangularIcons_CheckerboardMethod(n_states,colors,force_background,rule_name)
        total_states = n_states * 2 - 1
    else:
        golly.warn('Only support triangularMoore with 16 states or fewer, and triangularVonNeumann\n'+\
                   'with 128 states or fewer.')
        golly.exit()
    
    if n_states==2:    
        # the icons we wrote are monochrome, so we need a .colors file to avoid
        # them all having different colors or similar from Golly's preferences
        c = open(golly.getdir('rules')+rule_name+".colors",'w')
        if force_background:
            c.write('color = 0 '+' '.join(map(str,background_color))+'\n')
        for i in range(1,total_states):
            c.write('color = '+str(i)+' '+' '.join(map(str,colors[1]))+'\n')
        c.flush()
        c.close()

    return rule_name
Example #31
0
    + "where the percentage is an integer from 0 to 100\n"
    + "and the state values are integers from 1 to "
    + str(maxlive)
    + "\n"
    + "(maxstate is optional, default is minstate):",
    previousvals,
    "Randomly fill selection",
)

# save given values for next time this script is called
try:
    f = open(inifilename, "w")
    f.write(result)
    f.close()
except:
    g.warn("Unable to save given values in file:\n" + inifilename)

# extract and validate values
pmm = result.split()
if len(pmm) == 0:
    g.exit()
if len(pmm) == 1:
    g.exit("You must supply min and max states.")
if not validint(pmm[0]):
    g.exit("Bad percentage value: " + pmm[0])
if not validint(pmm[1]):
    g.exit("Bad minstate value: " + pmm[1])
perc = int(pmm[0])
minlive = int(pmm[1])
if perc < 0 or perc > 100:
    g.exit("Percentage must be from 0 to 100.")
Example #32
0
def floodfill():
    newstate = g.getoption("drawingstate")
    oldstate = newstate

    # wait for user to click a cell
    g.show("Click the region you wish to fill... (hit escape to abort)")
    while oldstate == newstate:
        event = g.getevent()
        if event.startswith("click"):
            # event is a string like "click 10 20 left none"
            evt, xstr, ystr, butt, mods = event.split()
            x = int(xstr)
            y = int(ystr)
            if x < minx or x > maxx or y < miny or y > maxy:
                # click is outside pattern's bounding box in unbounded universe
                g.warn("Click within the pattern's bounding box\n" +
                       "otherwise the fill will be unbounded.")
            else:
                # note that user might have changed drawing state
                newstate = g.getoption("drawingstate")
                oldstate = g.getcell(x, y)
                if oldstate == newstate:
                    g.warn("The clicked cell must have a different state\n" +
                           "to the current drawing state.")
        else:
            g.doevent(event)

    # tell Golly to handle all further keyboard/mouse events
    g.getevent(False)

    # do flood fill starting with clicked cell
    g.show("Filling clicked region... (hit escape to stop)")
    clist = [(x, y)]
    g.setcell(x, y, newstate)
    oldsecs = time()
    while len(clist) > 0:
        # remove cell from start of clist
        x, y = clist.pop(0)
        newsecs = time()
        if newsecs - oldsecs >= 0.5:  # show changed pattern every half second
            oldsecs = newsecs
            g.update()

        # check if any orthogonal neighboring cells are in oldstate
        if checkneighbor(x, y - 1, oldstate):
            g.setcell(x, y - 1, newstate)
            clist.append((x, y - 1))

        if checkneighbor(x, y + 1, oldstate):
            g.setcell(x, y + 1, newstate)
            clist.append((x, y + 1))

        if checkneighbor(x + 1, y, oldstate):
            g.setcell(x + 1, y, newstate)
            clist.append((x + 1, y))

        if checkneighbor(x - 1, y, oldstate):
            g.setcell(x - 1, y, newstate)
            clist.append((x - 1, y))

        # diagonal neighbors are more complicated because we don't
        # want to cross a diagonal line of live cells
        if checkneighbor(x + 1, y + 1, oldstate) and (g.getcell(
                x, y + 1) == 0 or g.getcell(x + 1, y) == 0):
            g.setcell(x + 1, y + 1, newstate)
            clist.append((x + 1, y + 1))

        if checkneighbor(x + 1, y - 1, oldstate) and (g.getcell(
                x, y - 1) == 0 or g.getcell(x + 1, y) == 0):
            g.setcell(x + 1, y - 1, newstate)
            clist.append((x + 1, y - 1))

        if checkneighbor(x - 1, y + 1, oldstate) and (g.getcell(
                x, y + 1) == 0 or g.getcell(x - 1, y) == 0):
            g.setcell(x - 1, y + 1, newstate)
            clist.append((x - 1, y + 1))

        if checkneighbor(x - 1, y - 1, oldstate) and (g.getcell(
                x, y - 1) == 0 or g.getcell(x - 1, y) == 0):
            g.setcell(x - 1, y - 1, newstate)
            clist.append((x - 1, y - 1))
def moveobject():
   global oldcells, object, object1
   
   # wait for 1st click in live cell
   while True:
      event = g.getevent()
      if event.startswith("click"):
         # event is a string like "click 10 20 left none"
         evt, xstr, ystr, butt, mods = event.split()
         result = findlivecell(int(xstr), int(ystr))
         if len(result) > 0:
            prevx = int(xstr)
            prevy = int(ystr)
            oldmouse = xstr + ' ' + ystr
            g.show("Extracting object...")
            x, y = result
            object = getobject(x, y)
            object1 = list(object)     # save in case user aborts script
            if mods == "alt":
               # don't delete object
               oldcells = list(object)
            break
         else:
            g.warn("Click on or near a live cell belonging to the desired object.")
      elif event == "key h none":
         showhelp1()
      else:
         g.doevent(event)
   
   # wait for 2nd click while moving object
   g.show("Move mouse and click again..." + helpmsg)
   gotclick = False
   while not gotclick:
      event = g.getevent()
      if event.startswith("click"):
         evt, x, y, butt, mods = event.split()
         mousepos = x+' '+y
         gotclick = True
      else:
         if len(event) > 0: lookforkeys(event)
         mousepos = g.getxy()
      if len(mousepos) > 0 and mousepos != oldmouse:
         # mouse has moved, so move object
         g.putcells(object, 0, 0, 1, 0, 0, 1, "xor")  # erase object
         if len(oldcells) > 0: g.putcells(oldcells)
         xstr, ystr = mousepos.split()
         x = int(xstr)
         y = int(ystr)

         if g.getwidth() > 0:
            # ensure object doesn't move beyond left/right edge of grid
            obox = getminbox( g.transform(object, x - prevx, y - prevy) )
            if obox.left < gridl:
               x += gridl - obox.left
            elif obox.right > gridr:
               x -= obox.right - gridr
         if g.getheight() > 0:
            # ensure object doesn't move beyond top/bottom edge of grid
            obox = getminbox( g.transform(object, x - prevx, y - prevy) )
            if obox.top < gridt:
               y += gridt - obox.top
            elif obox.bottom > gridb:
               y -= obox.bottom - gridb

         object = g.transform(object, x - prevx, y - prevy)
         oldcells = underneath(object)
         g.putcells(object)
         prevx = x
         prevy = y
         oldmouse = mousepos
         g.update()
Example #34
0
    # use name.tree to create name.rule (with no icons);
    # note that if name.rule already exists then we only replace the info in
    # the @TREE section to avoid clobbering any other info added by the user
    ConvertTreeToRule(name, n_states, [])
    
    golly.setalgo("RuleLoader")
    golly.setrule(name)
    golly.show("Created "+golly.getdir("rules")+name+".rule and switched to that rule.")

except:
    import sys
    import traceback
    exception, msg, tb = sys.exc_info()
    golly.warn(\
 '''To use this script, copy a Python format rule definition into the clipboard, e.g.:

 name = "ParityNWE"
 n_states = 5
 n_neighbors = 4
 # order for 4 neighbors is N, W, E, S, C
 def transition_function ( s ) :
       return ( s[0] + s[1] + s[2] ) % 5

 For more examples, see the script file (right-click on it).
 ____________________________________________________

 A problem was encountered with the supplied rule:

 '''+ '\n'.join(traceback.format_exception(exception, msg, tb)))
    golly.exit()
# (convert Mathematica code to Python and run eval)
action_table = eval(spec.replace('}',']').replace('{','['))
n_states = len(action_table)
n_colors = len(action_table[0])
# (N.B. The terminology 'state' here refers to the internal state of the finite
#       state machine that each Turmite is using, not the contents of each Golly
#       cell. We use the term 'color' to denote the symbol on the 2D 'tape'. The
#       actual 'Golly state' in this emulation of Turmites is given by the
#       "encoding" section below.)
n_dirs = 6

# TODO: check table is full and valid

total_states = n_colors + n_colors*n_states
if total_states > 256:
    golly.warn("Number of states required exceeds Golly's limit of 256.")
    golly.exit()

# encoding:
# (0-n_colors: empty square)
def encode(c,s):
    # turmite on color c in state s
    return n_colors + n_states*c + s

# http://rightfootin.blogspot.com/2006/09/more-on-python-flatten.html
def flatten(l, ltypes=(list, tuple)):
    ltype = type(l)
    l = list(l)
    i = 0
    while i < len(l):
        while isinstance(l[i], ltypes):
Example #36
0
n_states = len(action_table)
n_colors = len(action_table[0])
# (N.B. The terminology 'state' here refers to the internal state of the finite
#       state machine that each Turmite is using, not the contents of each Golly
#       cell. We use the term 'color' to denote the symbol on the 2D 'tape'. The
#       actual 'Golly state' in this emulation of Turmites is given by the
#       "encoding" section below.)
n_dirs = 4

# TODO: check table is full and valid

total_states = n_colors + n_colors * n_states * n_dirs

# problem if we try to export more than 255 states
if total_states > 255:
    golly.warn("Number of states required exceeds Golly's limit of 255.")
    golly.exit()


# encoding:
# (0-n_colors: empty square)
def encode(c, s, d):
    # turmite on color c in state s facing direction d
    return n_colors + n_dirs * (n_states * c + s) + d


# http://rightfootin.blogspot.com/2006/09/more-on-python-flatten.html
def flatten(l, ltypes=(list, tuple)):
    ltype = type(l)
    l = list(l)
    i = 0
Example #37
0
def moveobject():
    global oldcells, object, object1

    # wait for click in or near a live cell
    while True:
        event = g.getevent()
        if event.startswith("click"):
            # event is a string like "click 10 20 left none"
            evt, xstr, ystr, butt, mods = event.split()
            result = findlivecell(int(xstr), int(ystr))
            if len(result) > 0:
                prevx = int(xstr)
                prevy = int(ystr)
                oldmouse = xstr + ' ' + ystr
                g.show("Extracting object...")
                x, y = result
                object = getobject(x, y)
                object1 = list(object)     # save in case user aborts script
                if mods == "alt":
                    # don't delete object
                    oldcells = list(object)
                break
            else:
                g.warn("Click on or near a live cell belonging to the desired object.")
        elif event == "key h none":
            showhelp()
        else:
            g.doevent(event)

    # wait for mouse-up while moving object
    g.show("Move mouse and release button...")
    mousedown = True
    while mousedown:
        event = g.getevent()
        if event.startswith("mup"):
            mousedown = False
        elif len(event) > 0:
            lookforkeys(event)
        mousepos = g.getxy()
        if len(mousepos) > 0 and mousepos != oldmouse:
            # mouse has moved, so move object
            g.putcells(object, 0, 0, 1, 0, 0, 1, "xor")  # erase object
            if len(oldcells) > 0: g.putcells(oldcells)
            xstr, ystr = mousepos.split()
            x = int(xstr)
            y = int(ystr)

            if g.getwidth() > 0:
                # ensure object doesn't move beyond left/right edge of grid
                obox = getminbox( g.transform(object, x - prevx, y - prevy) )
                if obox.left < gridl:
                    x += gridl - obox.left
                elif obox.right > gridr:
                    x -= obox.right - gridr
            if g.getheight() > 0:
                # ensure object doesn't move beyond top/bottom edge of grid
                obox = getminbox( g.transform(object, x - prevx, y - prevy) )
                if obox.top < gridt:
                    y += gridt - obox.top
                elif obox.bottom > gridb:
                    y -= obox.bottom - gridb

            object = g.transform(object, x - prevx, y - prevy)
            oldcells = underneath(object)
            g.putcells(object)
            prevx = x
            prevy = y
            oldmouse = mousepos
            g.update()
Example #38
0
def getstring(prompt):
   # this routine is deprecated
   golly.warn("Change the script to use the getstring() command\n"+
              "from golly rather than from glife.")
   golly.exit("")
Example #39
0
def EmulateTriangular(neighborhood,n_states,transitions_list,input_filename):
    '''Emulate a triangularVonNeumann or triangularMoore neighborhood rule table with a rule tree.'''

    input_rulename = os.path.splitext(os.path.split(input_filename)[1])[0]

    # read rule_name+'.colors' file if it exists
    force_background = False
    background_color = [0,0,0]
    cfn = os.path.split(input_filename)[0] + "/" + input_rulename + ".colors"
    try:
        cf = open(cfn,'r')
    except IOError:
        # use Golly's default random colours
        random_colors=[[0,0,0],[0,255,127],[127,0,255],[148,148,148],[128,255,0],[255,0,128],[0,128,255],[1,159,0],
            [159,0,1],[255,254,96],[0,1,159],[96,255,254],[254,96,255],[126,125,21],[21,126,125],[125,21,126],
            [255,116,116],[116,255,116],[116,116,255],[228,227,0],[28,255,27],[255,27,28],[0,228,227],
            [227,0,228],[27,28,255],[59,59,59],[234,195,176],[175,196,255],[171,194,68],[194,68,171],
            [68,171,194],[72,184,71],[184,71,72],[71,72,184],[169,255,188],[252,179,63],[63,252,179],
            [179,63,252],[80,9,0],[0,80,9],[9,0,80],[255,175,250],[199,134,213],[115,100,95],[188,163,0],
            [0,188,163],[163,0,188],[203,73,0],[0,203,73],[73,0,203],[94,189,0],[189,0,94]]
        colors = dict(list(zip(list(range(len(random_colors))),random_colors)))
    else:
        # read from the .colors file
        colors = {0:[0,0,0]} # background is black
        for line in cf:
            if line[0:6]=='color ':
                entries = list(map(int,line[6:].replace('=',' ').replace('\n',' ').split()))
                if len(entries)<4:
                    continue # too few entries, ignore
                if entries[0]==0:
                    force_background = True
                    background_color = [entries[1],entries[2],entries[3]]
                else:
                    colors.update({entries[0]:[entries[1],entries[2],entries[3]]})
        # (we don't support gradients in .colors)

    rule_name = input_rulename + '_emulated'
    # (we use a special suffix to avoid picking up any existing .colors or .icons)

    # make a rule tree and some icons
    if n_states <= 16:
        TriangularTransitionsToRuleTree_SplittingMethod(neighborhood,n_states,transitions_list,rule_name)
        pixels = MakeTriangularIcons_SplittingMethod(n_states,colors,force_background,rule_name)
        total_states = n_states * n_states
    elif neighborhood=='triangularVonNeumann' and n_states <= 128:
        TriangularTransitionsToRuleTree_CheckerboardMethod(neighborhood,n_states,transitions_list,rule_name)
        pixels = MakeTriangularIcons_CheckerboardMethod(n_states,colors,force_background,rule_name)
        total_states = n_states * 2 - 1
    else:
        golly.warn('Only support triangularMoore with 16 states or fewer, and triangularVonNeumann\n'+\
                   'with 128 states or fewer.')
        golly.exit()

    if n_states==2:
        # the icons we wrote are monochrome, so we need a .colors file to avoid
        # them all having different colors or similar from Golly's preferences
        c = open(golly.getdir('rules')+rule_name+".colors",'w')
        if force_background:
            c.write('color = 0 '+' '.join(map(str,background_color))+'\n')
        for i in range(1,total_states):
            c.write('color = '+str(i)+' '+' '.join(map(str,colors[1]))+'\n')
        c.flush()
        c.close()
    
    # use rule_name.tree and rule_name.colors and icon info to create rule_name.rule
    ConvertTreeToRule(rule_name, total_states, pixels)
    return rule_name
Example #40
0
      cursorX += chars.find(data[i + 1]) + 4
      i += 1
    elif data[i] == 'z':
      cursorX = 0
      cursorY += 5
    else:
      col = chars.find(data[i])
      if col & 1 != 0: cellList += [cursorX, cursorY]
      if col & 2 != 0: cellList += [cursorX, cursorY + 1]
      if col & 4 != 0: cellList += [cursorX, cursorY + 2]
      if col & 8 != 0: cellList += [cursorX, cursorY + 3]
      if col & 16 != 0: cellList += [cursorX, cursorY + 4]
      cursorX += 1
    i += 1
  return cellList

filename = golly.opendialog('Choose an apgsearch log file')
dirname = golly.opendialog('Choose a folder for the output', 'dir')
with open(filename) as f:
  line = f.readline()
  while line:
    if not line.isspace() and line[0] != '@':
      code = line.split()[0]
      try:
        cellList = readApg(code)
      except Exception, args:
        golly.warn(args[0])
      else:
        golly.store(cellList, dirname + code + '.rle')
    line = f.readline()
Example #41
0
def create_average_colors(iconsection):
    global deadrgb
    colordata = "@COLORS\n\n"
    
    R, G, B = deadrgb
    colordata += "0 " + str(R) + " " + str(G) + " " + str(B) + "\n"

    width = 0
    height = 0
    num_colors = 0
    chars_per_pixel = 0
    xpmcount = 0
    colordict = {}
    row = 0
    state = 0
    nbcount = 0
    totalR = 0
    totalG = 0
    totalB = 0
    
    for line in iconsection.splitlines():
        if len(line) > 0 and line[0] == "\"":
            # extract the stuff inside double quotes
            line = line.lstrip("\"").rstrip("\"")
            xpmcount += 1
            if xpmcount == 1:
                # parse "width height num_colors chars_per_pixel"
                header = line.split()
                width = int(header[0])
                height = int(header[1])
                num_colors = int(header[2])
                chars_per_pixel = int(header[3])
            
            elif xpmcount > 1 and xpmcount <= 1 + num_colors:
                # parse color index line like "A c #FFFFFF" or "AB c #FF009900BB00"
                key, c, hexrgb = line.split()
                rgb = parse_hex(hexrgb.lstrip("#"))
                colordict[key] = rgb
            
            elif xpmcount <= 1 + num_colors + height:
                # parse pixel data in line like "......AAA......"
                for col in xrange(width):
                    offset = col*chars_per_pixel
                    key = line[offset : offset + chars_per_pixel]
                    if not key in colordict:
                        g.warn("Unexpected key in icon data: " + key)
                        return colordata
                    if key[0] != ".":
                        R, G, B = colordict[key]
                        nbcount += 1
                        totalR += R
                        totalG += G
                        totalB += B
                row += 1
                if row == width:
                    # we've done this icon
                    state += 1
                    if nbcount > 0:
                        colordata += str(state) + " " + str(totalR / nbcount) + " " \
                                                      + str(totalG / nbcount) + " " \
                                                      + str(totalB / nbcount) + "\n"
                    else:
                        # avoid div by zero
                        colordata += str(state) + " 0 0 0\n"
                    # reset counts for next icon
                    row = 0
                    nbcount = 0
                    totalR = 0
                    totalG = 0
                    totalB = 0
                if xpmcount == 1 + num_colors + height:
                    break
    
    colordata += "\n"
    return colordata
Example #42
0
    j = offset
    while ((backOff[(i + j) % period] >= 0) and (j < period)):
        j += 1
    if j == period:
        backOff[i] = period - i
        break
    backOff[i] = j
    i = (i + j) % period

rows = ["" for i in range(2 * period)]
k = 0
mp = 0
x = firstrow.x
y = firstrow.y
for i in range(period):
    rows[k] = getrow(x, y - mp, width)
    rows[k + period] = getrow(x, y + 1 - mp, width)
    k += backOff[k]
    if k >= period:
        k -= period
        mp += 1
    g.run(1)

try:
    f = open('initrows.txt', 'w')
    for i in range(2 * period):
        f.write(rows[i] + "\n")
    f.close()
except:
    g.warn("Unable to save file.")
Example #43
0
   f = open(savename, 'r')
   initdir = f.readline()
   f.close()
except:
   # this should only happen the very 1st time
   initdir = g.getdir("data")

# remove any existing extension from layer name and append .png
initfile = g.getname().split('.')[0] + ".png"

# prompt user for output file (image type depends on extension)
outfile = g.savedialog("Save image file",
                       "PNG (*.png)|*.png|BMP (*.bmp)|*.bmp|GIF (*.gif)|*.gif" +
                       "|TIFF (*.tif)|*.tif|JPEG (*.jpg)|*.jpg",
                       initdir, initfile)
if len(outfile) > 0:
   im.save(outfile)
   g.show("Image saved as " + outfile)
   
   # remember file's directory for next time
   try:
      f = open(savename, 'w')
      f.write(os.path.dirname(outfile))
      f.close()
   except:
      g.warn("Unable to save directory to file:\n" + savename)
   
   # on Mac OS X this opens the image file in Preview
   # but it causes an error on Windows
   # webbrowser.open("file://" + urllib.pathname2url(outfile))
Example #44
0
def floodfill():
    newstate = g.getoption("drawingstate")
    oldstate = newstate

    # wait for user to click a cell
    g.show("Click the region you wish to fill... (hit escape to abort)")
    while oldstate == newstate:
        event = g.getevent()
        if event.startswith("click"):
            # event is a string like "click 10 20 left none"
            evt, xstr, ystr, butt, mods = event.split()
            x = int(xstr)
            y = int(ystr)
            if x < minx or x > maxx or y < miny or y > maxy:
                # click is outside pattern's bounding box in unbounded universe
                g.warn("Click within the pattern's bounding box\n"+
                       "otherwise the fill will be unbounded.")
            else:
                # note that user might have changed drawing state
                newstate = g.getoption("drawingstate")
                oldstate = g.getcell(x, y)
                if oldstate == newstate:
                    g.warn("The clicked cell must have a different state\n"+
                           "to the current drawing state.")
        else:
            g.doevent(event)

    # tell Golly to handle all further keyboard/mouse events
    g.getevent(False)

    # do flood fill starting with clicked cell
    g.show("Filling clicked region... (hit escape to stop)")
    clist = [ (x,y) ]
    g.setcell(x, y, newstate)
    oldsecs = time()
    while len(clist) > 0:
        # remove cell from start of clist
        x, y = clist.pop(0)
        newsecs = time()
        if newsecs - oldsecs >= 0.5:     # show changed pattern every half second
            oldsecs = newsecs
            g.update()

        # check if any orthogonal neighboring cells are in oldstate
        if checkneighbor(  x, y-1, oldstate):
            g.setcell(     x, y-1, newstate)
            clist.append( (x, y-1) )
        
        if checkneighbor(  x, y+1, oldstate):
            g.setcell(     x, y+1, newstate)
            clist.append( (x, y+1) )
        
        if checkneighbor(  x+1, y, oldstate):
            g.setcell(     x+1, y, newstate)
            clist.append( (x+1, y) )
        
        if checkneighbor(  x-1, y, oldstate):
            g.setcell(     x-1, y, newstate)
            clist.append( (x-1, y) )

        # diagonal neighbors are more complicated because we don't
        # want to cross a diagonal line of live cells
        if checkneighbor(  x+1, y+1, oldstate) and (g.getcell(x, y+1) == 0 or
                                                   g.getcell(x+1, y) == 0):
            g.setcell(     x+1, y+1, newstate)
            clist.append( (x+1, y+1) )
        
        if checkneighbor(  x+1, y-1, oldstate) and (g.getcell(x, y-1) == 0 or
                                                   g.getcell(x+1, y) == 0):
            g.setcell(     x+1, y-1, newstate)
            clist.append( (x+1, y-1) )
        
        if checkneighbor(  x-1, y+1, oldstate) and (g.getcell(x, y+1) == 0 or
                                                   g.getcell(x-1, y) == 0):
            g.setcell(     x-1, y+1, newstate)
            clist.append( (x-1, y+1) )
        
        if checkneighbor(  x-1, y-1, oldstate) and (g.getcell(x, y-1) == 0 or
                                                   g.getcell(x-1, y) == 0):
            g.setcell(     x-1, y-1, newstate)
            clist.append( (x-1, y-1) )
def ConvertTreeToRule(rule_name, total_states, icon_pixels):
    '''
    Convert rule_name.tree to rule_name.rule and delete the .tree file.
    
    If rule_name.colors exists then use it to create an @COLORS section
    and delete the .colors file.
    
    If icon_pixels is supplied then add an @ICONS section.
    Format of icon_pixels (in this example there are 4 icons at each size):
    
    ---------------------------------------------------------
    |             |             |             |             |
    |             |             |             |             |
    |    31x31    |    31x31    |    31x31    |    31x31    |
    |             |             |             |             |
    |             |             |             |             |
    ---------------------------------------------------------
    |       |.....|       |.....|       |.....|       |.....|
    | 15x15 |.....| 15x15 |.....| 15x15 |.....| 15x15 |.....|
    |       |.....|       |.....|       |.....|       |.....|
    ---------------------------------------------------------
    |7x7|.........|7x7|.........|7x7|.........|7x7|.........|
    ---------------------------------------------------------
    
    The top layer of 31x31 icons is optional -- if not supplied (ie. the
    height is 22) then there are no gaps between the 15x15 icons.
    '''
    rulepath = golly.getdir('rules') + rule_name + '.rule'
    treepath = golly.getdir('rules') + rule_name + '.tree'
    colorspath = golly.getdir('rules') + rule_name + '.colors'

    # get contents of .tree file
    try:
        treefile = open(treepath, 'r')
        treedata = treefile.read()
        treefile.close()
    except:
        golly.exit('Failed to open .tree file: ' + treepath)

    # if the .rule file already exists then only replace the @TREE section
    # so we don't clobber any other info added by the user
    if os.path.isfile(rulepath):
        ReplaceTreeSection(rulepath, treedata)
        os.remove(treepath)
        if os.path.isfile(colorspath): os.remove(colorspath)
        return

    # create a new .rule file
    rulefile = open(rulepath, 'w')
    rulefile.write('@RULE ' + rule_name + '\n\n')
    rulefile.write('@TREE\n\n')

    # append contents of .tree file, then delete that file
    rulefile.write(treedata)
    os.remove(treepath)

    # if .colors file exists then append @COLORS section and delete file
    if os.path.isfile(colorspath):
        colorsfile = open(colorspath, 'r')
        rulefile.write('\n@COLORS\n\n')
        for line in colorsfile:
            if line.startswith('color') or line.startswith('gradient'):
                # strip off everything before 1st digit
                line = line.lstrip('colorgadient= \t')
            rulefile.write(line)
        colorsfile.close()
        os.remove(colorspath)

    # if icon pixels are supplied then append @ICONS section
    if len(icon_pixels) > 0:
        wd = len(icon_pixels[0])
        ht = len(icon_pixels)
        iconsize = 15  # size of icons in top row
        if ht > 22: iconsize = 31  # 31x31 icons are present
        numicons = wd / iconsize

        # get colors used in all icons (we assume each icon size uses the same set of colors)
        colors, multi_colored = GetColors(icon_pixels, wd, ht)
        if len(colors) > 256:
            golly.warn('Icons use more than 256 colors!')
            rulefile.flush()
            rulefile.close()
            return
        if multi_colored:
            # create @COLORS section using color info in icon_pixels (not grayscale)
            rulefile.write('\n@COLORS\n\n')
            if numicons >= total_states:
                # extra icon is present so use top right pixel to set the color of state 0
                R, G, B = icon_pixels[0][wd - 1]
                rulefile.write('0 ' + str(R) + ' ' + str(G) + ' ' + str(B) +
                               '\n')
                numicons -= 1
            # set colors for each live state to the average of the non-black pixels
            # in each icon on top row (note we've skipped the extra icon detected above)
            for i in xrange(numicons):
                nbcount = 0
                totalR = 0
                totalG = 0
                totalB = 0
                for row in xrange(iconsize):
                    for col in xrange(iconsize):
                        R, G, B = icon_pixels[row][col + i * iconsize]
                        if R > 0 or G > 0 or B > 0:
                            nbcount += 1
                            totalR += R
                            totalG += G
                            totalB += B
                if nbcount > 0:
                    rulefile.write(str(i+1) + ' ' + str(totalR / nbcount) + ' ' \
                                                  + str(totalG / nbcount) + ' ' \
                                                  + str(totalB / nbcount) + '\n')
                else:
                    # avoid div by zero
                    rulefile.write(str(i + 1) + ' 0 0 0\n')

        # create @ICONS section using (r,g,b) triples in icon_pixels[row][col]
        rulefile.write('\n@ICONS\n')
        if ht > 22:
            # top row of icons is 31x31
            CreateXPMIcons(colors, icon_pixels, 31, 0, 31, numicons, rulefile)
            CreateXPMIcons(colors, icon_pixels, 15, 31, 31, numicons, rulefile)
            CreateXPMIcons(colors, icon_pixels, 7, 46, 31, numicons, rulefile)
        else:
            # top row of icons is 15x15
            CreateXPMIcons(colors, icon_pixels, 15, 0, 15, numicons, rulefile)
            CreateXPMIcons(colors, icon_pixels, 7, 15, 15, numicons, rulefile)

    rulefile.flush()
    rulefile.close()
def create_average_colors(iconsection):
    global deadrgb
    colordata = "@COLORS\n\n"

    R, G, B = deadrgb
    colordata += "0 " + str(R) + " " + str(G) + " " + str(B) + "\n"

    width = 0
    height = 0
    num_colors = 0
    chars_per_pixel = 0
    xpmcount = 0
    colordict = {}
    row = 0
    state = 0
    nbcount = 0
    totalR = 0
    totalG = 0
    totalB = 0

    for line in iconsection.splitlines():
        if len(line) > 0 and line[0] == "\"":
            # extract the stuff inside double quotes
            line = line.lstrip("\"").rstrip("\"")
            xpmcount += 1
            if xpmcount == 1:
                # parse "width height num_colors chars_per_pixel"
                header = line.split()
                width = int(header[0])
                height = int(header[1])
                num_colors = int(header[2])
                chars_per_pixel = int(header[3])

            elif xpmcount > 1 and xpmcount <= 1 + num_colors:
                # parse color index line like "A c #FFFFFF" or "AB c #FF009900BB00"
                key, c, hexrgb = line.split()
                rgb = parse_hex(hexrgb.lstrip("#"))
                colordict[key] = rgb

            elif xpmcount <= 1 + num_colors + height:
                # parse pixel data in line like "......AAA......"
                for col in range(width):
                    offset = col * chars_per_pixel
                    key = line[offset:offset + chars_per_pixel]
                    if not key in colordict:
                        g.warn("Unexpected key in icon data: " + key)
                        return colordata
                    if key[0] != ".":
                        R, G, B = colordict[key]
                        nbcount += 1
                        totalR += R
                        totalG += G
                        totalB += B
                row += 1
                if row == width:
                    # we've done this icon
                    state += 1
                    if nbcount > 0:
                        colordata += str(state) + " " + str(totalR // nbcount) + " " \
                                                      + str(totalG // nbcount) + " " \
                                                      + str(totalB // nbcount) + "\n"
                    else:
                        # avoid div by zero
                        colordata += str(state) + " 0 0 0\n"
                    # reset counts for next icon
                    row = 0
                    nbcount = 0
                    totalR = 0
                    totalG = 0
                    totalB = 0
                if xpmcount == 1 + num_colors + height:
                    break

    colordata += "\n"
    return colordata
Example #47
0
    f = open(savename, 'r')
    initdir = f.readline()
    f.close()
except:
    # this should only happen the very 1st time
    initdir = g.getdir("data")

# remove any existing extension from layer name and append .png
initfile = g.getname().split('.')[0] + ".png"

# prompt user for output file (image type depends on extension)
outfile = g.savedialog(
    "Save image file",
    "PNG (*.png)|*.png|BMP (*.bmp)|*.bmp|GIF (*.gif)|*.gif" +
    "|TIFF (*.tif)|*.tif|JPEG (*.jpg)|*.jpg", initdir, initfile)
if len(outfile) > 0:
    im.save(outfile)
    g.show("Image saved as " + outfile)

    # remember file's directory for next time
    try:
        f = open(savename, 'w')
        f.write(os.path.dirname(outfile))
        f.close()
    except:
        g.warn("Unable to save directory to file:\n" + savename)

    # on Mac OS X this opens the image file in Preview
    # but it causes an error on Windows
    # webbrowser.open("file://" + urllib.pathname2url(outfile))
    # note that if name.rule already exists then we only replace the info in
    # the @TREE section to avoid clobbering any other info added by the user
    ConvertTreeToRule(name, n_states, [])

    golly.setalgo("RuleLoader")
    golly.setrule(name)
    golly.show("Created " + golly.getdir("rules") + name +
               ".rule and switched to that rule.")

except:
    import sys
    import traceback
    exception, msg, tb = sys.exc_info()
    golly.warn(\
 '''To use this script, copy a Python format rule definition into the clipboard, e.g.:

 name = "ParityNWE"
 n_states = 5
 n_neighbors = 4
 # order for 4 neighbors is N, W, E, S, C
 def transition_function ( s ) :
       return ( s[0] + s[1] + s[2] ) % 5

 For more examples, see the script file (right-click on it).
 ____________________________________________________

 A problem was encountered with the supplied rule:

 '''+ '\n'.join(traceback.format_exception(exception, msg, tb)))
    golly.exit()
Example #49
0
def ReadRuleTable(filename):
    '''
    Return n_states, neighborhood, transitions
    e.g. 2, "vonNeumann", [[0],[0,1],[0],[0],[1],[1]]
    Transitions are expanded for symmetries and bound variables.
    '''
    f = open(filename, 'r')
    vars = {}
    symmetry_string = ''
    symmetry = []
    n_states = 0
    neighborhood = ''
    transitions = []
    numParams = 0
    for line in f:
        if line[0] == '#' or line.strip() == '':
            pass
        elif line[0:9] == 'n_states:':
            n_states = int(line[9:])
            if n_states < 0 or n_states > 256:
                golly.warn('n_states out of range: ' + n_states)
                golly.exit()
        elif line[0:13] == 'neighborhood:':
            neighborhood = line[13:].strip()
            if not neighborhood in SupportedSymmetries:
                golly.warn('Unknown neighborhood: ' + neighborhood)
                golly.exit()
            numParams = len(SupportedSymmetries[neighborhood].items()[0][1][0])
        elif line[0:11] == 'symmetries:':
            symmetry_string = line[11:].strip()
            if not symmetry_string in SupportedSymmetries[neighborhood]:
                golly.warn('Unknown symmetry: ' + symmetry_string)
                golly.exit()
            symmetry = SupportedSymmetries[neighborhood][symmetry_string]
        elif line[0:4] == 'var ':
            line = line[4:]  # strip var keyword
            if '#' in line:
                line = line[:line.find('#')]  # strip any trailing comment
            # read each variable into a dictionary mapping string to list of ints
            entries = line.replace('=',' ').replace('{',' ').replace(',',' ').\
                replace(':',' ').replace('}',' ').replace('\n','').split()
            vars[entries[0]] = []
            for e in entries[1:]:
                if e in vars:
                    vars[entries[0]] += vars[e]  # vars allowed in later vars
                else:
                    vars[entries[0]].append(int(e))
        else:
            # assume line is a transition
            if '#' in line:
                line = line[:line.find('#')]  # strip any trailing comment
            if ',' in line:
                entries = line.replace('\n',
                                       '').replace(',',
                                                   ' ').replace(':',
                                                                ' ').split()
            else:
                entries = list(line.strip())  # special no-comma format
            if not len(entries) == numParams:
                golly.warn('Wrong number of entries on line: ' + line +
                           ' (expected ' + str(numParams) + ')')
                golly.exit()
            # retrieve the variables that repeat within the transition, these are 'bound'
            bound_vars = [
                e for e in set(entries) if entries.count(e) > 1 and e in vars
            ]
            # iterate through all the possible values of each bound variable
            var_val_indices = dict(zip(bound_vars, [0] * len(bound_vars)))
            while True:
                ### AKT: this code causes syntax error in Python 2.3:
                ### transition = [ [vars[e][var_val_indices[e]]] if e in bound_vars \
                ###                else vars[e] if e in vars \
                ###                else [int(e)] \
                ###                for e in entries ]
                transition = []
                for e in entries:
                    if e in bound_vars:
                        transition.append([vars[e][var_val_indices[e]]])
                    elif e in vars:
                        transition.append(vars[e])
                    else:
                        transition.append([int(e)])
                if symmetry_string == 'permute' and neighborhood in PermuteLater:
                    # permute all but C,C' (first and last entries)
                    for permuted_section in permu2(transition[1:-1]):
                        permuted_transition = [
                            transition[0]
                        ] + permuted_section + [transition[-1]]
                        if not permuted_transition in transitions:
                            transitions.append(permuted_transition)
                else:
                    # expand for symmetry using the explicit list
                    for s in symmetry:
                        tran = [transition[i] for i in s]
                        if not tran in transitions:
                            transitions.append(tran)
                # increment the variable values (or break out if done)
                var_val_to_change = 0
                while var_val_to_change < len(bound_vars):
                    var_label = bound_vars[var_val_to_change]
                    if var_val_indices[var_label] < len(vars[var_label]) - 1:
                        var_val_indices[var_label] += 1
                        break
                    else:
                        var_val_indices[var_label] = 0
                        var_val_to_change += 1
                if var_val_to_change >= len(bound_vars):
                    break
    f.close()
    return n_states, neighborhood, transitions
Example #50
0
rule_name = prefix + '_' + spec
action_table = eval(turmite_spec.replace('}', ']').replace('{', '['))
n_states = len(action_table)
n_dirs = 4
# (N.B. The terminology 'state' here refers to the internal state of the finite
#       state machine that each Turmite is using, not the contents of each Golly
#       cell. We use the term 'color' to denote the symbol on the 2D 'tape'. The
#       actual 'Golly state' in this emulation of Turmites is given by the
#       "encoding" section below.)

total_states = n_colors + n_colors * n_states * n_dirs

# problem if we try to export more than 255 states
if total_states > 255:
    golly.warn(
        "Number of states required exceeds Golly's limit of 255\n\nMaximum 51 turns allowed."
    )
    golly.exit()

# what direction would a turmite have been facing to end up here from direction
# d if it turned t: would_have_been_facing[t][d]
would_have_been_facing = {
    1: [2, 3, 0, 1],  # no turn
    2: [1, 2, 3, 0],  # right
    4: [0, 1, 2, 3],  # u-turn
    8: [3, 0, 1, 2],  # left
}

remap = [2, 1, 3, 0]  # N,E,S,W -> S,E,W,N

not_arriving_from_here = [range(n_colors) for i in range(n_dirs)