Golly suggestions

For general discussion about Conway's Game of Life.
User avatar
GUYTU6J
Posts: 1949
Joined: August 5th, 2016, 10:27 am
Location: 拆哪!I repeat, CHINA! (a.k.a. 种花家)
Contact:

Re: Golly suggestions

Post by GUYTU6J » August 17th, 2022, 11:54 pm

Andrew wrote:
August 17th, 2022, 11:34 pm
GUYTU6J wrote:
August 15th, 2022, 9:20 am
This commit says it "updated patterns used by web version of Golly", but the collection on http://golly.sourceforge.net/webapp/golly.html hasn't been expanded.
I've just uploaded a new version of webGolly that contains all your suggested pattern changes. You'll probably need to force the page to be reloaded, which might take a while, so be patient. Eventually you should see this message in the status bar:

This is Golly 4.2 for the web (copyright 2005-2022 The Golly Gang).
Update confirmed. Thank you! But zooming in or out the canvas with mouse wheel (laptop) or two fingers (mobile) seems to be not supported.
Why do most 2-state OCA rules tend to get a diminishing span of interest and go into oblivion, like lost civilizations leaving little records for their beauty and power?

Here multiflorate splendour blooms forlorn
Midst broken fountains, mouldering walls.

User avatar
Andrew
Moderator
Posts: 878
Joined: June 2nd, 2009, 2:08 am
Location: Melbourne, Australia
Contact:

Re: Golly suggestions

Post by Andrew » August 18th, 2022, 5:48 am

GUYTU6J wrote:
August 17th, 2022, 11:54 pm
Update confirmed. Thank you! But zooming in or out the canvas with mouse wheel (laptop) or two fingers (mobile) seems to be not supported.
I've uploaded a new build that should fix this (works on Safari and Chrome on my Mac).

User avatar
GUYTU6J
Posts: 1949
Joined: August 5th, 2016, 10:27 am
Location: 拆哪!I repeat, CHINA! (a.k.a. 种花家)
Contact:

Re: Golly suggestions

Post by GUYTU6J » August 20th, 2022, 11:49 pm

In a modified but not saved layer marked with *, open Life/Signal-Circuitry/h-to-h-collection-26Aug2017.zip, then click "cancel" in the "save changes" dialog. The package contains a pattern RLE and a lua script for poping up a window; despite the former not being loaded on the layer, the latter will still pop up.

I am not sure if it is caused by Golly or by the h-to-h-collection-21Aug2017.lua script within the package. The script boils down to

Code: Select all

local g = golly()

htmlname = g.getdir("temp").."h-to-h-collection-21Aug2017.html"
f = io.open(htmlname, "w")
if f then
    f:write(
[[
<html>
...
</html>
]]
    )
    f:close()
end
g.open(htmlname)
Why do most 2-state OCA rules tend to get a diminishing span of interest and go into oblivion, like lost civilizations leaving little records for their beauty and power?

Here multiflorate splendour blooms forlorn
Midst broken fountains, mouldering walls.

User avatar
Andrew
Moderator
Posts: 878
Joined: June 2nd, 2009, 2:08 am
Location: Melbourne, Australia
Contact:

Re: Golly suggestions

Post by Andrew » August 21st, 2022, 12:39 am

GUYTU6J wrote:
August 20th, 2022, 11:49 pm
In a modified but not saved layer marked with *, open Life/Signal-Circuitry/h-to-h-collection-26Aug2017.zip, then click "cancel" in the "save changes" dialog. The package contains a pattern RLE and a lua script for poping up a window; despite the former not being loaded on the layer, the latter will still pop up.
I don't think it's worth changing Golly's code to detect this (uncommon) situation. It would be quite easy to modify the script to do nothing if the file wasn't loaded. Something like this (untested!):

Code: Select all

if not g.getpath():find("h-to-h-collection-26Aug2017.rle",1,true) then g.exit() end

User avatar
Macbi
Posts: 882
Joined: March 29th, 2009, 4:58 am

Re: Golly suggestions

Post by Macbi » September 4th, 2022, 12:58 pm

On Linux, could we stop using the user's home directory for ~/.golly? The new consensus for dotfile locations seems to be the freedesktop.org standard. So the 'proper' place for GollyPrefs would be $XDG_CONFIG_HOME (which by default is ~/.config), while the user's Rules and Downloads would go in $XDG_DATA_HOME/golly (which by default is ~/.local/share/golly).

confocaloid
Posts: 303
Joined: February 8th, 2022, 3:15 pm

Re: Golly suggestions

Post by confocaloid » September 4th, 2022, 8:03 pm

A request for two related features. This is also related to files/directories. I may attempt to clarify any missing details later if needed, assuming this feature request will not happen outright unreasonable.
  • (Feature 1) For an arbitrary rule supported by RuleLoader, allow the user to store the rule definition in the same file as the pattern that uses the rule (rather than putting the rule definition in a separate file). More specifically, I think one way would be the same way as LifeViewer does it (i.e. by appending the rule definition to the end of the RLE).
  • (Feature 2) Provide a programmatic way to construct and use in a pattern an arbitrary RuleLoader-supported rule from a Golly script, without storing the rule in a file. (Note: this feature request is about programmatically building/generating a completely new rule from scratch, as opposed to modifying/mutating an already existing rule.)
Interactions between features (assuming both implemented):
  • When (2) is used to construct a rule dynamically and switch to it, a subsequent "File -> Save pattern..." should follow (1) by writing the rule definition to the same file as the pattern (rather than asking the user to provide two different filenames for the pattern and the rule) .
Several use cases:
  • (a) A multistate rule may be specifically designed for a single use in a specific pattern, without having any particularly "interesting" features otherwise. Several examples can be found in this thread. Having to invent names for such one-time rules and store them in separate files seems an inconvenience.
  • (b) I would like to write a script to generate and test random rules, without storing each rule in a file. Probably the script will be invoked many times, possibly with some user input to configure it. Each time the script is invoked, a new random rule is generated and the current pattern is set to use the rule. If given a choice, I would certainly prefer to avoid cluttering my rule directory by lots of rule files with autogenerated filenames, most of which will never be used again.
In this use case, feature (2) is needed to be able to generate and use rules from a script without forcing the user to save each of them in a file, and feature (1) is needed to allow the user to save any found "potentially interesting" rules - along with example soups/patterns for those rules - without having to pause and think to invent meaningful names for those rules.
  • (c) Write a script that dynamically generates both the pattern and the rule to be used in this pattern. In this use case, the only thing stored in a file is the script itself - neither the pattern nor the rule is stored. Again, there may be user input to the script, potentially affecting both the pattern and the rule.
  • (d) Compatibility with LifeViewer. If feature (1) is implemented in the same way (from the user's viewpoint) as LifeViewer does it, it would be possible to copy-and-paste a RLE with an appended rule definition into a single file and open it by Golly.
Is there any hope of seeing something along these lines implemented in Golly? I think these features would become useful, if implemented. Are there any important missing details to be clarified in this feature request?

User avatar
dvgrn
Moderator
Posts: 9135
Joined: May 17th, 2009, 11:00 pm
Location: Madison, WI
Contact:

Re: Golly suggestions

Post by dvgrn » September 4th, 2022, 10:08 pm

confocaloid wrote:
September 4th, 2022, 8:03 pm
...
  • (d) Compatibility with LifeViewer. If feature (1) is implemented in the same way (from the user's viewpoint) as LifeViewer does it, it would be possible to copy-and-paste a RLE with an appended rule definition into a single file and open it by Golly.
Is there any hope of seeing something along these lines implemented in Golly? I think these features would become useful, if implemented. Are there any important missing details to be clarified in this feature request?
Feature (1) does seem to me to be worth considering, just to get Golly and LifeViewer supporting the same pattern+rule format.

Personally I'm not convinced that feature (2) is an interesting thing to build in to Golly. If you care about not cluttering up your Rules folder, then you can just name all your rules "TempRule_{identifer}", and write a script that finds and deletes all TempRule_* rules (and run that on startup, or whenever you want). And/or go to File > Preferences > Control, change the "Your Rules" folder to where you're temporarily generating rules -- and then delete the whole folder when you're done.

Then again, I'm not somebody that you really need to convince, since I'm not likely to be the one to implement either of these features in any case!

It seems to me that it would be a somewhat tricky change to Golly's architecture to require that it not save a rule-table file anywhere. Golly saves a lot of temporary files -- Undo buffers and so on -- and cleans them up when they're no longer needed. The Python and Lua scripting systems completely allow you to implement both Feature 1 and Feature 2 yourself, with no changes to Golly needed -- as long as you can let go of the idea that a rule should never be saved to disk at all, as opposed to being saved temporarily and then deleted later.

User avatar
GUYTU6J
Posts: 1949
Joined: August 5th, 2016, 10:27 am
Location: 拆哪!I repeat, CHINA! (a.k.a. 种花家)
Contact:

Re: Golly suggestions

Post by GUYTU6J » September 22nd, 2022, 12:37 am

Algorithms except for QuickLife and Larger than Life support timelines, but no script command to operate on timelines exists. So I'd request for the relevant python and lua functions, particularly the ability to go to a specific generation (which may be forwards or backwards) within the record.
Why do most 2-state OCA rules tend to get a diminishing span of interest and go into oblivion, like lost civilizations leaving little records for their beauty and power?

Here multiflorate splendour blooms forlorn
Midst broken fountains, mouldering walls.

User avatar
Andrew
Moderator
Posts: 878
Joined: June 2nd, 2009, 2:08 am
Location: Melbourne, Australia
Contact:

Re: Golly suggestions

Post by Andrew » September 22nd, 2022, 7:08 pm

GUYTU6J wrote:
September 22nd, 2022, 12:37 am
Algorithms except for QuickLife and Larger than Life support timelines, but no script command to operate on timelines exists. So I'd request for the relevant python and lua functions, particularly the ability to go to a specific generation (which may be forwards or backwards) within the record.
A better idea would be to write an overlay script called timeline.lua that emulates (and improves on) the current timeline code. It would work in all algorithms, could record at variable step sizes, have a "Go To ..." button, etc. A nice little project for anyone interested in learning how to write an overlay script.

User avatar
GUYTU6J
Posts: 1949
Joined: August 5th, 2016, 10:27 am
Location: 拆哪!I repeat, CHINA! (a.k.a. 种花家)
Contact:

Re: Golly suggestions

Post by GUYTU6J » September 25th, 2022, 9:44 am

Andrew wrote:
September 22nd, 2022, 7:08 pm
GUYTU6J wrote:
September 22nd, 2022, 12:37 am
Algorithms except for QuickLife and Larger than Life support timelines, but no script command to operate on timelines exists. So I'd request for the relevant python and lua functions, particularly the ability to go to a specific generation (which may be forwards or backwards) within the record.
A better idea would be to write an overlay script called timeline.lua that emulates (and improves on) the current timeline code. It would work in all algorithms, could record at variable step sizes, have a "Go To ..." button, etc. A nice little project for anyone interested in learning how to write an overlay script.
Maybe, but is there a convenient single command to go to a particular previous generation in lua overlay? I can see none in Golly Help.

For the record, the relevant part in goto.lua is

Code: Select all

    if newgen < currgen then
        -- try to go back to starting gen (not necessarily 0) and
        -- then forwards to newgen; note that reset() also restores
        -- algorithm and/or rule, so too bad if user changed those
        -- after the starting info was saved;
        -- first save current location and scale
        local midx, midy = g.getpos()
        local mag = g.getmag()
        g.reset()
        -- restore location and scale
        g.setpos(midx, midy)
        g.setmag(mag)
which is unsatisfactory. Assuming no edits after T=0 and same step size, going from T=10000 to T=9999 takes more time than going from T=10 to T=9 in this reset-then-play scheme, despite both essentially being one generation backwards.

Timelines do not (at least seem to me) have this issue. Once recorded, it is only a mouse click on the "<" button of the scroll bar to go to the previous step (not necesarrily 1 tick) in the timeline regardless of the T count. What I am requesting is a one-line script command that replaces one or more such clicks of my finger.
Why do most 2-state OCA rules tend to get a diminishing span of interest and go into oblivion, like lost civilizations leaving little records for their beauty and power?

Here multiflorate splendour blooms forlorn
Midst broken fountains, mouldering walls.

User avatar
Andrew
Moderator
Posts: 878
Joined: June 2nd, 2009, 2:08 am
Location: Melbourne, Australia
Contact:

Re: Golly suggestions

Post by Andrew » September 27th, 2022, 12:21 am

GUYTU6J wrote:
September 25th, 2022, 9:44 am
Maybe, but is there a convenient single command to go to a particular previous generation in lua overlay?
No. I think it's worth pointing out that Golly is in a somewhat unusual state while a timeline exists. Note that you can't do any editing or change the algo/rule or run the pattern. You also can't run a script, so adding new script commands to control timeline functions would require a lot of messy changes. Certainly not something I'm ever likely to attempt.
Timelines do not (at least seem to me) have this issue. Once recorded, it is only a mouse click on the "<" button of the scroll bar to go to the previous step (not necesarrily 1 tick) in the timeline regardless of the T count. What I am requesting is a one-line script command that replaces one or more such clicks of my finger.
I'm a bit confused by this request. Given that it's easy to go to any step in the timeline, why do you want a script command to do it? Maybe provide more details about what sort of script you want to write.

User avatar
GUYTU6J
Posts: 1949
Joined: August 5th, 2016, 10:27 am
Location: 拆哪!I repeat, CHINA! (a.k.a. 种花家)
Contact:

Re: Golly suggestions

Post by GUYTU6J » September 27th, 2022, 12:55 am

Andrew wrote:
September 27th, 2022, 12:21 am
...
I'm a bit confused by this request. Given that it's easy to go to any step in the timeline, why do you want a script command to do it? Maybe provide more details about what sort of script you want to write.
The script I am envisioning is a Seeds of Destruction emulator mentioned previously, intended to be used on any Golly-compatible rule. One of its features is the Gens button: hover mouse over it and "mousewheel to change number of generations", which evolves the pattern forwards or backwards. The closest effect in Golly happens upon clicking on the "<" or ">" buttons in a timeline. So to reproduce this, I need a single script command as stated (but not necessarily mapped to mouse wheel in actual program).

Without timelines, either the reset-then-play scheme or a save-all-intermediate-generations-to-files-for-arbitrary-inspection method would be inefficient, and I have no other idea for implementation of said feature.
Why do most 2-state OCA rules tend to get a diminishing span of interest and go into oblivion, like lost civilizations leaving little records for their beauty and power?

Here multiflorate splendour blooms forlorn
Midst broken fountains, mouldering walls.

User avatar
Andrew
Moderator
Posts: 878
Joined: June 2nd, 2009, 2:08 am
Location: Melbourne, Australia
Contact:

Re: Golly suggestions

Post by Andrew » September 27th, 2022, 4:43 am

GUYTU6J wrote:
September 27th, 2022, 12:55 am
Without timelines, either the reset-then-play scheme or a save-all-intermediate-generations-to-files-for-arbitrary-inspection method would be inefficient, and I have no other idea for implementation of said feature.
I've never used Seeds of Destruction but it looks like it operates on fairly small patterns, so unless you want to manipulate patterns with millions of cells then I'm pretty sure either of those schemes would work just fine.

User avatar
Andrew
Moderator
Posts: 878
Joined: June 2nd, 2009, 2:08 am
Location: Melbourne, Australia
Contact:

Re: Golly suggestions

Post by Andrew » September 27th, 2022, 10:14 pm

Below is a quick and dirty script that implements a simple timeline using code from goto.lua to go back and forwards. Try loading a pattern like breeder.lif and then running the script. I think it shows that this method works fine, even for patterns with thousands of cells.

Code: Select all

-- This script implements a simple timeline.

local g = golly()
local gp = require "gplus"
local op = require "oplus"
local split = gp.split
local ov = g.overlay

-- set startgen to current generation count
local startgen = tonumber(g.getgen())
local endgen = startgen + 1000 -- maximum gen count
local currgen = startgen

local ovwd, ovht        -- size of overlay (set by CreateOverlay)
local minwd = 500       -- minimum width of overlay

-- controls (set by CreateControls)
local backbutton        -- -1
local nextbutton        -- +1
local exitbutton        -- X
local genslider         -- slider for changing currgen

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

function CreateOverlay()
    -- the overlay is a bar at the bottom of the viewport
    local viewwd, viewht = g.getview(g.getlayer())
    ovht = 32
    ovwd = viewwd
    if ovwd < minwd then ovwd = minwd end
    ov("create "..ovwd.." "..ovht)
    ov("cursor arrow")
    ov("position bottomleft")

    -- set parameters for buttons
    op.buttonht = 20
    op.textgap = 8                          -- gap between edge of button and its label
    op.textfont = "font 10 default-bold"    -- font for button labels
    op.textshadowx = 2
    op.textshadowy = 2
    if g.os() == "Linux" then
        op.textfont = "font 10 default"
    end
end

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

function DrawControls()
    -- enable/disable some buttons
    backbutton.enable(currgen > startgen)
    nextbutton.enable(currgen < endgen)

    local hgap = 10     -- horizontal space between buttons
    local vgap = 6      -- vertical space above buttons
    local x = hgap
    local y = vgap
    local biggap = hgap * 2

    backbutton.show(x, y)
    x = x + backbutton.wd + hgap
    nextbutton.show(x, y)
    x = x + nextbutton.wd + biggap

    -- show slider to right of nextbutton
    genslider.show(x, y, currgen)

    -- exitbutton is at right end of slider
    x = x + genslider.wd + biggap
    exitbutton.show(x, y)
end

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

function Refresh()
    ov("rgba 200 200 200 255")
    ov("fill")
    DrawControls()
    g.update()
end

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

function Goto(newgen)
    -- simplified code from goto.lua
    if newgen < currgen then
        -- go back to starting gen (not necessarily 0);
        -- first save current location, scale, selection
        local midx, midy = g.getpos()
        local mag = g.getmag()
        local sel = g.getselrect()
        g.reset()
        -- restore location, scale, selection
        g.setpos(midx, midy)
        g.setmag(mag)
        g.select(sel)
        -- current gen might be > 0
        currgen = tonumber(g.getgen())
    end
    if newgen == currgen then return end

    local function intbase(n, b)
        -- convert integer n >= 0 to a base b digit array (thanks to PM 2Ring)
        digits = {}
        while n > 0 do
            digits[#digits + 1] = n % b
            n = math.floor(n / b)
        end
        if #digits == 0 then digits = {0} end
        return digits
    end

    -- use fast stepping (thanks to PM 2Ring)
    for i, d in ipairs(intbase(newgen - currgen, g.getbase())) do
        if d > 0 then
            g.setstep(i-1)
            for j = 1, d do
                if g.empty() then
                    currgen = tonumber(g.getgen())
                    return
                end
                g.step()
            end
        end
    end
    currgen = newgen
end

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

function GotoGen(newgen)
    if newgen < startgen or newgen > endgen then return end
    
    local oldstep = g.getstep()
    Goto(newgen)
    g.setstep(oldstep)
    
    if g.getoption("autofit") == 1 then
        --!!! need smarter code to allow for overlay height
        g.fit()
    end
    
    Refresh()
end

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

function GenChange(newgen)
    -- called if genslider position has changed
    GotoGen(newgen)
end

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

function CreateControls()
    -- create buttons
    backbutton = op.button("-1", function() GotoGen(currgen-1) end)
    nextbutton = op.button("+1", function() GotoGen(currgen+1) end)
    exitbutton = op.button("X", g.exit)

    -- create slider for adjusting currgen
    genslider = op.slider("", op.white, 200, startgen, endgen, GenChange)
end

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

function CheckWindowSize()
    -- if viewport width has changed then resize the overlay
    local newwd, newht = g.getview(g.getlayer())
    if newwd ~= ovwd then
        ovwd = newwd
        if ovwd < minwd then ovwd = minwd end
        ov("resize "..ovwd.." "..ovht)
        Refresh()
    end
end

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

function EventLoop()
    while true do
        local event = g.getevent()
        if #event == 0 then
            g.sleep(5)          -- don't hog the CPU when idle
            CheckWindowSize()   -- might need to resize the overlay
        else
            event = op.process(event)
            if #event == 0 then
                -- op.process handled the given event (click in slider or button)
            elseif event:find("^key") then
                -- allow keyboard shortcuts (eg. to toggle full screen mode)
                g.doevent(event)
            elseif event:find("^click") or event:find("^zoom") then
                -- allow moving, zooming, etc
                g.doevent(event)
            end
        end
    end
end

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

function Main()
    CreateOverlay()
    CreateControls()
    Refresh()
    EventLoop()
end

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

if g.empty() then g.exit("There is no pattern.") end

-- make Goto code faster by copying current pattern into a new layer
-- so the g.step calls won't create lots of temporary files
if g.numlayers() == g.maxlayers() then
    g.exit("You need to delete a layer.")
else
    local pattern = g.getcells(g.getrect())
    local midx, midy = g.getpos()
    local mag = g.getmag()
    local sel = g.getselrect()
    g.addlayer()
    g.new("timeline")
    g.putcells(pattern)
    -- use same location, scale, selection, starting gen
    g.setpos(midx, midy)
    g.setmag(mag)
    g.select(sel)
    g.setgen(tostring(currgen)) -- currgen = startgen
    g.setcursor("Zoom In")
end
local oldtile = g.setoption("tilelayers", 0)

local status, err = xpcall(Main, gp.trace)
if err then g.continue(err) end
-- the following code is executed even if error occurred or user aborted script
ov("delete")
g.dellayer()
g.setoption("tilelayers", oldtile)

Post Reply