Re: Script request thread
Posted: February 10th, 2018, 6:29 am
Yes.Majestas32 wrote:Isotropic. And I think Calcyman talked about every rule actually having a strobing checkerboard dual?
Yes.Majestas32 wrote:Isotropic. And I think Calcyman talked about every rule actually having a strobing checkerboard dual?
Code: Select all
x = 7, y = 7, rule = B3/S23
$b3o$bo2bo$5bo$2bobo!
Code: Select all
x = 17, y = 11, rule = B3/S23
13b3o2$o$o$o2$2b3o2$o$o14b2o$o14b2o!
I guess I should have documented the census data better.is there some way to search for a pattern manually, and how do the coordinate systems for the entries work?
Code: Select all
x=3, y=3
3o$o$bo!
As it is now, there's probably not a good way to search for that. I mentioned to Dave that maybe I should include the apgcode of the final pattern, as a sort of hashcode.does this come up in the files somewhere?
Looks like there are 30 collisions that result in this constellation, probably all have the same ancestor, since they take about 180 generations to stabilize. Here are some of them--Also, does this come up in the files somewhere? It would indicate the presence of a spark I have been looking for a synthesis of.
Code: Select all
x=14, y=8
bo$2bo$3o2$12bo$b2o8b2o$2b2o7bobo$bo!
Code: Select all
x=10, y=8
8bo$9bo$7b3o$bo$2bo$3o3bo$6b2o$5bobo!
Has anyone looked into this yet?Majestas32 wrote:I also need to find the rule with the xp104_hexeh and xp14_eh so +1danny wrote:This gets a +1 from me because I need to find that one rule where the bun evolves into a monogram77topaz wrote:Is it possible to make a script that, given an apgcode, looks through Catagolue for rules where that apgcode has appeared and then returns the rule in which that pattern is the most common relative to other patterns (i.e. in which it appears the highest in the list of most common objects)?
Also the xp170 OMOS from my avatar
I haven't written anything related to CataGoLue, but I suspect that anyone who does is (and definitely should be) wary of running scripts that make lots of requests (over many different rules in this case) because that kind of thing can result in disk operations going over quota and therefore CataGoLue being down for the rest of the day.77topaz wrote:Has anyone looked into this yet?77topaz wrote:Is it possible to make a script that, given an apgcode, looks through Catagolue for rules where that apgcode has appeared and then returns the rule in which that pattern is the most common relative to other patterns (i.e. in which it appears the highest in the list of most common objects)?
The second part is pretty hard to do intelligently - I think better if you specify manually to the search which still lifes you want to include in the search.danny wrote:How do I find a reaction that shoots one of two ships at a few common still lifes and looks for a reaction that pulls it (-1,0) and outputs the same ship heading the other way, all in a specific rule?
I was thinking it could run soups and pick random still lifes out of there, and position them close enough together
Code: Select all
# build-dot-field-v10.py
import golly as g
from time import sleep
from glife.text import make_text
MAXOBJ=5
xsize,ysize=5,12
# Obtains an alphanumeric representation of a pattern that
# fits within a 40-by-40 bounding box. This representation is
# alphanumeric and lowercase, and so much more compact than RLE. Compare:
#
# It is a generalisation of a notation created by Allan Weschler in 1992.
# By Adam P. Goucher
def canonise_orientation(rect):
representation = ""
ox, oy, length, breadth = rect
a, b, c, d = 1, 0, 0, 1
chars = "0123456789abcdefghijklmnopqrstuvwxyz"
for v in xrange(int((breadth-1)/5)+1):
zeroes = 0
if (v != 0):
representation += "z"
for u in xrange(length):
baudot = 0
for w in xrange(5):
x = ox + a*u + b*(5*v + w)
y = oy + c*u + d*(5*v + w)
baudot = (baudot >> 1) + 16*g.getcell(x, y)
if (baudot == 0):
zeroes += 1
else:
if (zeroes > 0):
if (zeroes == 1):
representation += "0"
elif (zeroes == 2):
representation += "w"
elif (zeroes == 3):
representation += "x"
else:
representation += "y"
representation += chars[zeroes - 4]
zeroes = 0
if baudot >= len(chars): g.warn("baudot = " + str(baudot))
representation += chars[baudot]
return representation
# check that a layer is available for canonisation
testlayer = g.getlayer()
canonlayer = -1
for i in xrange(g.numlayers()):
if g.getname(i) == "canonical":
canonlayer = i
break
if canonlayer == -1 and g.numlayers() == g.maxlayers():
g.exit("You need to delete a layer.")
if canonlayer == -1:
canonlayer = g.addlayer()
g.setrule('B2/S0')
g.new("canonical")
g.setlayer(testlayer)
patdict={}
# for i in range(2,xsize+1):
# for j in range(2,ysize+1):
# patdict[str([i,j])]=[]
objs=["o!", ] # dot
objlist=[]
for i in range(len(objs)):
# normalize so that the first ON cell in the list is always (0,0)
templist=g.parse(objs[i])
objlist+=[g.transform(templist,-templist[0],-templist[1])]
numobjs=len(objlist)
zonelist=[]
for item in objlist:
g.setrule("B12345678/S012345678")
zone=g.evolve(item,2)
zonelist+=[zone] # includes cells for object also
g.setrule("LifeHistory")
nearlist=[[i,j] for i in range(-1,xsize+1) for j in range(-1,ysize+1) if i<0 or i>=xsize or j<0 or j>=ysize]
count,x,y,ptr,filledlist,searchlist=0,0,0,0,[],[]
canonlist=[]
while y==0 or len(searchlist)>0:
overlap=([x,y] in nearlist)
# place current object
#############################################
# TODO: if there's an overlap, set ptr to max value, then handle all cases with same code at the bottom
if overlap==0:
# g.show(str(ptr))
obj=g.transform(objlist[ptr],x,y)
objpairs=[[obj[i],obj[i+1]] for i in range(0,len(obj),2)]
for item in objpairs:
if item in nearlist:
overlap=1
break
if overlap==0:
zone=g.transform(zonelist[ptr],x,y)
zonepairs=[[zone[i],zone[i+1]] for i in range(0,len(zone),2)]
for item in zonepairs:
if item in filledlist:
overlap=2
break
if overlap==0:
g.new("TestPage")
newptr,newx,newy=ptr+1,x,y
if newptr>=len(objlist): newptr,newx=0,newx+1
if newx>=xsize-1: newptr,newx,newy=0,0,y+1
searchlist.append([newx,newy,newptr,nearlist[:],filledlist[:]]) # add next state to search to the stack
nearlist+=zonepairs
filledlist+=objpairs
for i,j in nearlist: g.setcell(i,j,2)
minx, maxx, miny, maxy = 999,-999,999,-999
for i,j in filledlist:
g.setcell(i,j,1)
if i<minx:minx=i
elif i>maxx:maxx=i
if j<miny: miny=j
elif j>maxy: maxy=j
# Take a snapshot of the current successful placement
# [e.g., successful if two objects placed, etc.]
if minx==0 and miny==0:
keystr=str(maxx+1)+"x"+str(maxy+1)
if keystr not in patdict: patdict[keystr]=[]
if filledlist not in patdict[keystr]:
# Add to pattern list
patdict[keystr]+=[filledlist[:]]
# Add canonical representation to list
g.setlayer(canonlayer)
g.new("")
g.putcells([v for cell in filledlist for v in cell])
canon = canonise_orientation(g.getrect())
canonlist.append("xs" + str(len(filledlist)) + "_" + canon)
g.setlayer(testlayer)
# Now continue searching from where we are
count+=1
if count%100==0:
g.show(str(count))
g.update()
ptr,x=0,x+4
else: # the neighbor zone for this object overlaps some already placed object
ptr+=1
if ptr>=len(objlist): ptr,x=0,x+1
else: # the object itself overlaps some already placed object's neighborhood
ptr+=1
if ptr>=len(objlist): ptr,x=0,x+1
else:
ptr,x=0,x+1
if x>=xsize-1: ptr,x,y=0,0,y+1
if y>=ysize-1 or len(searchlist)>=MAXOBJ:
# we've reached the end of the frame.
# Time to clear the last placed object, go back to that x,y
if searchlist==[]:
g.new("TestPage")
g.exit("Search is complete.")
x,y,ptr,nearlist,filledlist=searchlist.pop()
# no point in looking at configurations with no object on the first line
g.new("TestPage")
outstr="Total count = " + str(count)
t=make_text(outstr,"mono")
g.putcells(t,0,-20)
for item in sorted(patdict):
y=0
t = make_text(item + " ("+str(len(patdict[item]))+")","mono")
outstr+="\n" + item + " ("+str(len(patdict[item]))+")"
g.putcells(t,x-6,y)
y+=30
for pat in patdict[item]:
for cell in pat:
g.setcell(cell[0]+x,cell[1]+y,1)
y+=20
x+=100
g.setclipstr(outstr)
results = "@Dot constellations in fields of size " + str(xsize) + " x " + str(ysize) + "\n"
for patt in canonlist:
results += patt + "\n"
filename = "dot-field.txt"
try:
f = open(filename, 'w')
f.write(results)
f.close()
except:
g.warn("Unable to create results file:\n" + filename)
g.exit("Search is complete.")
Are you saying that could happen just from viewing/searching pages, as opposed to uploading things to the server via apgsearch?wildmyron wrote:I haven't written anything related to CataGoLue, but I suspect that anyone who does is (and definitely should be) wary of running scripts that make lots of requests (over many different rules in this case) because that kind of thing can result in disk operations going over quota and therefore CataGoLue being down for the rest of the day.
I'm thinking of scripts like this one which read dynamically generated pages (see references therein for details of the problem). On reflection, as you're only interested in a single object you can get away with just loading one page per rule the object works in (Limited to rules which have been searched, available from Apple Bottom's list.77topaz wrote:Are you saying that could happen just from viewing/searching pages, as opposed to uploading things to the server via apgsearch?wildmyron wrote:I haven't written anything related to CataGoLue, but I suspect that anyone who does is (and definitely should be) wary of running scripts that make lots of requests (over many different rules in this case) because that kind of thing can result in disk operations going over quota and therefore CataGoLue being down for the rest of the day.
Of course.77topaz wrote:Are you saying that could happen just from viewing/searching pages, as opposed to uploading things to the server via apgsearch?
Here's a candidate script:On Discord, danny wrote:i want a script that adds or removes a random transition from a rule
that isn't b012a...
Code: Select all
-- change-random-isotropic-bit-v1.0.lua
local g = golly()
local gp = require "gplus"
local split = gp.split
function fixrule(s)
return (gp.split(s,":")) -- remove bounded grid spec, if any
end
g.addlayer("temp") -- keep and test the current rule
fixedrule=fixrule(g.getrule())
g.setrule(fixedrule)
bitlist={{-1,-1,256},{0,-1,128},{1,-1,64},{-1,0,32},{0,0,16},{1,0,8},{-1,1,4},{0,1,2},{1,1,1}}
for j = 1, 9 do
x, y, bit = table.unpack(bitlist[j])
for i=0, 511 do
if i&bit>0 then g.setcell(i*5+x,y,1) end
end
end
g.run(1)
bits={}
ind=1
local rulestr, invstr, revinvstr="","",""
for k=0,2555,5 do
if g.getcell(k,0)==1 then
rulestr=rulestr.."1"
invstr=invstr.."0"
revinvstr="0"..revinvstr
else
rulestr=rulestr.."0"
invstr=invstr.."1"
revinvstr="1"..revinvstr
end
end
-- build base64 lookup table
local lookupstr="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
bdict={}
for i=1,64 do
local w=""
for j=0,5 do
if (i-1)&2^j>0 then w="1"..w else w="0"..w end
end
bdict[w]=lookupstr:sub(i,i)
end
-- decide whether to use standard, inverted, or inverted-reversed bitstring, based on fixedrule
-- (assuming Golly is correctly simulating rules with B0, with or without S8, to avoid strobing)
-- the following won't work for anisotropic non-totalistic rules defined by MAP strings, so
-- we'd have to decode the MAP rulestring into a 512-bit string in that case, check first and last digits.
if string.match(fixedrule,"B0") then rulestr = string.match(fixedrule,"S.*8") and revinvstr or invstr end
g.dellayer()
-- lookup table for isotropic bits
-- Each of the 102 isotropic bits corresponds to one or more bits in the 512-bit binary MAP string.
-- In this script we're assuming the rule in question is isotropic,
-- so technically we just need to check one of the neighborhoods to know the bit setting for all of them.
-- However, we'll check all the anisotropic bits, just to prove that everything is working...
isotropicbits ={{"0",0},
{"1c",1,4,64,256},
{"1e",2,8,32,128},
{"2a",3,6,9,36,72,192,288,384},
{"2c",5,65,260,320},
{"2e",10,34,136,160},
{"2i",40,130},
{"2k",12,33,66,96,129,132,258,264},
{"2n",68,257},
{"3c",69,261,321,324},
{"3e",42,138,162,168},
{"3a",11,38,200,416},
{"3i",7,73,292,448},
{"3k",98,140,161,266},
{"3n",13,37,67,193,262,328,352,388},
{"3j",14,35,74,137,164,224,290,392},
{"3q",70,76,100,196,259,265,289,385},
{"3r",41,44,104,131,134,194,296,386},
{"3y",97,133,268,322},
{"4c",325},
{"4e",170},
{"4a",15,39,75,201,294,420,456,480},
{"4i",45,195,360,390},
{"4k",99,141,165,225,270,330,354,396},
{"4n",71,77,263,293,329,356,449,452},
{"4j",106,142,163,169,172,226,298,394},
{"4q",102,204,267,417},
{"4r",43,46,139,166,202,232,418,424},
{"4y",101,197,269,323,326,332,353,389},
{"4t",105,135,300,450},
{"4w",78,228,291,393},
{"4z",108,198,297,387},
{"5c",171,174,234,426},
{"5e",327,333,357,453},
{"5a",79,295,457,484},
{"5i",47,203,422,488},
{"5k",229,334,355,397},
{"5n",107,143,167,233,302,428,458,482},
{"5j",103,205,271,331,358,421,460,481},
{"5q",110,206,230,236,299,395,419,425},
{"5r",109,199,301,361,364,391,451,454},
{"5y",173,227,362,398},
{"6c",175,235,430,490},
{"6e",335,359,461,485},
{"6a",111,207,303,423,459,486,489,492},
{"6i",365,455},
{"6k",231,237,363,366,399,429,462,483},
{"6n",238,427},
{"7c",239,431,491,494},
{"7e",367,463,487,493},
{"8",495}
}
-- pick a random bit to flip that isn't B012a
bschoice = math.random(2) -- 1=B, 2=S
-- flipping any bit would look like this:
-- flippedbit = isotropicbits[math.random(#isotropicbits)]
if bschoice==1 then -- with B bits, don't use the first four
flippedbit = isotropicbits[math.random(#isotropicbits-4)+4]
else
flippedbit = isotropicbits[math.random(#isotropicbits)]
end
-- g.note("Chosen bit is "..flippedbit[1])
finalrule = "B"
for i,bitlist in ipairs(isotropicbits) do
sum=0
bitname = bitlist[1]
for j=2,#bitlist do
value = bitlist[j]
sum=sum+tonumber(string.sub(rulestr,value+1,value+1))
end
if sum==#bitlist-1 then s=bitname else s="" end -- assuming isotropic rule here
if bitname==flippedbit[1] and bschoice==1 then
-- g.note("B bitname ="..bitname.." and s="..s)
s = (s=="") and bitname or ""
end
finalrule = finalrule..s
end
finalrule = finalrule.."/S"
for i,bitlist in ipairs(isotropicbits) do
sum=0
bitname = bitlist[1]
for j=2,#bitlist do
value = bitlist[j]+16
sum=sum+tonumber(string.sub(rulestr,value+1,value+1))
end
if sum==#bitlist-1 then s=bitname else s="" end -- assuming isotropic rule here
if bitname==flippedbit[1] and bschoice==2 then
-- g.note("S bitname ="..bitname.." and s="..s)
s = (s=="") and bitname or ""
end
finalrule = finalrule..s
end
-- g.note(finalrule)
g.setrule(finalrule)
canonicalrule = g.getrule()
-- g.note(canonicalrule)That seems like a good idea, though we'd still need the script to be able to search that database.Apple Bottom wrote:If anyone's interested, I can share these on archive.org so that we won't all have to start hitting Catagolue with thousands of requests.
Sure, here's last week's data.77topaz wrote:That seems like a good idea, though we'd still need the script to be able to search that database.
Saka wrote:What about a script that picks a random rule from a given rule range?
+1 support, having a random variant picker that still keeps some dynamics would be pretty coolSaka wrote:Saka wrote:What about a script that picks a random rule from a given rule range?
What's the format for specifying the rule range? And is the randomness just 50-50 odds of the presence of each isotropic bit in the "maybe there, maybe not" range, or should it be something more complicated like "remove at least one and at most three isotropic bits from such-and-such list, and add (something similar) from such-and-such other list"?danny wrote:+1 support, having a random variant picker that still keeps some dynamics would be pretty coolSaka wrote:Saka wrote:What about a script that picks a random rule from a given rule range?
Macbi describes his partial notation like this:Majestas32 wrote:The format will probably be in macbi's partial notation and probs just remove or add 1 bit in the list at random
That seems straightforward enough, and we can just steal the parsing code from LLS_rules.py (and LLS_literal_manipulation.py). EDIT: Took out the LLS_formatting.py stuff, which seems to be only necessary when a rule is being parsed that's already in dictionary form.Macbi wrote:... put a "p" at the front of the rule to indicate that the rule is only being "partially" specified. After that:
If a number isn't present then none of those transitions are allowed.
If a number is present without any letters after it then all of its transitions are allowed.
If a number is present with some letters after it, followed by a minus sign, followed by some more letters, then the letters in the first group must be in the rule, the letters in the second group can't be in the rule, and any letters not mentioned can be in the rule or not.
Also if you just write "p" then it allows all of the rules.
So for example the command "-r pB34a/S2-c3a-c" would search for rules in which any B3 transitions were allowed to be present or not, any B4 were allowed to be present or not except B4a has to be, any S2 transitions would be allowed or not except S2c can't be used, and all S3 transitions can be used or not except S3a must be present and S3c can't be. No other transitions would be allowed.
Code: Select all
import golly as g
import re
################## from LLS_literal_manipulation
#
possible_transitions = {"0":sorted("c"),
"1":sorted("ce"),
"2":sorted("cekain"),
"3":sorted("cekainyqjr"),
"4":sorted("cekainyqjrtwz"),
"5":sorted("cekainyqjr"),
"6":sorted("cekain"),
"7":sorted("ce"),
"8":sorted("c")}
def rule_from_rulestring(rulestring, indent = 0, verbosity = 0):
if rulestring == None:
return None
else:
rule = {}
rulestring = rulestring.strip()
original_rulestring = rulestring
partial_flag = False
if rulestring[0] in ["p", "P"]:
partial_flag = True
if len(rulestring) == 1:
rulestring = "B012345678/S012345678"
else:
rulestring = rulestring[1:]
rulestring = re.sub(' ', '', rulestring.upper())
rulestrings = re.split("/", rulestring)
if len(rulestrings) == 1:
assert "B" in rulestring or "S" in rulestring, 'Rule string not recognised (no "B" or "S")'
B_position = rulestring.find("B")
S_position = rulestring.find("S")
rulestring = rulestring.strip("BS")
rulestrings = re.split("[BS]*", rulestring)
assert len(rulestrings) < 3, "Rule string not recognised"
if B_position > S_position:
birth_string = rulestrings[1] if len(rulestrings) == 2 else ""
survival_string = rulestrings[0]
else:
birth_string = rulestrings[0]
survival_string = rulestrings[1] if len(rulestrings) == 2 else ""
else:
assert len(rulestrings) == 2, 'Rule string not recognised (too many "/"s)'
if "S" in rulestrings[0] or "B" in rulestrings[1]:
birth_string = rulestrings[1]
survival_string = rulestrings[0]
else:
birth_string = rulestrings[0]
survival_string = rulestrings[1]
assert "S" not in birth_string and "B" not in survival_string, "Rule string not recognised"
birth_string = re.sub('B', '', birth_string).lower()
survival_string = re.sub('S', '', survival_string).lower()
assert (birth_string == "" or birth_string[0] in "012345678") and (survival_string == "" or survival_string[0] in "012345678"), "Rule string not recognised"
if partial_flag:
variable_number = 0
for BS_letter, rulestring in zip(["B", "S"], [birth_string, survival_string]):
transitions = []
previous_number = 0
if rulestring != "":
for position in range(1,len(rulestring)):
if rulestring[position] in "012345678":
transitions.append(rulestring[previous_number:position])
previous_number = position
transitions.append(rulestring[previous_number:])
for transition in transitions:
number_of_neighbours = transition[0]
if not partial_flag:
if len(transition) == 1:
for character in possible_transitions[number_of_neighbours]:
rule[BS_letter + number_of_neighbours + character] = "1"
elif transition[1] == "-":
banned_characters = transition[2:]
assert all(character in possible_transitions[number_of_neighbours] for character in banned_characters), "Unrecognized character"
for character in possible_transitions[number_of_neighbours]:
if character in banned_characters:
rule[BS_letter + number_of_neighbours + character] = "0"
else:
rule[BS_letter + number_of_neighbours + character] = "1"
else:
characters = transition[1:]
assert all(character in possible_transitions[number_of_neighbours] for character in characters), "Unrecognized character"
for character in possible_transitions[number_of_neighbours]:
if character in characters:
rule[BS_letter + number_of_neighbours + character] = "1"
else:
rule[BS_letter + number_of_neighbours + character] = "0"
else:
if len(transition) == 1:
for character in possible_transitions[number_of_neighbours]:
rule[BS_letter + number_of_neighbours + character] = "rule_variable_" + str(variable_number)
variable_number += 1
else:
characters = transition[1:]
if "-" in characters:
characters, banned_characters = re.split("-", characters)
else:
banned_characters = ""
for character in possible_transitions[number_of_neighbours]:
if character in characters:
rule[BS_letter + number_of_neighbours + character] = "1"
elif character in banned_characters:
rule[BS_letter + number_of_neighbours + character] = "0"
else:
rule[BS_letter + number_of_neighbours + character] = "rule_variable_" + str(variable_number)
variable_number += 1
for number_of_neighbours in "012345678":
if not rule.has_key(BS_letter + number_of_neighbours + "c"):
for character in possible_transitions[number_of_neighbours]:
rule[BS_letter + number_of_neighbours + character] = "0"
return ruleCode: Select all
g.note(str(rule_from_rulestring("pB34a/S2-c3a-c")))Code: Select all
{'S4e': '0', 'S4a': '0', 'S4c': '0', 'S4n': '0', 'S4i': '0', 'S4j': '0', 'S4k': '0', 'S4t': '0', 'S4w': '0', 'S4q': '0', 'S4r': '0', 'S4y': '0', 'S4z': '0', 'B2n': '0', 'B2k': '0', 'B2i': '0', 'B2e': '0', 'B2c': '0', 'B2a': '0', 'S5e': '0', 'S5c': '0', 'S5a': '0', 'S5n': '0', 'S5k': '0', 'S5j': '0', 'S5i': '0', 'S5r': '0', 'S5q': '0', 'S5y': '0', 'B5y': '0', 'B5r': '0', 'B5q': '0', 'B5j': '0', 'B5k': '0', 'B5i': '0', 'B5n': '0', 'B5c': '0', 'B5a': '0', 'B5e': '0', 'S6n': '0', 'B0c': '0', 'S6k': '0', 'S6i': '0', 'S6e': '0', 'S6c': '0', 'S6a': '0', 'B8c': '0', 'S7c': '0', 'S7e': '0', 'B3y': 'rule_variable_9', 'B3q': 'rule_variable_7', 'B3r': 'rule_variable_8', 'B3n': 'rule_variable_6', 'B3i': 'rule_variable_3', 'B3j': 'rule_variable_4', 'B3k': 'rule_variable_5', 'B3e': 'rule_variable_2', 'B3a': 'rule_variable_0', 'B3c': 'rule_variable_1', 'S8c': '0', 'B6c': '0', 'B6a': '0', 'B6e': '0', 'B6k': '0', 'B6i': '0', 'S0c': '0', 'B6n': '0', 'B1e': '0', 'B1c': '0', 'S1c': '0', 'S1e': '0', 'S2c': '0', 'S2a': 'rule_variable_22', 'S2e': 'rule_variable_23', 'S2k': 'rule_variable_25', 'S2i': 'rule_variable_24', 'S2n': 'rule_variable_26', 'B4t': 'rule_variable_18', 'B4w': 'rule_variable_19', 'B4q': 'rule_variable_16', 'B4r': 'rule_variable_17', 'B4y': 'rule_variable_20', 'B4z': 'rule_variable_21', 'B4e': 'rule_variable_11', 'S3n': 'rule_variable_31', 'B4a': '1', 'B4c': 'rule_variable_10', 'B4n': 'rule_variable_15', 'B4i': 'rule_variable_12', 'B4k': 'rule_variable_14', 'B4j': 'rule_variable_13', 'S3y': 'rule_variable_34', 'S3q': 'rule_variable_32', 'S3r': 'rule_variable_33', 'B7c': '0', 'S3i': 'rule_variable_28', 'B7e': '0', 'S3k': 'rule_variable_30', 'S3j': 'rule_variable_29', 'S3e': 'rule_variable_27', 'S3a': '1', 'S3c': '0'}