make a python script repeat itself indefinitely ?

For scripts to aid with computation or simulation in cellular automata.
Post Reply
User avatar
gamnamno
Posts: 23
Joined: March 5th, 2014, 3:39 pm
Location: Rambaud, France
Contact:

make a python script repeat itself indefinitely ?

Post by gamnamno » March 11th, 2014, 5:25 pm

How can I make a python script repeat itself?

The purpose is to use the "save bmp" python script, but by adding some command line, each time it repeats itself, it also goes to the next generation so that it would create a sequence of bmp with the animation of the pattern, and to stop it you would just press Esc.

Can you help me?

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

Re: make a python script repeat itself indefinitely ?

Post by Andrew » March 11th, 2014, 8:04 pm

The following script should do what you want. Feel free to modify it in any way you like.

Code: Select all

# Run the current pattern and save the selection as a separate .bmp file
# for each generation.  The files are saved in the same folder as the script.
# Author: Andrew Trevorrow (andrew@trevorrow.com), March 2014.

import golly as g
from glife import validint
from glife.WriteBMP import WriteBMP
import os.path

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

srect = g.getselrect()
if len(srect) == 0: g.exit("There is no selection.")
x = srect[0]
y = srect[1]
wd = srect[2]
ht = srect[3]

# prevent Python allocating a huge amount of memory
if wd * ht >= 100000000:
   g.exit("Bitmap area is restricted to < 100 million cells.")

multistate = g.numstates() > 2
colors = g.getcolors()     # [0,r0,g0,b0, ... N,rN,gN,bN]
state0 = (colors[1],colors[2],colors[3])

# --------------------------------------------------------------------

def CreateBMPFile(filename):
    global x, y, wd, ht, multistate, colors, state0

    # create 2D array of pixels filled initially with state 0 color
    pixels = [[state0 for col in xrange(wd)] for row in xrange(ht)]
    
    cellcount = 0
    for row in xrange(ht):
       # get a row of cells at a time to minimize use of Python memory
       cells = g.getcells( [ x, y + row, wd, 1 ] )
       clen = len(cells)
       if clen > 0:
          inc = 2
          if multistate:
             # cells is multi-state list (clen is odd)
             inc = 3
             if clen % 3 > 0: clen -= 1    # ignore last 0
          for i in xrange(0, clen, inc):
             if multistate:
                n = cells[i+2] * 4 + 1
                pixels[row][cells[i]-x] = (colors[n],colors[n+1],colors[n+2])
             else:
                pixels[row][cells[i]-x] = (colors[5],colors[6],colors[7])
             cellcount += 1
             if cellcount % 1000 == 0:
                # allow user to abort huge pattern/selection
                g.dokey( g.getkey() )
    
    WriteBMP(pixels, filename)

# --------------------------------------------------------------------

# remove any existing extension from layer name
outname = g.getname().split('.')[0]

# prompt user for number of generations (= number of files)
numgens = g.getstring("The number of generations will be\n" +
                      "the number of .bmp files created.",
                      "100", "How many generations?")
if len(numgens) == 0:
    g.exit()
if not validint(numgens):
    g.exit('Sorry, but "' + numgens + '" is not a valid integer.')

numcreated = 0
intgens = int(numgens)
while intgens > 0:
   outfile = outname + "_" + g.getgen() + ".bmp"
   g.show("Creating " + outfile)
   CreateBMPFile(outfile)
   numcreated += 1
   g.run(1)
   g.update()
   intgens -= 1

g.show("Number of .bmp files created: " + str(numcreated))
Use Glu to explore CA rules on non-periodic tilings: DominoLife and HatLife

User avatar
gamnamno
Posts: 23
Joined: March 5th, 2014, 3:39 pm
Location: Rambaud, France
Contact:

Re: make a python script repeat itself indefinitely ?

Post by gamnamno » March 11th, 2014, 8:29 pm

YES !!
Thanks a lot !
Did you create it after my question or did it already exist ? because I was searching for this script for many days !

User avatar
gamnamno
Posts: 23
Joined: March 5th, 2014, 3:39 pm
Location: Rambaud, France
Contact:

Re: make a python script repeat itself indefinitely ?

Post by gamnamno » March 8th, 2017, 11:31 am

I just made a tutorial on how to make an image sequence of a cellular automaton which is aimed at everyone including people who don't know Golly :
https://caetano-veyssieres.com/cellular ... -tutorial/
I'd like it to be bulletproof for troubleshooting so if you have any advice on the possible errors one could meet and how to fix them that would make it more useful.
Also if you want to copy anything from it to the wiki or any documentation feel free to do it.

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

Re: make a python script repeat itself indefinitely ?

Post by Andrew » March 9th, 2017, 7:03 am

Included below is a Lua version of the above Python script. Given the problems some people have getting Python scripts working in Golly it would be better if your tutorial told people to download this Lua script (call it BMP-sequence.lua or whatever you like). It requires Golly 2.8 or later.

Another suggestion: avoid telling people to put the script anywhere inside Golly's Scripts folder. Please see the top tip in Help > Hints and Tips for the best way to organize your Golly folder. Much better to tell people to put the script in a new folder (eg. as a new subfolder in My-scripts), especially because all the BMP files are created in the same folder as the script. An easy way to run the script is to drop it on the Golly window or the app, or a shortcut to the app (or a dock icon on a Mac).

Code: Select all

-- Run the current pattern and save the selection as a separate .bmp file
-- for each generation.  The files are saved in the same folder as the script.
-- Author: Andrew Trevorrow (andrew@trevorrow.com), March 2017.

local g = golly()
local gp = require "gplus"
local chr = string.char
local getcell = g.getcell

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

local srect = g.getselrect()
if #srect == 0 then g.exit("There is no selection.") end
local x, y, wd, ht = table.unpack(srect)

-- avoid creating huge files
if wd * ht >= 100000000 then
   g.exit("Bitmap area is restricted to < 100 million cells.")
end

local colors = g.getcolors()     -- {0,r0,g0,b0, ... N,rN,gN,bN}
local state0 = chr(colors[4])..chr(colors[3])..chr(colors[2])
local statebgr = {}
for i = 1, g.numstates() - 1 do
    local j = i * 4 + 2
    statebgr[i] = chr(colors[j+2])..chr(colors[j+1])..chr(colors[j])
end

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

-- Pack a given +ve integer into a little-endian binary string of size numbytes.
-- Based on code at http://lua-users.org/wiki/ReadWriteFormat.

local function lpack(numbytes, value)
    local result = ""
    for i = 1, numbytes do
        result = result .. chr(value % 256)
        value = math.floor(value / 256)
    end
    return result
end

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

-- create a minimal dictionary with values for a Windows Version 3 DIB header:
local d = {
    mn1=66,
    mn2=77,
    filesize=0,
    undef1=0,
    undef2=0,
    offset=54,
    headerlength=40,
    width=wd,
    height=ht,
    colorplanes=1,
    colordepth=24,
    compression=0,
    imagesize=0,
    res_hor=0,
    res_vert=0,
    palette=0,
    importantcolors=0
}

-- we only need to create the header data once:
local header =
    lpack(1, d.mn1) ..
    lpack(1, d.mn2) ..
    lpack(4, d.filesize) ..
    lpack(2, d.undef1) ..
    lpack(2, d.undef2) ..
    lpack(4, d.offset) ..
    lpack(4, d.headerlength) ..
    lpack(4, d.width) ..
    lpack(4, d.height) ..
    lpack(2, d.colorplanes) ..
    lpack(2, d.colordepth) ..
    lpack(4, d.compression) ..
    lpack(4, d.imagesize) ..
    lpack(4, d.res_hor) ..
    lpack(4, d.res_vert) ..
    lpack(4, d.palette) ..
    lpack(4, d.importantcolors)

-- we may need to pad each row:
local row_mod = (d.width * d.colordepth / 8) % 4
local padding = ""
if row_mod > 0 then
    for i = 1, 4 - row_mod do
        padding = padding..chr(0)
    end
end

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

function CreateBMPFile(filename)
    -- create a BMP file showing the pattern in the current selection
    local outfile = io.open(filename,'wb')
    if not outfile then g.exit("Unable to create BMP file:\n"..filename) end

    -- write the header info
    outfile:write(header)

    -- write the byte data (BMPs are encoded left-to-right from the bottom-up)
    for row = ht, 1, -1 do
        for col = 1, wd do
            local state = getcell(x + col - 1, row + y - 1)
            if state == 0 then
                outfile:write(state0)
            else
                outfile:write(statebgr[state])
            end
        end
        if row_mod > 0 then
            -- add padding so the byte count for each row is divisible by 4
            outfile:write(padding)
        end
    end

    outfile:close()
end

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

-- remove any existing extension from layer name
local outname = gp.split(g.getname(),"%.")

-- prompt user for number of generations (= number of files)
local numgens = g.getstring("The number of generations will be\n" ..
                            "the number of .bmp files created.",
                            "100", "How many generations?")
if #numgens == 0 then
    g.exit()
end
if not gp.validint(numgens) then
    g.exit('Sorry, but "' .. numgens .. '" is not a valid integer.')
end

local numcreated = 0
local intgens = tonumber(numgens)
while intgens > 0 do
    local outfile = outname .. "_" .. g.getgen() .. ".bmp"
    g.show("Creating " .. outfile)
    CreateBMPFile(outfile)
    numcreated = numcreated + 1
    if intgens == 1 then break end
    g.run(1)
    g.update()
    intgens = intgens - 1
end
g.show("Number of .bmp files created: " .. numcreated)
Use Glu to explore CA rules on non-periodic tilings: DominoLife and HatLife

User avatar
gamnamno
Posts: 23
Joined: March 5th, 2014, 3:39 pm
Location: Rambaud, France
Contact:

Re: make a python script repeat itself indefinitely ?

Post by gamnamno » March 11th, 2017, 12:03 pm

Thank you very much for this advice and new script. I updated the tutorial.
Do you put all your scripts in one place (Sourceforge, Github or else) so that I could give a direct link to this new one (rather than copying it to my own github) ?

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

Re: make a python script repeat itself indefinitely ?

Post by Andrew » March 11th, 2017, 8:35 pm

gamnamno wrote:Do you put all your scripts in one place (Sourceforge, Github or else) ... ?
Most of the Golly-related scripts I write end up in the Golly Scripts Database but I've been slack the last few years. Eventually I'd like to replace all the .py/pl scripts with .lua equivalents. Hopefully other folks might help with that task.
Use Glu to explore CA rules on non-periodic tilings: DominoLife and HatLife

User avatar
gamnamno
Posts: 23
Joined: March 5th, 2014, 3:39 pm
Location: Rambaud, France
Contact:

Re: make a python script repeat itself indefinitely ?

Post by gamnamno » March 12th, 2017, 10:09 am

Sounds like a tremendous task. Unfortunately now I have a bit of knowledge in python but none in Lua. Didn't even know this language existed before.

Post Reply