Here's a Lua version of the MAPper script, with one handy improvement.
Instead of defaulting to B3/S23, the script now tries to default to the MAP string representing the rule currently set in Golly. This makes it easier to make minimal changes to specific Life-like rules, without having to go through a separate step to figure out what the MAP equivalent of the Life-like rule is.
This script also makes the rule change immediately in Golly, rather than reporting it to the clipboard.
If anyone runs into bugs, please let me know. I only tried it on
muzik's two rules, and those seemed to work fine, but it would be easy for some problem to have crept in that I haven't thought of.
Code: Select all
-- MAPper.lua
-- Changes a given MAP rule one state at a time, much faster than by hand.
-- The way it works will switch the existing transition input.
-- Solution is shown and copied to clipboard, prefixed with MAP.
-- Lua version defaults to current rule if this can be determined.
-- Authors: Rhombic, dvgrn
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
-- make reasonably sure that the current rule is something compatible with the MAP-rule-finding function
if g.numstates()==3 then
g.addlayer("Default two-state")
g.setrule("B/S")
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={}
lookup={}
base64char={}
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)
lookup[lookupstr:sub(i,i)]=i-1
base64char[i-1]=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()
toconvert=rulestr.."0000"
toconvertold=toconvert
mapstr=""
while #toconvert>0 do
chunk=toconvert:sub(1,6)
toconvert=toconvert:sub(7)
mapstr=mapstr..bdict[chunk]
end
-- g.setclipstr(mapstr.."\n"..toconvert.."\n"..toconvertold)
rule = g.getstring("Initial MAP rule to modify (default is CGoL or current rule) without the MAP prefix. Leave blank to start from scratch (B/S)", mapstr)
if rule == "" then rule="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" end
changestr = g.getstring("How many changes are you planning?","1")
if changestr == "" then changestr = 0 end
changes = tonumber(changestr)
if changes == 0 then g.exit() end
for i= 1, changes do
newcase = g.getstring("Binary code to implement:","000000000")
if #newcase~=9 then
g.exit("Input "..newcase.." does not have the required nine characters.")
end
defect = 0
pow = 256
for j = 1, string.len(newcase) do
num = string.sub(newcase, j, j) == "1" and 1 or 0
defect = defect + num * pow
pow = pow / 2
end
rulepos = (defect-(defect%6))//6
-- g.note("rulepos="..rulepos)
bitpos = defect % 6
char=rule:sub(rulepos+1,rulepos+1)
-- g.note("rulepos character in rule="..char..", bitpos="..bitpos)
bitpattern = lookup[char]
-- g.note(lookup[char])
-- g.note("bitpattern="..bitpattern)
newbitpattern = bitpattern ~ (2^(5-bitpos))
-- g.note("newbitpattern="..newbitpattern)
newrule = rule:sub(1,rulepos)..base64char[newbitpattern]..rule:sub(rulepos+2)
g.show("Last transition changed: "..base64char[newbitpattern].." replaced "..base64char[bitpattern].." at position "..rulepos.." New rule is MAP"..newrule)
rule = newrule
end
g.setrule("MAP"..newrule)