def HexagonalTransitionsToRuleTree(neighborhood,n_states,transitions,rule_name): '''Convert a set of hexagonal neighborhood transitions to a Moore neighborhood rule tree.''' tree = RuleTree(n_states,8) for t in transitions: # C,S,E,W,N,SE,(SW),(NE),NW tree.add_rule([t[0],t[4],t[2],t[5],t[1],t[3],range(n_states),range(n_states),t[6]],t[7][0]) tree.write( golly.getdir('rules')+rule_name+".tree" )
def EmulateOneDimensional(neighborhood,n_states,transitions,input_filename): '''Emulate a oneDimensional neighborhood rule table with a vonNeumann neighborhood rule tree.''' rule_name = os.path.splitext(os.path.split(input_filename)[1])[0] tree = RuleTree(n_states,4) for t in transitions: tree.add_rule([t[0],range(n_states),t[2],t[1],range(n_states)],t[3][0]) # C,S,E,W,N,C' tree.write( golly.getdir('rules')+rule_name+".tree" ) return rule_name
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 EmulateOneDimensional(neighborhood, n_states, transitions, input_filename): '''Emulate a oneDimensional neighborhood rule table with a vonNeumann neighborhood rule tree.''' rule_name = os.path.splitext(os.path.split(input_filename)[1])[0] tree = RuleTree(n_states, 4) for t in transitions: tree.add_rule( [t[0], range(n_states), t[2], t[1], range(n_states)], t[3][0]) # C,S,E,W,N,C' tree.write(golly.getdir('rules') + rule_name + ".tree") return rule_name
def HexagonalTransitionsToRuleTree(neighborhood, n_states, transitions, rule_name): '''Convert a set of hexagonal neighborhood transitions to a Moore neighborhood rule tree.''' tree = RuleTree(n_states, 8) for t in transitions: # C,S,E,W,N,SE,(SW),(NE),NW tree.add_rule([ t[0], t[4], t[2], t[5], t[1], t[3], range(n_states), range(n_states), t[6] ], t[7][0]) tree.write(golly.getdir('rules') + rule_name + ".tree")
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 EmulateMargolus(neighborhood,n_states,transitions,input_filename): '''Emulate a Margolus or square4_* neighborhood rule table with a Moore neighborhood rule tree.''' rule_name = os.path.splitext(os.path.split(input_filename)[1])[0]+'_emulated' total_states = 1+2*n_states tree = RuleTree(total_states,8) # now work through the transitions for tr in transitions: for iOutput,background_output in enumerate(BackgroundOutputs[neighborhood]): bg_inputs = BackgroundInputs[iOutput] iEntry = iOutput % 4 # (0=top-left, 1=top-right, 2=bottom-left, 3=bottom-right) rule_inputs = [] for i in range(9): if ForegroundInputs[iEntry][i]==-1: rule_inputs.append(encode( range(n_states), bg_inputs[i] ) + [0]) # wildcard else: rule_inputs.append(encode( tr[ForegroundInputs[iEntry][i]], bg_inputs[i] )) tree.add_rule( rule_inputs, encode( tr[iEntry+4], background_output )[0] ) # supply default behaviour: background still changes even if the state doesn't for iState in range(n_states): for iOutput,background_output in enumerate(BackgroundOutputs[neighborhood]): bg_inputs = BackgroundInputs[iOutput] tree.add_rule( [ encode( [iState], bg_inputs[0] ) ] + [ encode( range(n_states), bg_inputs[i] )+[0] for i in range(1,9) ], # wildcard encode( [iState], background_output )[0] ) # output the rule tree golly.show("Compressing rule tree and saving to file...") tree.write(golly.getdir('rules') + rule_name + '.tree') # also save a .colors file golly.show("Generating colors...") # read rule_name+'.colors' file if it exists cfn = os.path.split(input_filename)[0] + '/' + os.path.splitext(os.path.split(input_filename)[1])[0] + ".colors" try: cf = open(cfn,'r') except IOError: # use Golly's default random colours random_colors=[[90,90,90],[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 = {} for line in cf: if line[0:5]=='color': entries = map(int,line[5:].replace('=',' ').replace('\n',' ').split()) if len(entries)<4: continue # too few entries, ignore colors.update({entries[0]:[entries[1],entries[2],entries[3]]}) # (TODO: support gradients in .colors) # provide a deep blue background if none provided if not 0 in colors: colors.update({0:[0,0,120]}) c = open(golly.getdir('rules')+rule_name+".colors",'w') for col in colors.items()[:n_states]: c.write('color='+str(col[0]*2+1)+' '+' '.join(map(str,col[1]))+'\n') c.write('color='+str(col[0]*2+2)+' '+' '.join([ str(int(x*0.7)) for x in col[1] ])+'\n') # (darken slightly) c.flush() c.close() return rule_name
def EmulateMargolus(neighborhood, n_states, transitions, input_filename): '''Emulate a Margolus or square4_* neighborhood rule table with a Moore neighborhood rule tree.''' rule_name = os.path.splitext(os.path.split(input_filename)[1])[0] total_states = 1 + 2 * n_states tree = RuleTree(total_states, 8) # now work through the transitions for tr in transitions: for iOutput, background_output in enumerate( BackgroundOutputs[neighborhood]): bg_inputs = BackgroundInputs[iOutput] iEntry = iOutput % 4 # (0=top-left, 1=top-right, 2=bottom-left, 3=bottom-right) rule_inputs = [] for i in range(9): if ForegroundInputs[iEntry][i] == -1: rule_inputs.append( encode(range(n_states), bg_inputs[i]) + [0]) # wildcard else: rule_inputs.append( encode(tr[ForegroundInputs[iEntry][i]], bg_inputs[i])) tree.add_rule(rule_inputs, encode(tr[iEntry + 4], background_output)[0]) # supply default behaviour: background still changes even if the state doesn't for iState in range(n_states): for iOutput, background_output in enumerate( BackgroundOutputs[neighborhood]): bg_inputs = BackgroundInputs[iOutput] tree.add_rule( [encode([iState], bg_inputs[0])] + [ encode(range(n_states), bg_inputs[i]) + [0] for i in range(1, 9) ], # wildcard encode([iState], background_output)[0]) # output the rule tree golly.show("Compressing rule tree and saving to file...") tree.write(golly.getdir('rules') + rule_name + '.tree') # also save a .colors file golly.show("Generating colors...") # read rule_name+'.colors' file if it exists cfn = os.path.split(input_filename)[0] + '/' + os.path.splitext( os.path.split(input_filename)[1])[0] + ".colors" try: cf = open(cfn, 'r') except IOError: # use Golly's default random colours random_colors = [[90, 90, 90], [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 = {} for line in cf: if line[0:5] == 'color': entries = map( int, line[5:].replace('=', ' ').replace('\n', ' ').split()) if len(entries) < 4: continue # too few entries, ignore colors.update( {entries[0]: [entries[1], entries[2], entries[3]]}) # (TODO: support gradients in .colors) # provide a deep blue background if none provided if not 0 in colors: colors.update({0: [0, 0, 120]}) c = open(golly.getdir('rules') + rule_name + ".colors", 'w') for col in colors.items()[:n_states]: c.write('color=' + str(col[0] * 2 + 1) + ' ' + ' '.join(map(str, col[1])) + '\n') c.write('color=' + str(col[0] * 2 + 2) + ' ' + ' '.join([str(int(x * 0.7)) for x in col[1]]) + '\n') # (darken slightly) c.flush() c.close() # use rule_name.tree and rule_name.colors to create rule_name.rule (no icon info) ConvertTreeToRule(rule_name, total_states, []) return rule_name
] #golly.warn(str(not_arriving_from_here)) # What states leave output_color behind? leaving_color_behind = {} for output_color in range(n_colors): leaving_color_behind[output_color] = [output_color] # (no turmite present) for state in range(n_states): for color in range(n_colors): if action_table[state][color][0] == output_color: leaving_color_behind[output_color] += [ encode(color, state, d) for d in range(n_dirs) ] # any direction tree = RuleTree(total_states, 4) # A single turmite is entering this square: for s in range(n_states): # collect all the possibilities for a turmite to arrive in state s... inputs_sc = [] for state in range(n_states): for color in range(n_colors): if action_table[state][color][2] == s: inputs_sc += [(state, color)] # ...from direction dir for dir in range(n_dirs): inputs = [] for state, color in inputs_sc: turnset = action_table[state][color][1] # sum of all turns inputs += [
def TriangularTransitionsToRuleTree_SplittingMethod(neighborhood,n_states,transitions_list,rule_name): # each square cell is j*N+i where i is the lower triangle, j is the upper triangle # each i,j in (0,N] # (lower and upper are lists) def encode(lower,upper): return [ up*n_states+low for up in upper for low in lower ] # what neighbors of the lower triangle overlap neighbors of the upper triangle? lower2upper = { "triangularVonNeumann": [(0,1),(1,0)], "triangularMoore": [(0,1),(1,0),(2,12),(3,4),(4,3),(5,10),(6,11),(10,5),(11,6),(12,2)], } numNeighbors = { "triangularVonNeumann":4, "triangularMoore":8 } # convert transitions to list of list of sets for speed transitions = [[set(e) for e in t] for t in transitions_list] tree = RuleTree(n_states*n_states,numNeighbors[neighborhood]) # for each transition pair, see if we can apply them both at once to a square for i,t1 in enumerate(transitions): # as lower golly.show("Building rule tree... (pass 1 of 2: "+str(100*i//len(transitions))+"%)") for t2 in transitions: # as upper # we can only apply both rules at once if they overlap to some extent ### AKT: any() and isdisjoint() are not available in Python 2.3: ### if any( t1[j].isdisjoint(t2[k]) for j,k in lower2upper[neighborhood] ): ### continue any_disjoint = False for j,k in lower2upper[neighborhood]: if len(t1[j] & t2[k]) == 0: any_disjoint = True break if any_disjoint: continue # take the intersection of their inputs if neighborhood=="triangularVonNeumann": tree.add_rule( [ encode(t1[0]&t2[1],t1[1]&t2[0]), # C encode(list(range(n_states)),t1[2]), # S encode(t2[3],list(range(n_states))), # E encode(list(range(n_states)),t1[3]), # W encode(t2[2],list(range(n_states))) ], # N encode(t1[4],t2[4])[0] ) # C' elif neighborhood=="triangularMoore": tree.add_rule( [ encode(t1[0]&t2[1],t1[1]&t2[0]), # C encode(t1[7],t1[2]&t2[12]), # S encode(t1[4]&t2[3],t2[9]), # E encode(t1[9],t1[3]&t2[4]), # W encode(t1[12]&t2[2],t2[7]), # N encode(t1[6]&t2[11],t1[5]&t2[10]), # SE encode(list(range(n_states)),t1[8]), # SW encode(t2[8],list(range(n_states))), # NE encode(t1[10]&t2[5],t1[11]&t2[6]) ], # NW encode(t1[13],t2[13])[0] ) # C' # apply each transition to an individual triangle, leaving the other unchanged for i,t in enumerate(transitions): golly.show("Building rule tree... (pass 2 of 2: "+str(100*i//len(transitions))+"%)") for t_1 in t[1]: if neighborhood=="triangularVonNeumann": # as lower triangle: tree.add_rule( [ encode(t[0],[t_1]), # C encode(list(range(n_states)),t[2]), # S list(range(n_states*n_states)), # E encode(list(range(n_states)),t[3]), # W list(range(n_states*n_states)) ], # N encode(t[4],[t_1])[0] ) # C' # as upper triangle: tree.add_rule( [ encode([t_1],t[0]), # C list(range(n_states*n_states)), # S encode(t[3],list(range(n_states))), # E list(range(n_states*n_states)), # W encode(t[2],list(range(n_states))) ], # N encode([t_1],t[4])[0] ) # C' elif neighborhood=="triangularMoore": # as lower triangle: tree.add_rule( [encode(t[0],[t_1]), # C encode(t[7],t[2]), # S encode(t[4],list(range(n_states))), # E encode(t[9],t[3]), # W encode(t[12],list(range(n_states))), # N encode(t[6],t[5]), # SE encode(list(range(n_states)),t[8]), # SW list(range(n_states*n_states)), # NE encode(t[10],t[11]) ], # NW encode(t[13],[t_1])[0] ) # C' # as upper triangle: tree.add_rule( [encode([t_1],t[0]), encode(list(range(n_states)),t[12]), # S encode(t[3],t[9]), # E encode(list(range(n_states)),t[4]), # W encode(t[2],t[7]), # N encode(t[11],t[10]), # SE list(range(n_states*n_states)), # SW encode(t[8],list(range(n_states))), # NE encode(t[5],t[6]) ], # NW encode([t_1],t[13])[0] ) # C' # output the rule tree golly.show("Compressing rule tree and saving to file...") tree.write(golly.getdir('rules') + rule_name + '.tree')
for state in range(n_states): moveset = action_table[state][color][1] for iMove,move in enumerate(dirs): if not move in moveset: not_arriving_from_here[opposite_dirs[iMove]] += [encode(color,state)] # What states leave output_color behind? leaving_color_behind = {} for output_color in range(n_colors): leaving_color_behind[output_color] = [output_color] # (no turmite present) for state in range(n_states): for color in range(n_colors): if action_table[state][color][0]==output_color: leaving_color_behind[output_color] += [encode(color,state)] tree = RuleTree(total_states,4) # A single turmite is entering this square: for s in range(n_states): # collect all the possibilities for a turmite to arrive in state s... inputs_sc = [] for state in range(n_states): for color in range(n_colors): if action_table[state][color][2]==s: inputs_sc += [(state,color)] # ...from direction dir for dir in range(n_dirs): inputs = [] for state,color in inputs_sc: moveset = action_table[state][color][1] if dirs[opposite_dirs[dir]] in moveset: # e.g. is there one to the S about to move N
def TriangularTransitionsToRuleTree_SplittingMethod(neighborhood,n_states,transitions_list,rule_name): # each square cell is j*N+i where i is the lower triangle, j is the upper triangle # each i,j in (0,N] # (lower and upper are lists) def encode(lower,upper): return [ up*n_states+low for up in upper for low in lower ] # what neighbors of the lower triangle overlap neighbors of the upper triangle? lower2upper = { "triangularVonNeumann": [(0,1),(1,0)], "triangularMoore": [(0,1),(1,0),(2,12),(3,4),(4,3),(5,10),(6,11),(10,5),(11,6),(12,2)], } numNeighbors = { "triangularVonNeumann":4, "triangularMoore":8 } # convert transitions to list of list of sets for speed transitions = [[set(e) for e in t] for t in transitions_list] tree = RuleTree(n_states*n_states,numNeighbors[neighborhood]) # for each transition pair, see if we can apply them both at once to a square for i,t1 in enumerate(transitions): # as lower golly.show("Building rule tree... (pass 1 of 2: "+str(100*i/len(transitions))+"%)") for t2 in transitions: # as upper # we can only apply both rules at once if they overlap to some extent ### AKT: any() and isdisjoint() are not available in Python 2.3: ### if any( t1[j].isdisjoint(t2[k]) for j,k in lower2upper[neighborhood] ): ### continue any_disjoint = False for j,k in lower2upper[neighborhood]: if len(t1[j] & t2[k]) == 0: any_disjoint = True break if any_disjoint: continue # take the intersection of their inputs if neighborhood=="triangularVonNeumann": tree.add_rule( [ encode(t1[0]&t2[1],t1[1]&t2[0]), # C encode(range(n_states),t1[2]), # S encode(t2[3],range(n_states)), # E encode(range(n_states),t1[3]), # W encode(t2[2],range(n_states)) ], # N encode(t1[4],t2[4])[0] ) # C' elif neighborhood=="triangularMoore": tree.add_rule( [ encode(t1[0]&t2[1],t1[1]&t2[0]), # C encode(t1[7],t1[2]&t2[12]), # S encode(t1[4]&t2[3],t2[9]), # E encode(t1[9],t1[3]&t2[4]), # W encode(t1[12]&t2[2],t2[7]), # N encode(t1[6]&t2[11],t1[5]&t2[10]), # SE encode(range(n_states),t1[8]), # SW encode(t2[8],range(n_states)), # NE encode(t1[10]&t2[5],t1[11]&t2[6]) ], # NW encode(t1[13],t2[13])[0] ) # C' # apply each transition to an individual triangle, leaving the other unchanged for i,t in enumerate(transitions): golly.show("Building rule tree... (pass 2 of 2: "+str(100*i/len(transitions))+"%)") for t_1 in t[1]: if neighborhood=="triangularVonNeumann": # as lower triangle: tree.add_rule( [ encode(t[0],[t_1]), # C encode(range(n_states),t[2]), # S range(n_states*n_states), # E encode(range(n_states),t[3]), # W range(n_states*n_states) ], # N encode(t[4],[t_1])[0] ) # C' # as upper triangle: tree.add_rule( [ encode([t_1],t[0]), # C range(n_states*n_states), # S encode(t[3],range(n_states)), # E range(n_states*n_states), # W encode(t[2],range(n_states)) ], # N encode([t_1],t[4])[0] ) # C' elif neighborhood=="triangularMoore": # as lower triangle: tree.add_rule( [encode(t[0],[t_1]), # C encode(t[7],t[2]), # S encode(t[4],range(n_states)), # E encode(t[9],t[3]), # W encode(t[12],range(n_states)), # N encode(t[6],t[5]), # SE encode(range(n_states),t[8]), # SW range(n_states*n_states), # NE encode(t[10],t[11]) ], # NW encode(t[13],[t_1])[0] ) # C' # as upper triangle: tree.add_rule( [encode([t_1],t[0]), encode(range(n_states),t[12]), # S encode(t[3],t[9]), # E encode(range(n_states),t[4]), # W encode(t[2],t[7]), # N encode(t[11],t[10]), # SE range(n_states*n_states), # SW encode(t[8],range(n_states)), # NE encode(t[5],t[6]) ], # NW encode([t_1],t[13])[0] ) # C' # output the rule tree golly.show("Compressing rule tree and saving to file...") tree.write(golly.getdir('rules') + rule_name + '.tree')