Golly scripts written in Lua

For scripts to aid with computation or simulation in cellular automata.
Post Reply
User avatar
confocaloid
Posts: 6697
Joined: February 8th, 2022, 3:15 pm
Location: learn to protect yourself against stray gliders and sparks and self-destruct mechanisms

Golly scripts written in Lua

Post by confocaloid »

It looks like many Golly scripts so far are written in Python, even though Lua is also supported.
The purpose of this forum thread is to collect (links to) Golly scripts written in Lua, and for ontopic discussion about such scripts.
search.php?keywords=lua+port
search.php?keywords=lua+porting
viewtopic.php?f=9&t=6418 safeopenclip.lua
viewtopic.php?f=9&t=3404 3D.lua

Other threads

For non-Lua scripts, post instead in one of the following threads:
viewtopic.php?f=9&t=3915 Thread for your script-related questions
viewtopic.php?f=9&t=2032 Script request thread
viewtopic.php?f=9&t=45 Golly scripts

---
R2INT wrote: March 26th, 2025, 1:45 pm [...] Here is an updated list of additional neighborhoods:

Code: Select all

#C White represents the center cell in the neighborhood, while
#C Cyan represents the corner cells and blue represents the knight cells.
# [[ COLOR ALIVE 255 255 255 COLOR DYING 0 255 255 COLOR DYINGRAMP 0 0 255 ]]
x = 72, y = 38, rule = 012345678//4
26.C.C10.C.C9.C3.C9.C3.C$3.C.C9.C.C32.C5.C7.C5.C$2.CB.BC7.C.B.C5.C.B.
B.C6.C2.B2.C8.B.B12.B$4.A10.BAB9.A11.BAB11.A12.BAB$2.CB.BC7.C.B.C5.C.
B.B.C6.C2.B2.C8.B.B12.B$3.C.C9.C.C32.C5.C7.C5.C$26.C.C10.C.C9.C3.C9.C
3.C3$26.C.C10.C.C9.C3.C9.C3.C$2.BC.CB8.CBC7.B3.B10.B9.CB3.BC7.C2.B2.C
$2.C3.C7.C3.C5.C5.C6.C5.C$4.A9.B.A.B8.A10.B.A.B10.A11.B.A.B$2.C3.C7.C
3.C5.C5.C6.C5.C$2.BC.CB8.CBC7.B3.B10.B9.CB3.BC7.C2.B2.C$26.C.C10.C.C9.
C3.C9.C3.C4$.B5.B8.B7.B.C.C.B8.CBC8.BC3.CB8.C.B.C$3.C.C9.C.C32.C5.C7.
C5.C$2.C3.C7.C3.C5.C5.C6.C5.C$4.A8.B2.A2.B7.A9.B2.A2.B9.A10.B2.A2.B$2.
C3.C7.C3.C5.C5.C6.C5.C$3.C.C9.C.C32.C5.C7.C5.C$.B5.B8.B7.B.C.C.B8.CBC
8.BC3.CB8.C.B.C4$B7.B7.B6.B7.B8.B8.B7.B9.B$26.C.C10.C.C9.C3.C9.C3.C$3.
C.C9.C.C32.C5.C7.C5.C$2.C3.C7.C3.C5.C5.C6.C5.C$4.A7.B3.A3.B6.A8.B3.A3.
B8.A9.B3.A3.B$2.C3.C7.C3.C5.C5.C6.C5.C$3.C.C9.C.C32.C5.C7.C5.C$26.C.C
10.C.C9.C3.C9.C3.C$B7.B7.B6.B7.B8.B8.B7.B9.B!
Here, I am actually 'forgetting' an infinite number of neighborhoods. These neighborhoods can be arbitrarily defined by manipulating the position of the knight neighbors and the position of the edge and corner neighbors. Obviously, I cannot include infinitely many patterns in this post, so I chose the simplest and smallest neighborhoods.
[...]
Assuming I understand how the pattern is formatted and what are restrictions in this case, below is a Golly script (Lua) to convert any of those neighbourhoods into a Golly-supported weighted neighbourhood ("NW") definition. This may be useful for those people who are interested in actually finding some reactions/patterns in cellular automata defined using some of these neighbourhoods (rather than inventing notations).

To use the script, open the above pattern in Golly, select one of neighbourhoods (and nothing else), and run the script.

Code: Select all

local g = golly()
local r = g.getselrect()
if r and (#r == 4) and (r[3] == r[4]) and (r[3] % 2 == 1) then
    local n = r[3] // 2
    local x = r[1] + n
    local y = r[2] + n
    local w = ''
    for dy = -n, n do
        for dx = -n, n do
            local c = g.getcell(x + dx, y + dy)
            if c == 2 then
                w = w .. '1'
            elseif c == 3 then
                w = w .. '5'
            else
                w = w .. '0'
            end
        end
    end
    local s = string.format('R%q,C0,S,B1,5,NW%s', n, w)
    g.setrule(s)
else
    g.show('Please select the neighbourhood (an odd-by-odd square) and nothing else.')
end
127:1 B3/S234c User:Confocal/R (isotropic CA, incomplete)
Unlikely events happen.
My silence does not imply agreement, nor indifference. If I disagreed with something in the past, then please do not construe my silence as something that could change that.
User avatar
dvgrn
Moderator
Posts: 12034
Joined: May 17th, 2009, 11:00 pm
Location: Madison, WI
Contact:

Re: Golly scripts written in Lua

Post by dvgrn »

Just in the last year or so we have a really helpful new tool to use for these code-porting projects: ChatGPT (or many similar LLMs, like Copilot) is capable of producing a completely correct Lua version of most Golly Python scripts that I've tried it on lately.

I guess I only have a few links to contribute so far:

LLS-format-selection-to-clipboard.lua, LLS-replace-center-with-asterisks.lua (minor helper scripts for an LLS iterative rewinding search)

llsss-setup.lua (Sokwe's helper script for setting up LLSSS searches)

Should make a jls-to-lls.lua also -- jls-to-lls.py has definitely proved its worth with the p18 gun and several other recent projects.

Lua version of RCT semilator showcase script -- an updated version of this is also available in the RCT Git repo, with a little digging.

I've also got getminpopandbb.lua for figuring out parameters to go in LifeWiki infoboxes for new engineered spaceships.

Also there's the extremely underwhelming pat-to-ascii.lua for Life Lexicon-type ASCII pattern format.

And there's change-random-isotropic-bit-v1.0.lua, also, for random-walk exploration of Hensel-notation isotropic rules.

There's not much else in that repo yet -- Python has been the usual script language choice, as you say.
User avatar
LuveelVoom
Posts: 679
Joined: April 27th, 2022, 7:59 pm

Re: Golly scripts written in Lua

Post by LuveelVoom »

Can I just say- as someone who has a broken golly-python link, this thread is AMAZING.
User avatar
confocaloid
Posts: 6697
Joined: February 8th, 2022, 3:15 pm
Location: learn to protect yourself against stray gliders and sparks and self-destruct mechanisms

Re: Golly scripts written in Lua

Post by confocaloid »

Crossposting an example script to switch to a pseudorandom 2-state isotropic CA with Moore neighbourhood, chosen from a hardcoded subspace
confocaloid wrote: December 15th, 2024, 1:15 am
confocaloid wrote: December 14th, 2024, 9:53 pm
  • The space is very large, and there are different subspaces. (B0, A0 B1c, A01c B1e, A01 B2a, A012a, ... ???) It is unclear whether to stay within a subspace (defined in some way or another), or to allow "jumping" between subspaces.
  • Different birth/survival conditions have significantly different consequences, even within the same subspace (defined in some way or another). How to assign probabilities?
LuveelVoom wrote: December 14th, 2024, 11:48 pm These are good points, do you know any way to randomly generate INT strings?
For Golly, the most universal solution is to write a script that will switch to a pseudorandom CA with desired properties. All the restrictions and probabilities can be adjusted within the script itself.

For example, I believe the following Golly Lua script will switch to a pseudorandom two-state isotropic CA with range-1 Moore neighbourhood, with the additional restriction that the CA must support the glider from Conway's Life.

You can adjust the restrictions in the code as needed.

Code: Select all

--------------------------------------------------------------------------------
local g = golly()
--------------------------------------------------------------------------------
local subconditions = { "0", "1c", "1e", "2a", "2c", "2e", "2i", "2k", "2n",
                        "3a", "3c", "3e", "3i", "3k", "3n", "3y", "3q", "3j", "3r",
                        "4a", "4c", "4e", "4i", "4k", "4n", "4y", "4q", "4j", "4r", "4t", "4w", "4z",
                        "5a", "5c", "5e", "5i", "5k", "5n", "5y", "5q", "5j", "5r",
                        "6a", "6c", "6e", "6i", "6k", "6n", "7c", "7e", "8" }
--------------------------------------------------------------------------------
-- Decide whether or not (c,s) should be included as a living condition.
-- c: the current state of the cell.
-- s: a string (either one or two characters) denoting the isotropic subcondition
--    on the current states of the Moore neighbours of the cell.
local function pr_should_be_a_living_condition(c, s)
    if (c == 0) and ((s == "0") or (s == "1c") or (s == "1e") or
                     (s == "2a") or (s == "2c") or (s == "2e") or
                     (s == "4r") or (s == "5n")) then
        -- (c, s) is a forbidden birth condition
        return false
    elseif (c == 1) and ((s == "1c") or (s == "1e") or (s == "4k")) then
        -- (c, s) is a forbidden survival condition
        return false
    elseif (c == 0) and ((s == "3a") or (s == "3i") or (s == "3j") or (s == "3n")) then
        -- (c, s) is a required birth condition
        return true
    elseif (c == 1) and ((s == "2a") or (s == "2e") or (s == "3j") or (s == "3n") or (s == "3r")) then
        -- (c, s) is a required survival condition
        return true
    else
        -- (c, s) is an optional living condition; pseudorandom choice
        return (math.random(1, 3) == 1)
    end
end
--------------------------------------------------------------------------------
-- Generate a pseudorandom set of conditions
-- for a state-c cell to be alive in the next generation.
-- The returned string doesn't need to be canonical.
local function pr_living_conditions(c)
    local result = ""
    for i = 1, #subconditions do
        s = subconditions[i]
        if pr_should_be_a_living_condition(c, s) then
            result = result .. s
        end
    end
    return result
end
--------------------------------------------------------------------------------
-- Switch to a pseudorandom CA
g.setrule("B" .. pr_living_conditions(0) .. "/S" .. pr_living_conditions(1))
--------------------------------------------------------------------------------
127:1 B3/S234c User:Confocal/R (isotropic CA, incomplete)
Unlikely events happen.
My silence does not imply agreement, nor indifference. If I disagreed with something in the past, then please do not construe my silence as something that could change that.
User avatar
dvgrn
Moderator
Posts: 12034
Joined: May 17th, 2009, 11:00 pm
Location: Madison, WI
Contact:

Re: Golly scripts written in Lua

Post by dvgrn »

dvgrn wrote: March 26th, 2025, 4:46 pm Should make a jls-to-lls.lua also -- jls-to-lls.py has definitely proved its worth with the p18 gun and several other recent projects.
Might as well fill the gap I mentioned:

Code: Select all

-- jls-to-lls.lua version 1.0 by Matthias Merzenich
-- (translated to Lua by ChatGPT 3.5, 26 March 2025)
-- This script converts JLS save files into LLS input files.

local g = golly

-- JLS cell states
local OFF, ON, EMPTY = 0, 1, 2
local UNCHECKED, UNSET = 6, 10
local FROZEN, UNCHECKED_FROZEN = 18, 22

-- Set subperiod_six_no_rule flag
local subperiod_six_no_rule = true

-- Function to extract curly brace array from a line
local function get_array(line, n)
    local arrays = {}
    for match in line:gmatch("{(.-)}") do
        table.insert(arrays, match)
    end
    return arrays[n + 1] and load("return {" .. arrays[n + 1] .. "}")()
end

-- Read JLS file
local function read_jls(filename)
    local file = io.open(filename, "r")
    if not file then error("Cannot open file: " .. filename) end
    
    local columns, rows, generations, subperiods, cell_rows, subperiod_array = 0, 0, 0, {}, {}, {}
    
    for line in file:lines() do
        if line:match("^columns=") then columns = tonumber(line:match("%d+")) end
        if line:match("^rows=") then rows = tonumber(line:match("%d+")) end
        if line:match("^generations=") then generations = tonumber(line:match("%d+")) end
        if line:match("^periods=") then subperiods = get_array(line, 0) end
        if line:match("^cells") then table.insert(cell_rows, get_array(line, 1)) end
        if line:match("^stacks") then table.insert(subperiod_array, get_array(line, 1)) end
        if line:match("^%[Search%]") then break end
    end
    file:close()
    
    return columns, rows, generations, subperiods, cell_rows, subperiod_array
end

local function convert_to_lls(columns, rows, generations, subperiods, cell_rows, subperiod_array)
    local cell_array, lls_array = {}, {}
    
    for gen = 1, generations do
        cell_array[gen] = {}
        for row = 1, rows do
            cell_array[gen][row] = cell_rows[(gen - 1) * rows + row]
        end
    end
    
    if subperiod_six_no_rule then subperiods[6] = generations end
    
    for gen = 1, generations do
        lls_array[gen] = {}
        for row = 1, rows do
            lls_array[gen][row] = {}
            for col = 1, columns do
                local the_cell = cell_array[gen][row][col]
                local subp = subperiod_array[row][col] % 8
                
                if the_cell == OFF then
                    lls_array[gen][row][col] = "0"
                elseif the_cell == ON then
                    lls_array[gen][row][col] = "1"
                elseif gen == 1 or the_cell == EMPTY or the_cell == UNCHECKED or the_cell == UNSET then
                    lls_array[gen][row][col] = "x" .. ((gen - 1) % subperiods[subp]) .. "-" .. (row - 1) .. "-" .. (col - 1)
                elseif the_cell == FROZEN or the_cell == UNCHECKED_FROZEN then
                    lls_array[gen][row][col] = lls_array[gen - 1][row][col]
                end
                
                if the_cell == UNCHECKED then
                    lls_array[gen][row][col] = lls_array[gen][row][col] .. "-uc" .. (gen - 1)
                end
                
                if the_cell == UNSET or (subperiod_six_no_rule and subp == 6) then
                    lls_array[gen][row][col] = lls_array[gen][row][col] .. "'"
                end
            end
        end
    end
    
    for row = 1, rows do
        for col = 1, columns do
            if cell_array[1][row][col] == FROZEN or cell_array[1][row][col] == UNCHECKED_FROZEN then
                lls_array[1][row][col] = lls_array[generations][row][col]
            end
        end
    end
    
    return lls_array
end

local function generate_output(lls_array, generations, rows, columns)
    local lls_output = ""
    local gen_zero = ""
    
    for gen = 1, generations do
        for row = 1, rows do
            for col = 1, columns do
                lls_output = lls_output .. lls_array[gen][row][col] .. ","
            end
            lls_output = lls_output .. "\n"
        end
        if gen == 1 then gen_zero = lls_output end
        lls_output = lls_output .. "\n"
    end
    
    lls_output = lls_output .. gen_zero
    return lls_output
end

local function main()
    local filename = g.opendialog("Select JLS save file", "*.jls", "")
    if not filename then return end
    
    local columns, rows, generations, subperiods, cell_rows, subperiod_array = read_jls(filename)
    local lls_array = convert_to_lls(columns, rows, generations, subperiods, cell_rows, subperiod_array)
    local output = generate_output(lls_array, generations, rows, columns)
    
    local out_filename = filename:gsub("%.jls$", ".lls")
    local out_file = io.open(out_filename, "w")
    out_file:write(output)
    out_file:close()
    
    g.note("Conversion completed. Output saved to " .. out_filename)
end

main()
This is a port of jls-to-lls.py version 1.0. It took me less than five minutes to ask ChatGPT for this, including writing this post.

As of this writing the Lua version is completely untested, and I don't have any time to give it a good trial right now. But I don't expect that to last long. If someone can do a sanity check, let me know via forum PM or Discord DM, and I'll update this note accordingly!
User avatar
confocaloid
Posts: 6697
Joined: February 8th, 2022, 3:15 pm
Location: learn to protect yourself against stray gliders and sparks and self-destruct mechanisms

Re: Golly scripts written in Lua

Post by confocaloid »

FWIW, speaking for myself, I wouldn't trust anything autoconverted, until and unless it is reviewed by a human person (which often means more work than would be needed to do it manually the old way).

Out of curiosity I tried to autoconvert several simple scripts from Python to Lua and (as expected) got incorrect and/or nonsensical results. It attempts to guess what I really meant, and neither guesses it correctly nor gives code that would be valid in case if I really meant what it "thinks" I meant.
dvgrn wrote: March 26th, 2025, 8:51 pm [...] It took me less than five minutes to ask ChatGPT for this, including writing this post.

As of this writing the Lua version is completely untested, and I don't have any time to give it a good trial right now. [...]
dvgrn wrote: March 26th, 2025, 4:46 pm Just in the last year or so we have a really helpful new tool [...]
127:1 B3/S234c User:Confocal/R (isotropic CA, incomplete)
Unlikely events happen.
My silence does not imply agreement, nor indifference. If I disagreed with something in the past, then please do not construe my silence as something that could change that.
User avatar
dvgrn
Moderator
Posts: 12034
Joined: May 17th, 2009, 11:00 pm
Location: Madison, WI
Contact:

Re: Golly scripts written in Lua

Post by dvgrn »

confocaloid wrote: March 28th, 2025, 2:46 pm FWIW, speaking for myself, I wouldn't trust anything autoconverted, until and unless it is reviewed by a human person ...
Yup, that's why I very carefully included the part about "If someone can do a sanity check, let me know via forum PM or Discord DM, and I'll update this note accordingly..."

That said, I've had a somewhat different experience with ChatGPT automatic Python-to-Lua ports -- especially very recently, as LLMs get better at this kind of thing.

I've had several scripts port over with zero issues, and several more scripts where the Lua version just needed a tiny and fairly obvious change -- basically, run the code, see an error, fix the error, run it again and it works absolutely 100% fine after that.

The shorter the Python script is, the more likely the port is to work out well -- and if the Python script is doing very standard string manipulation (like jls-to-lls.lua is) and not something trickier with libraries (such as would be involved in an apgsearch port, for example) then the odds of success go up a lot.

I've been estimating that ChatGPT recently has been saving me well over 90% of the time I would otherwise have spent on re-coding various things in Lua. It's a really significant time savings, and so far hasn't resulted in any subtle bugs being introduced (that I know of, of course).

Maybe a Lua Conversion Request Thread?
Might it be worth separating out requests for Python scripts to be ported to Lua, into a separate thread linked from the top of this thread?

Then candidate ported Lua code could be posted in the other thread, and testing could be documented there -- and just a link or a final copy could be posted here in the Lua-script collection thread.

(?)
User avatar
confocaloid
Posts: 6697
Joined: February 8th, 2022, 3:15 pm
Location: learn to protect yourself against stray gliders and sparks and self-destruct mechanisms

Re: Golly scripts written in Lua

Post by confocaloid »

This is an old script to evolve the pattern until the selected part repeats exactly. It can be useful when working with predictable constructed patterns, not limited to oscillators or spaceships.

Select some region of interest, run the script, and it will evolve the pattern and either stop automatically when all cells in the selected region return to their initial states, or will run until interrupted via the escape key.
gorepeat.lua wrote:

Code: Select all

-- Evolve the pattern until the selected part repeats exactly.

--------------------------------------------------------------------------------

SCRIPT_NAME = "gorepeat.lua"

local g = golly()

--------------------------------------------------------------------------------

local function cell2key(x, y, v)
    return string.format("%q:%q:%q", x, y, v)
end

--------------------------------------------------------------------------------

local function cells2pat(cells)
    local epc = 2 + (#cells % 2)
    local nc = #cells // epc
    local ans = {}
    for i = 0, nc - 1 do
        local x = cells[epc * i + 1]
        local y = cells[epc * i + 2]
        local v = 1
        if epc == 3 then
            v = cells[epc * i + 3]
        end
        local key = cell2key(x, y, v)
        table.insert(ans, key)
    end
    table.sort(ans)
    return ans
end

--------------------------------------------------------------------------------

local function pat_equal(pat1, pat2)
    if #pat1 ~= #pat2 then
        return false
    end
    for i = 1, #pat1 do
        if pat1[i] ~= pat2[i] then
            return false
        end
    end
    return true
end

--------------------------------------------------------------------------------

local function ticks_per_step()
   local base = g.getbase()
   local step = g.getstep()
   local ans = 1
   while step > 0 do
       ans = ans * base
       step = step - 1
   end
   return ans
end

--------------------------------------------------------------------------------

local function mainfun()
   local sel_rect = g.getselrect()
   if #sel_rect == 0 then
       g.show("No selection.")
       return
   end
   local sel_cells = g.getcells(sel_rect)
   local pat_expected = cells2pat(sel_cells)
   local n_steps = 0
   g.show(string.format("[%s] evolving in %q-tick steps until the selected region repeats (press escape key to abort)...",
       SCRIPT_NAME, ticks_per_step()))
   repeat
       g.step()
       n_steps = n_steps + 1
       sel_cells = g.getcells(sel_rect)
       local pat_actual = cells2pat(sel_cells)
   until pat_equal(pat_expected, pat_actual)
   g.show("OK (" .. n_steps .. " steps, " .. n_steps * ticks_per_step() .. " ticks)")
end

--------------------------------------------------------------------------------

mainfun()
As a demo, open the following pattern in Golly, evolve it to generation 650 (for example using Scripts/Lua/goto.lua), then select a small region containing the escaped glider and nothing else, and then run the script gorepeat.lua a few times and see what happens.

Code: Select all

#N Sqrtgun 3.0
#C https://conwaylife.com/ref/DRH/sqrtgun3.0.html
#C Population in generation t is asymptotic to  5 sqrt(t/12).  A 4-glider
#C salvo pushes a blinker 3 units southeast and sends back a glider,
#C which causes another salvo to be fired and a glider to be sent
#C northeast.  The round trip time, and hence the gap between
#C northeastward gliders, increases by an average of 24 generations each
#C time.  More specifically, let a[0]=207, a[1]=159, a[2]=-33, a[3]=111,
#C and a[4]=231.  For n>=0, a glider is sent northeast (by reflection from
#C a buckaroo) in generation  12 n^2 + 1116 n + a[n mod 5]  (at which
#C time, for n>=1, the population is  5n + 1297)  and escapes about 300
#C generations later.
#O Dean Hickerson, <...>  1/28/1991
x = 176, y = 170, rule = B3/S23
46b2o$46bo6$37b2o24b2o$37bo25bo$28b2o5bobo5b2o3b2o$27bobo5b2o6bo5bo$
12bobo11bo$12bo2bo10bo2bo14bo3bo15bo$15b2o9bo18b3o15bobo$3b2o8bo3b2o8b
obo6b2o24bo3bo$3bo11b2o11b2o6bo2bo23b3o$12bo2bo45b2o3b2o$12bobo21bo2bo
$35bo2bo$35bobo$36bo2$36b2o$36bo$44bo$8bo34b3o$6b4o32b5o$2o5bob2o13bob
o14b2o3b2o$o4bobob3o12bo3bo13b5o$7bob2o17bo13bo3bo47b2o$6b4o19bo14bo
18b2o3b2o26bo$8bo19bo34b2o3b2o13b2o12bo$24bo3bo3b2o12b2o8bo7b5o14bo13b
o13b2o$24bobo5bobo11bo8bo9bobo12b2o15bo11bo2bo$34bo12b3o5b3o14b2o5b3o
14bo11bo15bobo$34b2o13bo15b3o4bo7b2o12b2o12bo15bo3bo$83bo24bo19bo$83b
2o24bo2bo16bo4b2o$23b2o86b2o15bo5bo$23bo100bo3bo$78b2o9b2o33bobo$65b2o
10bo2bo7bo2bo$37bo27bo11b3o2b5o2b3o$37b3o40b2o5b2o$40bo38bo9bo$39b2o
38b2obo3bob2o$84bo4$21b2o3b2o14bo$23b3o15b3o55b2o21b2o$22bo3bo14b3o55b
o22bo$23bobo86bo7bobo$24bo14b2o3b2o33bobo30b4o4b2o$39bo5bo32bo20b2o12b
4o$74bo2bo4bo15bobo12bo2bo$73b2obo2bob2o5b2o7b3o13b4o$77b2o9bo7b3o13b
4o$21b3o73b3o12bo$98bobo$21bobo15b2o58b2o$20b5o15bo$19b2o3b2o11b3o$19b
2o3b2o11bo3$47b2o$47bo3$47bo72bo$21b2o23b2obo68bobo$21bo27bo66b2o18b2o
$34b2o13bo66b2o17bo$34bo11bo2bo66b2o16bo$21bobo23b2o49bo13b2o4bobo13bo
9b2o$21bo3bo70b3o12bobo6bo13bo9bo$11b2o12bo10b2o57bo15bo23bo$11bo14bo
7bo2bo57b2o13b2o24b2o$25bo7bo11b2o$21bo3bo7bo11bo98b2o$21bobo9bo110bo$
34bo2bo86bo$36b2o79bo5bobo28b2o$117bobo4bo29bo$41bo75b2o$39bobo125b2o$
29b2o6b2o12b2o92bo21bo$28bo3bo4b2o12bo92b3o7bo$27bo5bo3b2o105b3o6bobo$
17b2o8bo3bob2o4bobo110bo3bo$17bo9bo5bo7bo100b2o3b2o4b3o$28bo3bo109bo5b
o2b2o3b2o$29b2o$54b2o$53bo2bo108b2o3b2o$56bo108bo5bo$28b2o26bo$28bo24b
2obo109bo3bo$54bo112b3o3$54b2o$55bo2$140b2o3b2o$149b2o3b2o$26b2o3b2o
94b3o11bo3bo3b2o3b2o$27b5o3b2o92bo12b3o5b5o$27b2ob2o4b2o90bo13b3o6bobo
$27b2ob2o3bo134bo$28b3o10b2o108b3o15b3o$41bo126b5o$87bo70bo8b2o3b2o$
80b2o5bobo15b2o36b2o12bo10b5o$80bo6b2o16bo37bo5b2o6b3o8bo3bo$30b3o39bo
5bobo69bo19bo$30b3o39bobo3b2o67b3o$29bo3bo39bobo28b3o40bo15b2o7b2o$28b
o5bo38bo2bo27b2o34bo18b4o4b2o3bo$29bo3bo5b2o3b2o27bobo31b2o27b2o2b2ob
3o13b3ob2o2bo5b3o$30b3o6bo5bo15b2o9bobo31b3o27bo5b4o18bo10bo$60bobo9bo
32bobo32b2o$40bo3bo15bo44b2o$41b3o15b2o6$39b2o51bo$31b2o7bo49b3o$31bo
5b3o49bo$37bo51b2o3$86b3o$86b3o8b3o$85bo3bo9bo$98bo$84b2o3b2o2$48bo$
47bobo47bo30bo$40b2o4bob2o46bobo28bo15b3o$40bo4b2ob2o47bo29b3o$46bob2o
$47bobo9b2o$48bo10bobo$61bo$61b2o4$88b3o$87bo3bo$86bo5bo$86bo5bo3$127b
o$126bobo$114bobo8bob2o$114bo2bo6b2ob2o10b2o$89b2o14b2o10b2o6bob2o10bo
$89bo15bo9bo3b2o5bobo$117b2o8bo$114bo2bo$114bobo!
127:1 B3/S234c User:Confocal/R (isotropic CA, incomplete)
Unlikely events happen.
My silence does not imply agreement, nor indifference. If I disagreed with something in the past, then please do not construe my silence as something that could change that.
User avatar
confocaloid
Posts: 6697
Joined: February 8th, 2022, 3:15 pm
Location: learn to protect yourself against stray gliders and sparks and self-destruct mechanisms

Re: Golly scripts written in Lua

Post by confocaloid »

CARuler wrote: April 26th, 2025, 9:24 pm I have finally done it after literally only two days of which the combined time spent amounts to a few hours, I have created an arbitrarily nested SMOSMOS...MOS :
[...]
also, can someone make a script to nest these
[...]
I suggest to rename the RuleLoader file to follow existing conventions. (The filename should begin with a capital letter; only use letters and digits; if you need separators then hyphens or underscores are allowed for that purpose.)
Your current filename is problematic because of three dots in the name.

In the script below, I changed to the filename 'RecursiveSpaceship' for concreteness (there is likely something better), and I appended a copy of the RuleLoader file (the version I assumed in the script) with name changed accordingly.

EDIT by dvgrn: At CARuler's request, I've edited in "ArbitrarilyNestedSMOS" as the rule name in place of "RecursiveSpaceship".

Here is the script (Golly/Lua):

Code: Select all

local g = golly()

local SCRIPT_FILE_NAME     = 'make-arbitrarily-nested-SMOS.lua'
local RULELOADER_FILE_NAME = 'ArbitrarilyNestedSMOS'
local c29o = {-4, 9, 1, 0, 9, 2, 4, 9, 1, -4, 10, 1, 0, 10, 1, 4, 10, 1, 0}

local function integer_power_of_2(n)
    local x = 1
    for i = 1, n do x = x + x end
    return x
end

local function build(level)
    if level > 0 then
        local part0 = build(level - 1)
        if level > 1 then
            part0 = g.transform(part0, 0, 17 * integer_power_of_2(level - 2))
        end
        local part1 = g.transform(part0, 0, 0, 0, -1, 1, 0)
        local part2 = g.transform(part0, 0, 0, 0, 1, -1, 0)
        return g.join(part0, g.join(part1, part2))
    else
        return c29o
    end
end

local function guess_the_period(level)
    return integer_power_of_2(6 + level) + integer_power_of_2(2 + level) - 39 - 15 * level
end

local function main()
    local level = math.tointeger(g.getstring('Level (nonnegative integer):', '4', SCRIPT_FILE_NAME))
    if level and (level >= 0) then
        local period = guess_the_period(level)
        g.new(string.format('p%q orthogonal c/%q spaceship, level %q, generated using %s',
            period, period, level, SCRIPT_FILE_NAME))
        g.setrule(RULELOADER_FILE_NAME)
        g.putcells(build(level))
        g.fit()
    else
        g.show('Invalid input')
    end
end

main()
Here is the version of the .rule file which I assumed in the script.
The file is renamed to follow existing naming conventions.

Code: Select all

@RULE ArbitrarilyNestedSMOS

"an arbitrarily nested SMOSMOS...MOS" by CARuler
Source: https://conwaylife.com/forums/viewtopic.php?p=210710#p210710

@TABLE
n_states:27
neighborhood:Moore
symmetries:rotate4reflect
var a = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26}
var b = a
var c = a
var d = a
var e = a
var f = a
var g = a
var h = a
var i = {9,10,11,12,13}
0,2,1,0,0,0,0,0,0,3
2,1,0,0,0,0,0,0,0,4
0,3,0,0,0,0,0,0,0,3
0,8,0,0,0,0,0,0,0,8
0,1,1,0,0,3,0,0,0,5
0,1,1,0,3,0,0,0,0,6
6,1,1,5,4,0,0,0,0,6
5,1,1,6,0,4,0,0,0,5
0,0,5,0,0,0,0,0,0,5
0,5,1,0,0,0,0,0,0,6
0,5,6,0,0,0,0,0,0,6
5,1,1,6,0,0,0,0,0,0
5,6,0,6,0,0,0,0,0,0
0,5,6,0,6,5,0,0,0,2
2,0,6,0,6,0,0,0,0,4
0,6,0,2,0,6,0,0,0,9
6,0,2,0,0,0,0,0,0,2
0,0,2,9,2,0,0,0,0,10
0,0,2,10,2,0,0,0,0,11
0,0,2,11,2,0,0,0,0,12
0,0,2,12,2,0,0,0,0,13
4,0,2,0,2,0,0,0,0,8
0,2,0,4,0,2,0,0,0,4
0,8,0,0,0,1,0,0,0,8
0,0,4,8,1,0,0,0,0,8
8,4,0,0,0,1,0,0,0,8
8,8,0,1,0,8,0,0,0,8
8,4,0,1,0,4,0,0,0,9
0,1,1,0,0,8,0,0,0,7
0,9,1,0,0,4,0,0,0,10
13,13,0,1,0,13,0,0,0,1
1,0,13,13,13,0,0,0,0,0
0,0,13,13,13,0,0,0,0,2
0,1,7,0,0,0,0,0,0,1
1,1,7,0,0,0,0,0,0,0
0,0,13,2,0,2,13,0,0,15
0,15,0,4,0,15,0,0,0,2
15,0,4,0,0,0,4,0,0,16
4,0,15,0,15,0,0,0,0,4
0,17,0,0,0,0,0,0,0,17
0,0,16,2,16,0,0,0,0,14
4,0,16,2,16,0,0,0,0,17
0,14,0,16,0,0,0,0,0,14
14,0,16,0,16,0,0,0,0,14
0,0,14,14,14,0,0,0,0,14
14,14,0,16,0,0,0,0,0,14
14,0,14,0,14,0,0,0,0,14
14,16,0,0,14,0,0,0,0,14
0,14,0,14,16,0,16,14,0,4
4,14,0,14,16,0,16,14,0,14
14,14,4,14,0,0,0,0,0,14
14,0,14,4,14,0,0,0,0,14
0,14,4,14,0,0,0,0,0,14
14,14,14,0,0,0,0,0,0,14
14,0,14,0,0,0,0,0,0,14
0,14,0,14,0,14,0,0,0,4
4,14,0,14,0,14,0,0,0,14
0,17,0,0,0,1,0,0,0,17
17,4,0,0,0,1,0,0,0,17
0,17,0,0,16,0,16,0,0,17
0,16,0,17,0,16,0,0,0,17
0,0,16,17,16,0,0,0,0,17
0,17,0,0,14,4,14,0,0,17
14,17,0,0,14,14,14,0,0,17
0,14,0,14,0,14,0,17,0,8
8,14,0,0,0,4,0,0,0,8
14,8,0,0,0,0,0,0,0,4
0,8,0,0,16,0,16,0,0,8
8,4,0,0,16,0,16,0,0,18
16,0,8,0,0,0,0,0,0,0
0,8,0,16,0,0,0,0,4,21
0,16,0,8,0,16,0,0,0,8
0,21,18,0,0,0,0,0,0,4
0,21,0,0,0,0,0,0,0,21
14,0,14,0,17,0,0,0,0,2
0,2,8,14,0,0,0,0,0,6
8,14,0,2,0,4,0,2,0,2
0,23,0,0,0,0,0,0,0,23
0,24,0,0,0,0,0,0,0,24
0,4,4,21,0,0,0,0,0,4
0,4,4,22,0,0,0,0,0,4
18,4,0,4,4,0,4,4,0,0
0,1,0,0,0,21,0,0,0,21
21,4,4,0,0,1,0,0,0,21
0,4,4,21,1,0,0,0,0,23
0,0,4,21,1,0,0,0,0,24
0,23,0,0,0,0,0,0,0,23
0,24,0,0,0,0,0,0,0,24
21,24,0,1,0,23,0,0,0,21
0,1,1,0,0,23,0,0,0,23
0,1,1,0,23,0,0,0,0,23
1,1,23,23,0,0,0,0,0,23
0,23,23,0,0,0,0,0,0,1
0,1,1,0,0,24,0,0,0,24
0,1,1,0,24,0,0,0,0,24
1,1,24,24,0,0,0,0,0,0
24,1,1,24,4,0,0,0,0,1
24,1,1,24,0,4,0,0,0,1
0,1,21,4,23,0,0,0,0,25
1,25,0,4,0,0,0,0,0,0
4,1,25,0,0,0,0,0,0,4
0,4,1,25,0,4,0,0,0,10
4,13,1,0,0,0,0,0,0,0
13,1,0,4,0,0,0,0,0,2
14,0,2,8,2,0,0,0,0,14
0,6,14,0,0,0,0,0,0,6
14,6,0,2,0,6,0,0,0,2
14,14,16,0,16,14,0,0,0,6
14,0,14,6,14,0,0,0,0,5
0,14,6,14,0,0,0,0,0,14
5,14,0,0,0,14,0,0,0,4
0,14,5,0,0,0,0,0,0,14
0,0,14,5,14,0,0,0,0,3
14,3,4,0,0,0,0,0,0,14
0,0,14,3,14,0,0,0,0,14
0,21,0,0,16,0,16,0,0,19
0,16,0,19,0,16,0,0,0,21
0,16,0,19,4,0,0,0,0,8
0,16,0,19,4,4,0,0,0,26
16,0,19,0,0,0,0,0,0,0
19,4,4,0,16,0,16,0,0,4
0,26,0,0,0,0,0,0,0,26
0,26,4,21,0,0,0,0,0,4
0,1,0,0,0,26,0,0,0,26
0,1,26,0,0,0,0,0,0,8
26,1,0,0,0,4,0,0,0,6
6,0,8,1,8,0,0,0,0,6
0,0,8,1,8,0,0,0,0,1
1,6,0,4,0,1,0,4,0,9
13,1,0,0,0,6,0,0,0,2
6,0,4,1,4,0,0,0,0,6
6,13,0,0,0,0,0,0,0,0
0,26,0,0,16,0,16,0,0,20
16,0,20,0,0,0,0,0,0,0
0,16,0,20,0,16,0,0,0,26
20,4,0,0,16,0,16,0,0,4
0,16,0,20,4,0,0,0,0,21

#default-like
6,i,0,0,0,0,0,0,0,6
4,i,1,0,0,0,0,0,0,4
0,2,i,0,0,0,0,0,0,2
i,2,0,4,0,2,0,0,0,4
#defaults
2,a,b,c,d,e,f,g,h,0
3,a,b,c,d,e,f,g,h,4
4,a,b,c,d,e,f,g,h,0
5,a,b,c,d,e,f,g,h,6
6,a,b,c,d,e,f,g,h,0
7,a,b,c,d,e,f,g,h,0
8,a,b,c,d,e,f,g,h,4
9,a,b,c,d,e,f,g,h,10
10,a,b,c,d,e,f,g,h,11
11,a,b,c,d,e,f,g,h,12
12,a,b,c,d,e,f,g,h,13
13,a,b,c,d,e,f,g,h,0
14,a,b,c,d,e,f,g,h,0
15,a,b,c,d,e,f,g,h,0
17,a,b,c,d,e,f,g,h,4
22,a,b,c,d,e,f,g,h,4
21,a,b,c,d,e,f,g,h,4
23,a,b,c,d,e,f,g,h,4
24,a,b,c,d,e,f,g,h,4
25,a,b,c,d,e,f,g,h,1
26,a,b,c,d,e,f,g,h,4
@COLORS
0   0   0   0
1 128 128 128
2   0 255   0
3 255   0   0
4   0   0 255
5 255 255   0
6 255   0 255
7   0 255 255
8 255 255 255
9 255 128 255
10 255 128 192
11 255 128 128
12 255 128  64
13 255 128   0
14 148   0 255
15 255   0 148
16   0 255 148
17 255 148 125
18 148 148  64
19 148  64 148
20  64 148 148
21  64  42  20
22 128  84  40
23 192 126  60
24 255 168  80
25 128  64 200
26  64  64 128
127:1 B3/S234c User:Confocal/R (isotropic CA, incomplete)
Unlikely events happen.
My silence does not imply agreement, nor indifference. If I disagreed with something in the past, then please do not construe my silence as something that could change that.
Post Reply