Code: Select all
import os
class RuleGenerator:
global rulestring
# notationdict adapted from Eric Goldstein's HenselNotation->Ruletable(1.3).py
# ( http://conwaylife.com/forums/viewtopic.php?p=6815#p6815 )
# Modified for neighbourhood2 version of Hensel's notation
notationdict = {
"0": [0, 0, 0, 0, 0, 0, 0, 0], #
"1e": [1, 0, 0, 0, 0, 0, 0, 0], # N
"1c": [0, 1, 0, 0, 0, 0, 0, 0], # NE
"2a": [1, 1, 0, 0, 0, 0, 0, 0], # N, NE
"2e": [1, 0, 1, 0, 0, 0, 0, 0], # N, E
"2k": [1, 0, 0, 1, 0, 0, 0, 0], # N, SE
"2i": [1, 0, 0, 0, 1, 0, 0, 0], # N, S
"2c": [0, 1, 0, 1, 0, 0, 0, 0], # NE, SE
"2n": [0, 1, 0, 0, 0, 1, 0, 0], # NE, SW
"3a": [1, 1, 1, 0, 0, 0, 0, 0], # N, NE, E
"3n": [1, 1, 0, 1, 0, 0, 0, 0], # N, NE, SE
"3r": [1, 1, 0, 0, 1, 0, 0, 0], # N, NE, S
"3q": [1, 1, 0, 0, 0, 1, 0, 0], # N, NE, SW
"3j": [1, 1, 0, 0, 0, 0, 1, 0], # N, NE, W
"3i": [1, 1, 0, 0, 0, 0, 0, 1], # N, NE, NW
"3e": [1, 0, 1, 0, 1, 0, 0, 0], # N, E, S
"3k": [1, 0, 1, 0, 0, 1, 0, 0], # N, E, SW
"3y": [1, 0, 0, 1, 0, 1, 0, 0], # N, SE, SW
"3c": [0, 1, 0, 1, 0, 1, 0, 0], # NE, SE, SW
"4a": [1, 1, 1, 1, 0, 0, 0, 0], # N, NE, E, SE
"4r": [1, 1, 1, 0, 1, 0, 0, 0], # N, NE, E, S
"4q": [1, 1, 1, 0, 0, 1, 0, 0], # N, NE, E, SW
"4i": [1, 1, 0, 1, 1, 0, 0, 0], # N, NE, SE, S
"4y": [1, 1, 0, 1, 0, 1, 0, 0], # N, NE, SE, SW
"4k": [1, 1, 0, 1, 0, 0, 1, 0], # N, NE, SE, W
"4n": [1, 1, 0, 1, 0, 0, 0, 1], # N, NE, SE, NW
"4z": [1, 1, 0, 0, 1, 1, 0, 0], # N, NE, S, SW
"4j": [1, 1, 0, 0, 1, 0, 1, 0], # N, NE, S, W
"4t": [1, 1, 0, 0, 1, 0, 0, 1], # N, NE, S, NW
"4w": [1, 1, 0, 0, 0, 1, 1, 0], # N, NE, SW, W
"4e": [1, 0, 1, 0, 1, 0, 1, 0], # N, E, S, W
"4c": [0, 1, 0, 1, 0, 1, 0, 1], # NE, SE, SW, NW
"5i": [1, 1, 1, 1, 1, 0, 0, 0], # N, NE, E, SE, S
"5j": [1, 1, 1, 1, 0, 1, 0, 0], # N, NE, E, SE, SW
"5n": [1, 1, 1, 1, 0, 0, 1, 0], # N, NE, E, SE, W
"5a": [1, 1, 1, 1, 0, 0, 0, 1], # N, NE, E, SE, NW
"5q": [1, 1, 1, 0, 1, 1, 0, 0], # N, NE, E, S, SW
"5c": [1, 1, 1, 0, 1, 0, 1, 0], # N, NE, E, S, W
"5r": [1, 1, 0, 1, 1, 1, 0, 0], # N, NE, SE, S, SW
"5y": [1, 1, 0, 1, 1, 0, 1, 0], # N, NE, SE, S, W
"5k": [1, 1, 0, 1, 0, 1, 1, 0], # N, NE, SE, SW, W
"5e": [1, 1, 0, 1, 0, 1, 0, 1], # N, NE, SE, SW, NW
"6a": [1, 1, 1, 1, 1, 1, 0, 0], # N, NE, E, SE, S, SW
"6c": [1, 1, 1, 1, 1, 0, 1, 0], # N, NE, E, SE, S, W
"6k": [1, 1, 1, 1, 0, 1, 1, 0], # N, NE, E, SE, SW, W
"6e": [1, 1, 1, 1, 0, 1, 0, 1], # N, NE, E, SE, SW, NW
"6n": [1, 1, 1, 0, 1, 1, 1, 0], # N, NE, E, S, SW, W
"6i": [1, 1, 0, 1, 1, 1, 0, 1], # N, NE, SE, S, SW, NW
"7c": [1, 1, 1, 1, 1, 1, 1, 0], # N, NE, E, SE, S, SW, W
"7e": [1, 1, 1, 1, 1, 1, 0, 1], # N, NE, E, SE, S, SW, NW
"8": [1, 1, 1, 1, 1, 1, 1, 1], # N, NE, E, SE, S, SW, W, NW
}
allneighbours = [
["0"],
["1e", "1c"],
["2a", "2e", "2k", "2i", "2c", "2n"],
["3a", "3n", "3r", "3q", "3j", "3i", "3e", "3k", "3y", "3c"],
["4a", "4r", "4q", "4i", "4y", "4k", "4n", "4z", "4j", "4t", "4w", "4e", "4c"],
["5i", "5j", "5n", "5a", "5q", "5c", "5r", "5y", "5k", "5e"],
["6a", "6c", "6k", "6e", "6n", "6i"],
["7c", "7e"],
["8"],
]
allneighbours_flat = [n for x in allneighbours for n in x]
numneighbours = len(notationdict)
# Use dict to store rule elements, initialised by setrule():
bee = {}
ess = {}
alphanumeric = ""
rulename = "Rule"
def __init__(self, rulestring):
self.table = """
n_states: """ + rulestring.split("/")[0].lower().replace("rg", "") + \
"""
neighborhood:Moore
symmetries:rotate4reflect
"""
all_states = list(range(int(rulestring.split("/")[0].lower().replace("rg", ""))))
self.table += self.newvars(["a", "b", "c", "d", "e", "f", "g", "h"],
all_states)
all_states.remove(1)
for i in range(8):
self.table += self.newvars(["any" + str(i)], all_states)
# Interpret birth or survival string
def ruleparts(self, part):
inverse = False
nlist = []
totalistic = True
rule = {k: False for k, v in self.notationdict.items()}
# Reverse the rule string to simplify processing
part = part[::-1]
for c in part:
if c.isdigit():
d = int(c)
if totalistic:
# Add all the neighbourhoods for this value
for neighbour in self.allneighbours[d]:
rule[neighbour] = True
elif inverse:
# Add all the neighbourhoods not in nlist for this value
for neighbour in self.allneighbours[d]:
if neighbour[1] not in nlist:
rule[neighbour] = True
else:
# Add all the neighbourhoods in nlist for this value
for n in nlist:
neighbour = c + n
if neighbour in rule:
rule[neighbour] = True
else:
# Error
return {}
inverse = False
nlist = []
totalistic = True
elif (c == '-'):
inverse = True
else:
totalistic = False
nlist.append(c)
return rule
def setrule(self, rulestring):
birth = rulestring.split("/")[0].replace("b", "")
survive = rulestring.split("/")[1].replace("s", "")
b = self.ruleparts(birth)
s = self.ruleparts(survive)
if b and s:
self.alphanumeric = 'B' + birth + 'S' + survive
self.rulename = 'B' + birth + '_S' + survive
self.bee = b
self.ess = s
# Save a rule file:
def saverule(self, name, comments, table, colours):
ruledir = ""
filename = ruledir + name + ".rule"
print(filename)
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):
f = open(filename, 'w+')
f.write(results)
f.close()
# Defines a variable:
def newvar(self, name, vallist):
line = "var " + name + "={"
for i in range(len(vallist)):
if (i > 0):
line += ','
line += str(vallist[i])
line += "}\n"
return line
# Defines a block of equivalent variables:
def newvars(self, namelist, vallist):
block = "\n"
for name in namelist:
block += self.newvar(name, vallist)
return block
def scoline(self, chara, charb, left, right, amount):
line = str(left) + ","
for i in range(8):
if (i < amount):
line += chara
else:
line += charb
line += chr(97 + i)
line += ","
line += str(right) + "\n"
return line
def isotropicline(self, chara, charb, left, right, n):
line = str(left) + ","
neighbours = self.notationdict[n]
for i in range(8):
if neighbours[i]:
line += chara
else:
line += charb
line += chr(97 + i)
line += ","
line += str(right) + "\n"
return line
def saveIsotropicRule(self, birth_1, birth_2, survival_1, survival_2, death_1, death_2):
comments = ""
self.table += "\n# Birth\n"
for n in self.allneighbours_flat:
if self.bee[n]:
self.table += str(birth_1) + ","
string = ""
counter = 0
for i in str(self.notationdict[n])[1:-1].replace(" ", "").replace(",", ""):
if i == "0":
string += "any" + str(counter) + ","
counter += 1
else:
string += i + ","
self.table += string
self.table += "," + str(birth_2) + "\n"
self.table += "\n# Survival\n"
for n in self.allneighbours_flat:
if self.ess[n]:
self.table += str(survival_1) + ","
string = ""
counter = 0
for i in str(self.notationdict[n])[1:-1].replace(" ", "").replace(",", ""):
if i == "0":
string += "any" + str(counter) + ","
counter += 1
else:
string += i + ","
self.table += string
self.table += "," + str(survival_2) + "\n"
self.table += "\n# Death\n"
self.table += self.scoline("", "", death_1, death_2, 0)
rulestring = "rg3/l1/b34c/s234y8/rb36/rs58"
n_states = int(rulestring.split("/")[0].lower().replace("rg", ""))
rg = RuleGenerator(rulestring) # rg3/l1/b3/s23/rb36/rs58
rg.setrule("/".join(rulestring.split("/")[2:4]))
rg.saveIsotropicRule(0, int(rulestring.split("/")[1].replace("l", "")), 1, 1, 1, 2)
rg.setrule("/".join(rulestring.split("/")[4:]))
for i in range(2, n_states):
rg.saveIsotropicRule(i, i - 1, i, i, i, (i + 1) % n_states)
print("@RULE Rule")
print()
print("@TABLE")
print(rg.table)
Just change the variable rulestring to the desired rulestring.
Copy output into rule table file.