I barely have any experience with Lua, so this no doubt contains a ton of inefficiencies and unnecessary nonsense, but I've attempted to create a script that can simulate any 1D Wolfram rule in a bounded universe in Golly, including odd-numbered ones:
Code: Select all
-- Creates a rule file for 1D elementary cellular automata, and then optionally runs
-- it for a given number of generations in a torus.
-- Note: This will create a .rule file in your Rules folder, specified in Preferences.
-- The rules can be run by themselves when the background is state 1, but the script
-- will run them closer to how Golly simulates even rules.
-- Also note that while this script does support even-numbered elementary rules, Golly
-- natively supports these, so it's mostly pointless to use it with even rules.
local g = golly()
local clipboard = g.getclipstr()
-- Decimal to binary converter function from http://bit.ly/2wQ9yqr because I have
-- absolutely no idea where to begin making my own
local function tobits(num,bits)
-- returns a table of bits, most significant first.
bits = bits or math.max(1, select(2, math.frexp(num)))
local t = {} -- will contain the bits
for b = bits, 1, -1 do
t[b] = math.fmod(num, 2)
num = math.floor((num - t[b]) / 2)
end
return t
end
local rule = tonumber(g.getstring("Enter 1D rule (0 to 255).\n\nRule \"W-<#>\" will be created, and overwritten\nif it exists.", "73", "Set rule"))
local rulename = "W-"..tostring(rule)
if rule == nil or rule < 0 or rule > 255 then
g.exit("Invalid rule specified.")
end
local rulestring = tobits(rule, 8)
local a, b, c, d, e, f, h, i = table.unpack(rulestring)
local function a1(x)
x = tostring(tonumber(x)+1)
return x
end
local trans = "1,1,1,"..a1(i).."\n1,1,2,"..a1(h).."\n2,1,1,"..a1(f).."\n2,1,2,"..a1(e).."\n1,2,1,"..a1(d).."\n1,2,2,"..a1(c).."\n2,2,1,"..a1(b).."\n2,2,2,"..a1(a).."\n"
local comment = "Automatically generated by a Lua script.\nThe rule will only work when the background state is 1."
local rulefile = "@RULE "..rulename.."\n\n"..comment.."\n\n@TABLE\n\nn_states:3\nneighborhood:oneDimensional\nsymmetries:none\n\n"..trans.."\n@COLORS\n1 0 0 0\n2 255 255 255"
local ruledir = g.getdir("rules")
file = io.open(ruledir..rulename..".rule", "w")
file:write(rulefile)
file:close()
g.show("Rule \""..rulename.."\" created.")
local patternrect = g.getrect()
local pattern
local usepattern = g.getstring("Enter 1 to run the current pattern; anything\nelse will start with a single cell.\n\nIf doing this, the pattern should be 1 cell high\nand roughly centered on the y-axis.\n\n(Note: Use state 0 as the background state for this.)", "", "Use current pattern?")
if usepattern == "1" then
local rect = g.getrect()
if rect[4] ~= 1 then
g.warn("Pattern is either empty or more than one cell high.\nDefaulting to single cell.")
pattern = {0, 0, 2}
else
pattern = g.getcells(g.getrect())
end
else
pattern = {0, 0, 2}
end
local width = tonumber(g.getstring("Set width of pattern generation:", "500", "Set width"))
local height = math.tointeger(g.getstring("Set number of generations to run:", "250") + 1) -- +1 because top is gen 0
g.setrule(rulename..":T"..tostring(width)..","..tostring(height))
g.new(rulename)
local rect = {math.ceil(-g.getwidth() / 2), math.ceil(-g.getheight() / 2), g.getwidth(), g.getheight()}
for j = rect[2], rect[2] + rect[4] - 1 do
for k = rect[1], rect[1] + rect[3] - 1 do
g.setcell(k, j, 1)
end
end
g.putcells(pattern, 0, rect[2] - pattern[2])
-- there has got to be a better way to do this absolute mess of a thing but i
-- can't think of anything right now
g.select({rect[1], rect[2], rect[3], 1})
for l = rect[2], rect[2]+rect[4] - 2 do
g.copy()
g.paste(rect[1], l+1, "or")
g.select({rect[1], l+1, rect[3], 1})
g.advance(0, 1)
end
g.select({})
g.fit()
g.setclipstr(clipboard)
As I said, there are surely lots of ways this could be improved. One rather obvious thing is that when the script completes, it spits out a bunch of copies of this error message:
Code: Select all
Failed to get data from the clipboard (error -2147221040: openClipboard Failed)
If anyone knows of any ways to fix that issue or improve on the script in general (for example, not requiring that stupid copy-paste-advance loop), please let me know.
(Also note that I've tested this on 3.0b2 on Windows 10, and haven't made any attempts to test it on other versions.)