File: goto.lua

package info (click to toggle)
golly 3.3-1.1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 20,176 kB
  • sloc: cpp: 72,638; ansic: 25,919; python: 7,921; sh: 4,245; objc: 3,721; java: 2,781; xml: 1,362; makefile: 530; javascript: 279; perl: 69
file content (141 lines) | stat: -rwxr-xr-x 4,635 bytes parent folder | download | duplicates (2)
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
-- Go to a requested generation.  The given generation can be an
-- absolute number like 1,000,000 (commas are optional) or a number
-- relative to the current generation like +9 or -6.  If the target
-- generation is less than the current generation then we go back
-- to the starting generation (normally 0) and advance to the target.
-- Authors: Andrew Trevorrow and Dave Greene, Apr 2016.

local g = golly()
local gp = require "gplus"
local validint = gp.validint

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

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

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

local function go_to(gen)
    local currgen = tonumber(g.getgen())
    local newgen
    if gen:sub(1,1) == '+' then
        newgen = currgen + tonumber(gen:sub(2,-1))
    elseif gen:sub(1,1) == '-' then
        local n = tonumber(gen:sub(2,-1))
        if currgen > n then
            newgen = currgen - n
        else
            newgen = 0
        end
    else
        newgen = tonumber(gen)
    end
    
    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)
        -- current gen might be > 0 if user loaded a pattern file
        -- that set the gen count
        currgen = tonumber(g.getgen())
        if newgen < currgen then
            g.error("Can't go back any further; pattern was saved "..
                    "at generation "..currgen..".")
            return
        end
    end
    if newgen == currgen then return end
    
    g.show("Hit escape to abort...")
    local oldsecs = os.clock()
    
    -- before stepping we advance by 1 generation, for two reasons:
    -- 1. if we're at the starting gen then the *current* step size
    --    will be saved (and restored upon Reset/Undo) rather than a
    --    possibly very large step size
    -- 2. it increases the chances the user will see updates and so
    --    get some idea of how long the script will take to finish
    --    (otherwise if the base is 10 and a gen like 1,000,000,000
    --    is given then only a single step() of 10^9 would be done)
    g.run(1)
    currgen = currgen + 1

    -- 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
                    g.show("Pattern is empty.")
                    return
                end
                g.step()
                local newsecs = os.clock()
                if newsecs - oldsecs >= 1.0 then
                    -- do an update every sec
                    oldsecs = newsecs
                    g.update()
                end
            end
        end
    end
    g.show("")
end

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

local function savegen(filename, gen)
    local f = io.open(filename, "w")
    if f then
        f:write(gen)
        f:close()
    else
        g.warn("Can't save gen in filename:\n"..filename)
    end
end

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

-- use same file name as in goto.py
local GotoINIFileName = g.getdir("data").."goto.ini"
local previousgen = ""
local f = io.open(GotoINIFileName, "r")
if f then
    previousgen = f:read("*l") or ""
    f:close()
end

local gen = g.getstring("Enter the desired generation number,\n"..
                        "or -n/+n to go back/forwards by n:",
                        previousgen, "Go to generation")
if gen == "" then
    g.exit()
elseif gen == '+' or gen == '-' then
    -- clear the default
    savegen(GotoINIFileName, "")
elseif not validint(gen) then
    g.exit("Sorry, but \""..gen.."\" is not a valid integer.")
else
    -- best to save given gen now in case user aborts script
    savegen(GotoINIFileName, gen)
    local oldstep = g.getstep()
    go_to(gen:gsub(",",""))
    g.setstep(oldstep)
end