Golly scripts

For scripts to aid with computation or simulation in cellular automata.
User avatar
codeholic
Moderator
Posts: 1147
Joined: September 13th, 2011, 8:23 am
Location: Hamburg, Germany

Re: Golly scripts

Post by codeholic » June 8th, 2014, 9:07 pm

Thank you! That is what I was looking for!
Ivan Fomichev

User avatar
Lewis
Posts: 337
Joined: March 17th, 2009, 5:26 pm
Location: UK
Contact:

Re: Golly scripts

Post by Lewis » July 24th, 2014, 3:37 pm

Is there any way to get Golly to write text (not RLE or pattern file) to a .txt file?

I've managed to modify the census script in this thread so it repeatedly generates and census-es loads of random soups, keeping a running total of each object it finds. So far I've managed to get it to output the cumulative results to the clipboard after each game, just by using things out of the scripting help file that came with Golly. But it'd be easier (and free up the clipboard while the script is running) if I could get it to export the results to a file every so often.

I can't help but feel that there's a really obvious way to do this that I'm missing...

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

Re: Golly scripts

Post by dvgrn » July 24th, 2014, 9:04 pm

Lewis wrote:Is there any way to get Golly to write text (not RLE or pattern file) to a .txt file?
Have a look at savegen() in goto.py -- it has everything you need to write a line of text to a text file.

Other parts of that script show how to read a single line back again.

Writing multiple lines takes a little more getting used to. Python's read() and readlines() functions do pretty much what you expect, but write() and writelines() tend to write everything into a single line of text -- you have to add "\n" characters to your text whenever you want to start a new line.

Let me know if you can't get something working.

User avatar
Lewis
Posts: 337
Joined: March 17th, 2009, 5:26 pm
Location: UK
Contact:

Re: Golly scripts

Post by Lewis » July 27th, 2014, 9:15 am

Another quick question: is there any way to get a script to generate random soups with eight-way symmetry (ie. reflective symmetry in the horizontal, vertical and both diagonal axes) without using the copy/paste function (This is for the same census script as before).

So far I'm just using this kind of long winded method, which is just automating the way I'd do it by hand:

Code: Select all

	   g.new("")
	   g.select([0,0,24,24])
	   g.randfill(5)
	   g.copy()
	   g.flip(0)
	   g.paste(0,0, "or")
	   g.copy()
	   g.flip(1)
	   g.paste(0,0, "or")
	   g.copy()
	   g.rotate(0)
	   g.paste(0,0, "or")
But this sometimes brings up "Could not copy text to clipboard" errors and things. I had a look at the 'Quadsymm' here which seemed to do a similar job, but I can't figure out how it does what it does, so I can't just modify it.
dvgrn wrote:Let me know if you can't get something working.
The savegen() function seems to be working fine, luckily Nathaniel's census script stores the object counts as one long line.

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

Re: Golly scripts

Post by dvgrn » July 27th, 2014, 10:10 am

Lewis wrote:Another quick question: is there any way to get a script to generate random soups with eight-way symmetry (ie. reflective symmetry in the horizontal, vertical and both diagonal axes) without using the copy/paste function...?
The quick answer is "yes" -- use the optional transform coordinates on golly.putcells(), or just use golly.transform().

If you find you need sample code, I can write something up. The easy way might be to draw a triangle of cells starting at (0,0), and then put it into a variable:

pat=golly.getcells(golly.getrect())

Then

golly.putcells(pat,0,0,a,b,c,d)

for seven different a, b, c, d combinations corresponding to all the standard rotations and reflections.

c0b0p0
Posts: 645
Joined: February 26th, 2014, 4:48 pm

Re: Golly scripts

Post by c0b0p0 » September 17th, 2014, 9:30 pm

Here is a prototype slow salvo search script in 22da. It produces a set of collisions between a glider and an oscillator the user selects.

Code: Select all

# Creates a set of collisions between a glider and another object, 
# selected by the user.
import golly as g
from glife.base import *

rule("22da")

glider = pattern("o2$2bo$2o$2o2bo!")
oscillator = pattern(g.getcells(g.getselrect()))

def collision (i, j):
    return glider + oscillator[i + 9] (-10 + j, 30)

all = pattern ()

for i in xrange (-7, 7):
    for j in xrange (-9, 10):
        all += collision (i, j) (100 * i, 100 * j)

all.display("synthesis")

Feel free to post comments and results in the thread for 22da.

c0b0p0
Posts: 645
Joined: February 26th, 2014, 4:48 pm

Re: Golly scripts

Post by c0b0p0 » September 20th, 2014, 6:46 pm

Here is the new slow salvo synthesis search script, edited to find more syntheses.

Code: Select all

# Creates a set of collisions between a glider and another object, 
# selected by the user.
import golly as g
from glife.base import *

rule("22da")

glider = pattern("o2$2bo$2o$2o2bo!")
osc = pattern(g.getcells(g.getselrect()))

def collision (i, j):
    return glider + osc[i + 9] (-25 + j, 30)

all = pattern ()

for i in xrange (-9, 10):
    for j in xrange (-9, 10):
        all += collision (i, j) (100 * i, 100 * j)

all.display("synthesis")


NickGotts
Posts: 101
Joined: November 10th, 2011, 6:20 pm

Re: Golly scripts

Post by NickGotts » October 14th, 2014, 8:54 am

Here is Python code to test whether the current pattern is "quiescent": that is,
consists solely of still lifes, oscillators, gliders and *WSSs, with
the gliders and *WSSs being so placed that they will never interact
with each other, or with any of the still lifes or oscillators.

Code: Select all

# Code to test whether the current pattern is "quiescent": that is,
# consists solely of still lifes, oscillators, gliders and *WSSs, with
# the gliders and *WSSs being so placed that they will never interact
# with each other, or with any of the still lifes or oscillators. The
# "period" argument to testquiescence determines the periods of
# oscillators that the function will recognise as oscillators: all
# periods that are divisors of the given period. So if period is 60,
# oscillators of periods 2, 3, 4, 5, 6, 10, 12, 15, 20, 30 and 60 will
# be recognised as such. If there is an oscillator of period 7 or 8,
# for example, it will not be recognised and testquiescence will
# return <false>.

import golly as g
from glife import *

def testquiescence (period):
    boundrect = g.getrect ()
    clist, el, em, eh, sl, sm, sh, wl, wm ,wh, nl, nm, nh, se, sw, nw, ne = diviup (boundrect)
    return quiescent (boundrect, period, clist, el, em, eh, sl, sm, sh, wl, wm ,wh, nl, nm, nh, se, sw, nw, ne)

def quiescent (boundrect, period, clist, el, em, eh, sl, sm, sh, wl, wm ,wh, nl, nm, nh, se, sw, nw, ne):
    if boundrect == []:
        boundrect = g.getrect ()
        if boundrect != []:
            boundrect[0] = boundrect [0] - 1
            boundrect[1] = boundrect [1] - 1
            boundrect[2] = boundrect [2] + 2
            boundrect[3] = boundrect [3] + 2
    eastcells = allcells (el + em + eh)
    clist = clistdiff (clist, eastcells)
    if clist == []:
        return (True)
    if (eastcells != []) and (max (clist[::2]) + (2 * (period + 1)) > min (eastcells[::2])):
        return (False)
    southcells = allcells (sl + sm + sh)
    clist = clistdiff (clist, southcells)
    if clist == []:
        return (True)
    if (southcells != []) and (max (clist[1::2]) + (2 * (period + 1)) > min (southcells[1::2])):
        return (False)
    westcells = allcells (wl + wm + wh)
    clist =  clistdiff (clist, westcells)
    if clist == []:
        return (True)
    if (westcells != []) and (min (clist[::2]) - (2 * (period + 1)) < max (westcells[::2])):
        return (False)
    northcells = allcells (nl + nm + nh)
    clist = clistdiff (clist, northcells)
    if clist == []:
        return (True)
    if (northcells != []) and (min (clist[1::2]) - (2 * (period + 1)) < max (northcells[1::2])):
        return (False)
    secells = allcells (se)
    clist = clistdiff (clist, secells)
    if clist == []:
        return (True)
    if (secells != []) and \
        (max ([clist [n] + clist [n+1] for n in range (0, len (clist) - 1, 2)]) + (2 * (period + 1)) > \
            min ([secells [n] + secells [n+1] for n in range (0, len (secells) - 1, 2)])):
        return (False)
    swcells = allcells (sw)
    clist = clistdiff (clist, swcells)
    if clist == []:
        return (True)
    if (swcells != []) and \
        (max ([clist [n+1] - clist [n] for n in range (0, len (clist) - 1, 2)]) + (2 * (period + 1)) > \
            min ([swcells [n+1] - swcells [n] for n in range (0, len (swcells) - 1, 2)])):
        return (False)
    nwcells = allcells (nw)
    clist = clistdiff (clist, nwcells)
    if clist == []:
        return (True)
    if (nwcells != []) and \
        (min ([clist [n] + clist [n+1] for n in range (0, len (clist) - 1, 2)]) - (2 * (period + 1)) < \
            max ([nwcells [n] + nwcells [n+1] for n in range (0, len (nwcells) - 1, 2)])):
        return (False)
    necells = allcells (ne)
    clist = clistdiff (clist, necells)
    if clist == []:
        return (True)
    if (necells != []) and \
        (max ([clist [n] - clist [n+1] for n in range (0, len (clist) - 1, 2)]) + (2 * (period + 1)) > \
            min ([necells [n] - necells [n+1] for n in range (0, len (necells) - 1, 2)])):
        return (False)
    wssmove = period/2
    if eastcells != []:
        for n in range (0, len(eastcells) - 1, 2):
            eastcells[n] += wssmove
    if southcells != []:
        for n in range (1, len(southcells), 2):
            southcells[n] += wssmove
    if westcells != []:
        for n in range (0, len(westcells) - 1, 2):
            westcells[n] -= wssmove
    if northcells != []:
        for n in range (1, len(northcells), 2):
            northcells[n] -= wssmove
    glimove = period/4
    if secells != []:
        for n in range (0, len (secells) - 1, 2):
            secells[n] += glimove
            secells[n+1] += glimove
    if swcells != []:
        for n in range (0, len (swcells) - 1, 2):
            swcells[n] -= glimove
            swcells[n+1] += glimove
    if nwcells != []:
        for n in range (0, len (nwcells) - 1, 2):
            nwcells[n] -= glimove
            nwcells[n+1] -= glimove
    if necells != []:
        for n in range (0, len (necells) - 1, 2):
            necells[n] += glimove
            necells[n+1] -= glimove
    g.run (period)
    boundrect[0] = boundrect [0] - period/2
    boundrect[1] = boundrect [1] - period/2
    boundrect[2] = boundrect [2] + period
    boundrect[3] = boundrect [3] + period
    newclist = g.getcells (boundrect)
    checkclist = northcells + nwcells + necells + westcells + clist + eastcells + swcells + secells + southcells
    return (clistssame (newclist, checkclist))

def allcells (listofrects):
    clist = []
    for rect in listofrects:
      clist = clist + g.getcells (rect)
    return (clist)

def clistdiff (clist1, clist2):
    while clist2 != []:
        for n in range (0, len (clist1) - 1, 2):
            if clist2[0] == clist1[n] and  clist2[1] == clist1[n+1]:
                del clist1 [n:n+2]
                break
        clist2 = clist2 [2:]
    return (clist1)

def clistssame (clist1, clist2):
    if len (clist1) != len (clist2):
        return (False)
    while clist2 != []:
        unmatched = True
        for n in range (0, len (clist1) - 1, 2):
            if clist2[0] == clist1[n] and  clist2[1] == clist1[n+1]:
                del clist1 [n:n+2]
                unmatched = False
                break
        if unmatched:
            return (False)
        clist2 = clist2 [2:]
    return (clist2 == [])

# Not currently in use.
def containingrect (listofrects):
    if listofrects == []:
        contrect = []
    else:
        firstrect = listofrects[0]
        left = firstrect[0]
        top = firstrect[1]
        rightplus1 = firstrect[0] + firstrect[2]
        bottomplus1 = firstrect[1] + firstrect[3]
        for rect in listofrects[1:]:
            left = min ([rect[0], left])
            top = min ([rect[1], top])
            rightplus1 = max ([rect[0] + rect[2], rightplus1])
            bottomplus1 = max ([rect[1] + rect[3], bottomplus1])
            #g.show (str ([left, top, rightplus1, bottomplus1]))
            #ch = chr (8)
            #while ch != chr (9):
            #    ch = g.getkey ()
        contrect = [left, top, rightplus1 - left, bottomplus1 - top]
    return (contrect)
    # Note that when used on listofrects derived from diviup, this will
    # return a rectangle with one empty layer of cells on the outside.

def diviup (boundrect):
    clist = g.getcells (boundrect)
    if clist == []:
        g.show ("Empty pattern!")
        el = list ()
        em = list ()
        eh = list ()
        sl = list ()
        sm = list ()
        sh = list ()
        wl = list ()
        wm = list ()
        wh = list ()
        nl = list ()
        nm = list ()
        nh = list ()
        se = list ()
        sw = list ()
        nw = list ()
        ne = list ()
    else:
        boundrect[0] = boundrect [0] - 1
        boundrect[1] = boundrect [1] - 1
        boundrect[2] = boundrect [2] + 2
        boundrect[3] = boundrect [3] + 2
        el = matchpattern (lwsse0wrapped, 2, 1, 7, 6, boundrect) + \
             matchpattern (lwsse1wrapped, 2, 1, 7, 6, boundrect) + \
             matchpattern (lwsse2wrapped, 1, 1, 7, 6, boundrect) + \
             matchpattern (lwsse3wrapped, 3, 1, 7, 6, boundrect)
        em = matchpattern (mwsse0wrapped, 2, 1, 8, 7, boundrect) + \
             matchpattern (mwsse1wrapped, 2, 1, 8, 6, boundrect) + \
             matchpattern (mwsse2wrapped, 3, 1, 8, 7, boundrect) + \
             matchpattern (mwsse3wrapped, 4, 1, 8, 6, boundrect)
        eh = matchpattern (hwsse0wrapped, 2, 1, 9, 7, boundrect) + \
             matchpattern (hwsse1wrapped, 2, 1, 9, 6, boundrect) + \
             matchpattern (hwsse2wrapped, 3, 1, 9, 7, boundrect) + \
             matchpattern (hwsse3wrapped, 5, 1, 9, 6, boundrect)
        sl = matchpattern (lwsss0wrapped, 1, 1, 6, 7, boundrect) + \
             matchpattern (lwsss1wrapped, 2, 1, 6, 7, boundrect) + \
             matchpattern (lwsss2wrapped, 2, 1, 6, 7, boundrect) + \
             matchpattern (lwsss3wrapped, 2, 1, 6, 7, boundrect)
        sm = matchpattern (mwsss0wrapped, 2, 1, 7, 8, boundrect) + \
             matchpattern (mwsss1wrapped, 2, 1, 6, 8, boundrect) + \
             matchpattern (mwsss2wrapped, 2, 1, 7, 8, boundrect) + \
             matchpattern (mwsss3wrapped, 2, 1, 6, 8, boundrect)
        sh = matchpattern (hwsss0wrapped, 2, 1, 7, 9, boundrect) + \
             matchpattern (hwsss1wrapped, 2, 1, 6, 9, boundrect) + \
             matchpattern (hwsss2wrapped, 2, 1, 7, 9, boundrect) + \
             matchpattern (hwsss3wrapped, 2, 1, 6, 9, boundrect)
        wl = matchpattern (lwssw0wrapped, 1, 1, 7, 6, boundrect) + \
             matchpattern (lwssw1wrapped, 3, 1, 7, 6, boundrect) + \
             matchpattern (lwssw2wrapped, 2, 1, 7, 6, boundrect) + \
             matchpattern (lwssw3wrapped, 2, 1, 7, 6, boundrect)
        wm = matchpattern (mwssw0wrapped, 1, 1, 8, 7, boundrect) + \
             matchpattern (mwssw1wrapped, 3, 1, 8, 6, boundrect) + \
             matchpattern (mwssw2wrapped, 4, 1, 8, 7, boundrect) + \
             matchpattern (mwssw3wrapped, 2, 1, 8, 6, boundrect)
        wh = matchpattern (hwssw0wrapped, 1, 1, 9, 7, boundrect) + \
             matchpattern (hwssw1wrapped, 3, 1, 9, 6, boundrect) + \
             matchpattern (hwssw2wrapped, 4, 1, 9, 7, boundrect) + \
             matchpattern (hwssw3wrapped, 2, 1, 9, 6, boundrect)
        nl = matchpattern (lwssn0wrapped, 2, 1, 6, 7, boundrect) + \
             matchpattern (lwssn1wrapped, 2, 1, 6, 7, boundrect) + \
             matchpattern (lwssn2wrapped, 1, 1, 6, 7, boundrect) + \
             matchpattern (lwssn3wrapped, 3, 1, 6, 7, boundrect)
        nm = matchpattern (mwssn0wrapped, 3, 1, 7, 8, boundrect) + \
             matchpattern (mwssn1wrapped, 2, 1, 6, 8, boundrect) + \
             matchpattern (mwssn2wrapped, 1, 1, 7, 8, boundrect) + \
             matchpattern (mwssn3wrapped, 3, 1, 6, 8, boundrect)
        nh = matchpattern (hwssn0wrapped, 3, 1, 7, 9, boundrect) + \
             matchpattern (hwssn1wrapped, 2, 1, 6, 9, boundrect) + \
             matchpattern (hwssn2wrapped, 1, 1, 7, 9, boundrect) + \
             matchpattern (hwssn3wrapped, 3, 1, 6, 9, boundrect)
        se = matchpattern (gliderse0wrapped, 2, 1, 5, 5,  boundrect) + \
             matchpattern (gliderse1wrapped, 1, 1, 5, 5,  boundrect) + \
             matchpattern (gliderse2wrapped, 3, 1, 5, 5,  boundrect) + \
             matchpattern (gliderse3wrapped, 1, 1, 5, 5,  boundrect)
        sw = matchpattern (glidersw0wrapped, 2, 1, 5, 5,  boundrect) + \
             matchpattern (glidersw1wrapped, 1, 1, 5, 5,  boundrect) + \
             matchpattern (glidersw2wrapped, 1, 1, 5, 5,  boundrect) + \
             matchpattern (glidersw3wrapped, 3, 1, 5, 5,  boundrect)
        nw = matchpattern (glidernw0wrapped, 1, 1, 5, 5,  boundrect) + \
             matchpattern (glidernw1wrapped, 2, 1, 5, 5,  boundrect) + \
             matchpattern (glidernw2wrapped, 1, 1, 5, 5,  boundrect) + \
             matchpattern (glidernw3wrapped, 2, 1, 5, 5,  boundrect)
        ne = matchpattern (gliderne0wrapped, 1, 1, 5, 5,  boundrect) + \
             matchpattern (gliderne1wrapped, 2, 1, 5, 5,  boundrect) + \
             matchpattern (gliderne2wrapped, 2, 1, 5, 5,  boundrect) + \
             matchpattern (gliderne3wrapped, 1, 1, 5, 5,  boundrect)
    return (clist, el, em, eh, sl, sm, sh, wl, wm ,wh, nl, nm, nh, se, sw, nw, ne)

def matchpattern (patt, xsub, ysub, txsize, tysize, rectlist):
    clist = g.getcells (rectlist)
    lmr = []
    while len (clist) > 0:
        testrect = [clist[0] - xsub, clist[1] - ysub, txsize, tysize]
        testpatt = g.getcells (testrect)
        if len (patt) == len (testpatt):
            z = 0
            while z < len (testpatt):
                testpatt [z] = testpatt [z] - testrect [0]
                testpatt [z+1] = testpatt [z+1] - testrect [1]
                z = z + 2
            if patt == testpatt:
                lmr = lmr + [testrect]
        clist = clist [2:]
    return (lmr)

block = pattern ("""
**
**
""")

hblinker = pattern ("""
***
""")

vblinker = pattern ("""
*
*
*
""")

gliderse0wrapped = pattern ("""
.....
..*..
...*.
.***.
.....
""")

gliderse1wrapped = pattern ("""
.....
.*.*.
..**.
..*..
.....
""")

gliderse2wrapped = pattern ("""
.....
...*.
.*.*.
..**.
.....
""")

gliderse3wrapped = pattern ("""
.....
.*...
..**.
.**..
.....
""")

glidersw0wrapped = pattern ("""
.....
..*..
.*...
.***.
.....
""")

glidersw1wrapped = pattern ("""
.....
.*.*.
.**..
..*..
.....
""")

glidersw2wrapped = pattern ("""
.....
.*...
.*.*.
.**..
.....
""")

glidersw3wrapped = pattern ("""
.....
...*.
.**..
..**.
.....
""")

glidernw0wrapped = pattern ("""
.....
.***.
.*...
..*..
.....
""")

glidernw1wrapped = pattern ("""
.....
..*..
.**..
.*.*.
.....
""")

glidernw2wrapped = pattern ("""
.....
.**..
.*.*.
.*...
.....
""")

glidernw3wrapped = pattern ("""
.....
..**.
.**..
...*.
.....
""")

gliderne0wrapped = pattern ("""
.....
.***.
...*.
..*..
.....
""")

gliderne1wrapped = pattern ("""
.....
..*..
..**.
.*.*.
.....
""")

gliderne2wrapped = pattern ("""
.....
..**.
.*.*.
...*.
.....
""")

gliderne3wrapped = pattern ("""
.....
.**..
..**.
.*...
.....
""")


lwsse0wrapped = pattern ("""
.......
..****.
.*...*.
.....*.
.*..*..
.......
""")

lwsse1wrapped = pattern ("""
.......
..**...
.****..
.**.**.
...**..
.......
""")

lwsse2wrapped = pattern ("""
.......
.*..*..
.....*.
.*...*.
..****.
.......
""")

lwsse3wrapped = pattern ("""
.......
...**..
.**.**.
.****..
..**...
.......
""")


lwsss0wrapped = pattern ("""
......
.*.*..
....*.
....*.
.*..*.
..***.
......
""")

lwsss1wrapped = pattern ("""
......
..**..
..***.
.*.**.
.***..
..*...
......
""")

lwsss2wrapped = pattern ("""
......
..*.*.
.*....
.*....
.*..*.
.***..
......
""")

lwsss3wrapped = pattern ("""
......
..**..
.***..
.**.*.
..***.
...*..
......
""")

lwssw0wrapped = pattern ("""
.......
.****..
.*...*.
.*.....
..*..*.
.......
""")

lwssw1wrapped = pattern ("""
.......
...**..
..****.
.**.**.
..**...
.......
""")

lwssw2wrapped = pattern ("""
.......
..*..*.
.*.....
.*...*.
.****..
.......
""")

lwssw3wrapped = pattern ("""
.......
..**...
.**.**.
..****.
...**..
.......
""")

lwssn0wrapped = pattern ("""
......
..***.
.*..*.
....*.
....*.
.*.*..
......
""")

lwssn1wrapped = pattern ("""
......
..*...
.***..
.*.**.
..***.
..**..
......
""")

lwssn2wrapped = pattern ("""
......
.***..
.*..*.
.*....
.*....
..*.*.
......
""")

lwssn3wrapped = pattern ("""
......
...*..
..***.
.**.*.
.***..
..**..
......
""")

mwsse0wrapped = pattern ("""
........
..*****.
.*....*.
......*.
.*...*..
...*....
........
""")

mwsse1wrapped = pattern ("""
........
..***...
.*****..
.***.**.
....**..
........
""")

mwsse2wrapped = pattern ("""
........
...*....
.*...*..
......*.
.*....*.
..*****.
........
""")

mwsse3wrapped = pattern ("""
........
....**..
.***.**.
.*****..
..***...
........
""")


mwsss0wrapped = pattern ("""
.......
..*.*..
.....*.
.*...*.
.....*.
..*..*.
...***.
.......
""")

mwsss1wrapped = pattern ("""
......
..**..
..***.
..***.
.*.**.
.***..
..*...
......
""")

mwsss2wrapped = pattern ("""
.......
..*.*..
.*.....
.*...*.
.*.....
.*..*..
.***...
.......
""")

mwsss3wrapped = pattern ("""
......
..**..
.***..
.***..
.**.*.
..***.
...*..
......
""")

mwssw0wrapped = pattern ("""
........
.*****..
.*....*.
.*......
..*...*.
....*...
........
""")

mwssw1wrapped = pattern ("""
........
...***..
..*****.
.**.***.
..**....
........
""")

mwssw2wrapped = pattern ("""
........
....*...
..*...*.
.*......
.*....*.
.*****..
........
""")

mwssw3wrapped = pattern ("""
........
..**....
.**.***.
..*****.
...***..
........
""")

mwssn0wrapped = pattern ("""
.......
...***.
..*..*.
.....*.
.*...*.
.....*.
..*.*..
.......
""")

mwssn1wrapped = pattern ("""
......
..*...
.***..
.*.**.
..***.
..***.
..**..
......
""")

mwssn2wrapped = pattern ("""
.......
.***...
.*..*..
.*.....
.*...*.
.*.....
..*.*..
.......
""")

mwssn3wrapped = pattern ("""
......
...*..
..***.
.**.*.
.***..
.***..
..**..
......
""")

hwsse0wrapped = pattern ("""
.........
..******.
.*.....*.
.......*.
.*....*..
...**....
.........
""")

hwsse1wrapped = pattern ("""
.........
..****...
.******..
.****.**.
.....**..
.........
""")

hwsse2wrapped = pattern ("""
.........
...**....
.*....*..
.......*.
.*.....*.
..******.
.........
""")

hwsse3wrapped = pattern ("""
.........
.....**..
.****.**.
.******..
..****...
.........
""")


hwsss0wrapped = pattern ("""
.......
..*.*..
.....*.
.*...*.
.*...*.
.....*.
..*..*.
...***.
.......
""")

hwsss1wrapped = pattern ("""
......
..**..
..***.
..***.
..***.
.*.**.
.***..
..*...
......
""")

hwsss2wrapped = pattern ("""
.......
..*.*..
.*.....
.*...*.
.*...*.
.*.....
.*..*..
.***...
.......
""")

hwsss3wrapped = pattern ("""
......
..**..
.***..
.***..
.***..
.**.*.
..***.
...*..
......
""")


hwssw0wrapped = pattern ("""
.........
.******..
.*.....*.
.*.......
..*....*.
....**...
.........
""")

hwssw1wrapped = pattern ("""
.........
...****..
..******.
.**.****.
..**.....
.........
""")

hwssw2wrapped = pattern ("""
.........
....**...
..*....*.
.*.......
.*.....*.
.******..
.........
""")

hwssw3wrapped = pattern ("""
.........
..**.....
.**.****.
..******.
...****..
.........
""")


hwssn0wrapped = pattern ("""
.......
...***.
..*..*.
.....*.
.*...*.
.*...*.
.....*.
..*.*..
.......
""")

hwssn1wrapped = pattern ("""
......
..*...
.***..
.*.**.
..***.
..***.
..***.
..**..
......
""")

hwssn2wrapped = pattern ("""
.......
.***...
.*..*..
.*.....
.*...*.
.*...*.
.*.....
..*.*..
.......
""")

hwssn3wrapped = pattern ("""
......
...*..
..***.
.**.*.
.***..
.***..
.***..
..**..
......
""")
To use the code, write a simple script such as:

Code: Select all

import sys
import golly as g
from glife import *
import quiescentauton as q


if q.testquiescence (60):
    g.show ("quiescent")
else:
    g.show ("active")

wildmyron
Posts: 1544
Joined: August 9th, 2013, 12:45 am
Location: Western Australia

Re: Golly scripts

Post by wildmyron » October 17th, 2014, 6:11 am

dvgrn wrote:
codeholic wrote:Is there an easy way to rotate clockwise/counterclockwise a cell array?
In a regular square neighborhood rule, not hexagonal?

putcells(), transform(), and parse() all have optional transform parameters. Sample usage -- draw something in a new universe between (0,0) and (99,99) before you run it:

Code: Select all

import golly as g
all=g.getcells(g.getrect())
g.putcells(all,100,0,0,-1,1,0) # clockwise turn
g.putcells(all,0,100,0,1,-1,0)  # counterclockwise
g.putcells(all,100,100,-1,0,0,-1) # 180 degrees
g.fit()
But maybe golly.transform() is a better answer, if you want to put a cell array in and get a cell array out. (?)
This script demonstrates usage of matrices to rotate patterns as cell lists in hexagonal rules. It takes the selection and pastes copies of it rotated by multiples of 60deg, as well as rotation followed by a flip. Because the rotation is around the origin the selection is translated to the origin, transformed and then translated back when pasted into the layer. The matrices could readily be used with glife but I haven't done so here.

The essence of the trick is that in Golly's hexagonal neighbourhood - which is embedded within the Moore neighbourhood - rotation by 60 deg corresponds to a 90deg rotation and then a shear.

Code: Select all

# Hexagonal transformations
import golly as g 

if g.empty(): g.exit("There is no pattern.")
rect = g.getselrect() 
if len(rect) == 0: g.exit("There is no selection.")
x = rect[0] + rect[2]//2
y = rect[1] + rect[3]//2

clist = g.getcells(rect)

if (len(clist) % 2 == 0):
    cellints = 2
else:
    cellints = 3
pop = len(clist) // cellints

# Translate centre to origin
for ii in xrange(0, cellints*pop, cellints):
    clist[ii] -= x
    clist[ii+1] -= y

# Identity - I
g.putcells(clist, x, y, 1, 0, 0, 1)

# 60 cw - 90 cw then shear x
g.putcells(clist, x+30, y, 1, -1, 1, 0)

# 120 cw - 90 cw then shear y
g.putcells(clist, x+60, y, 0, -1, 1, -1)

# 180 - 180
g.putcells(clist, x+90, y, -1, 0, 0, -1)

# 120 ccw - 90 ccw then shear x
g.putcells(clist, x+120, y, -1, 1, -1, 0)

# 60 ccw - 90 ccw then shear y
g.putcells(clist, x+150, y, 0, 1, -1, 1)

# Swap xy - swap xy
g.putcells(clist, x, y+30, 0, 1, 1, 0)

# 60 ccw flip - flip x then shear x
g.putcells(clist, x+30, y+30, -1, 1, 0, 1)

# 120 ccw flip - flip x then shear y
g.putcells(clist, x+60, y+30, -1, 0, -1, 1)

# Swap xy flip - swap xy flip
g.putcells(clist, x+90, y+30, 0, -1, -1, 0)

# 120 cw flip - flip y then shear x
g.putcells(clist, x+120, y+30, 1, -1, 0, -1)

# 60 cw flip - flip y then shear y
g.putcells(clist, x+150, y+30, 1, 0, 1, -1)
The 5S project (Smallest Spaceships Supporting Specific Speeds) is now maintained by AforAmpere. The latest collection is hosted on GitHub and contains well over 1,000,000 spaceships.

Semi-active here - recovering from a severe case of LWTDS.

User avatar
simsim314
Posts: 1823
Joined: February 10th, 2014, 1:27 pm

Re: Golly scripts

Post by simsim314 » December 5th, 2014, 5:40 am

Blazingly fast LifeHistory2Life script:

Code: Select all

#Blazingly fast LifeHistory to Life converter
#Creates special rule and run it for one generation then switch to Life 
#Replace 2k + 1-> 1 and 2k -> 0
#Preserves step
import golly as g 
import os

if not(g.getrule()[:11]=="LifeHistory" or g.getrule()=="HistoricalLife" or g.getrule()=="CBRLife"):
   g.exit()
   
def CreateRule():
	fname = os.path.join(g.getdir("rules"), "LifeHistory2Life.rule")
	with open(fname, 'wb') as f:
		f.write('@RULE LifeHistory2Life\n')
		f.write('\n')
		f.write('@TABLE\n')
		f.write('n_states:7\n')
		f.write('neighborhood:vonNeumann\n')
		f.write('symmetries:none\n')
		f.write('\n')
		f.write('var a={0,1,2,3,4,5,6}\n')
		f.write('var b={a}\n')
		f.write('var c={a}\n')
		f.write('var d={a}\n')
		f.write('var f={a}\n')
		f.write('\n')
		f.write('1,a,b,c,d,1\n')
		f.write('2,a,b,c,d,0\n')
		f.write('3,a,b,c,d,1\n')
		f.write('4,a,b,c,d,0\n')
		f.write('5,a,b,c,d,1\n')
		f.write('6,a,b,c,d,0\n')
		
		
CreateRule()
g.setrule("LifeHistory2Life")
g.run(1)
step = g.getstep()
g.setrule("B3/S23")
g.setalgo("HashLife")
g.setstep(step)
g.setgen("-1")
And a script to add text in LifeHistory (state 4):

Code: Select all

import golly as g
from glife.text import make_text

if g.numstates() - 1 < 4:
   g.exit("Please select LifeHistory rule")

val = g.getstring("Enter string to place in golly", "Write here", "String Selection") 

t = make_text(val, "mono")
newt = []
cnt = 0 

for i in t:
   cnt += 1
   newt.append(i)
   
   if cnt % 2 == 0:
      newt.append(4)
      
if len(newt) % 2 == 0:
   newt.append(0)
   
if g.getselrect() == []:
   g.putcells(newt)
else:
   rect = g.getselrect()
   g.putcells(newt, rect[0], rect[1])
Those scripts are result of this discussion with dvgrn.
Last edited by simsim314 on December 5th, 2014, 10:28 am, edited 1 time in total.

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

Re: Golly scripts

Post by dvgrn » December 5th, 2014, 9:59 am

simsim314 wrote:Blazingly fast LifeHistory2Life script:
...
Those scripts are result of this discussion with dvgrn.
EDIT [from other thread] Notice this script is raising the generation by one. It's also sometimes for some reason shows the pattern in LifeHistory2Life rule instead of the original LifeHistory. I didn't manage to reproduce this bug, but it's sometimes happens.
You can take care of the generation change very easily with

g.setgen("-1")

Haven't seen the other problem yet. The code seems straightforward enough, so I'm not sure why the script would get interrupted there in the last few lines.

User avatar
simsim314
Posts: 1823
Joined: February 10th, 2014, 1:27 pm

Re: Golly scripts

Post by simsim314 » December 5th, 2014, 10:36 am

dvgrn wrote:g.setgen("-1")
Change done to the script posted here. Thx.
dvgrn wrote:Haven't seen the other problem yet. The code seems straightforward enough, so I'm not sure why the script would get interrupted there in the last few lines.
It's not exactly interrupted. What happens is the script looks OK, but when you chose "reset" or "undo" option, sometimes it brings you back to the LifeHistory2Life state instead to LifeHistory. This is golly bug, that happens from time to time, sometimes the undo works fine and the reset fails and sometimes the opposite, but usually it works fine - so I couldn't find steps to reproduce the issue. Anyway using it for a while now, and in general it doesn't cause any issues.

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

Re: Golly scripts

Post by dvgrn » December 5th, 2014, 11:33 am

simsim314 wrote:
dvgrn wrote:Haven't seen the other problem yet. The code seems straightforward enough, so I'm not sure why the script would get interrupted there in the last few lines.
It's not exactly interrupted. What happens is the script looks OK, but when you chose "reset" or "undo" option, sometimes it brings you back to the LifeHistory2Life state instead to LifeHistory. This is golly bug, that happens from time to time, sometimes the undo works fine and the reset fails and sometimes the opposite, but usually it works fine - so I couldn't find steps to reproduce the issue. Anyway using it for a while now, and in general it doesn't cause any issues.
Ah, that problem. I've been trying to find steps to reproduce what I think is a related bug for years now. It happens rarely and apparently randomly, and usually you don't lose work -- there's generally some way to combine Reset, Undo and Redo to get back to where you were, more or less.

But if you're doing a lot of editing combined with script-running, you can get into situations where as you step through Undo or Redo, changes to the universe are placed in the wrong locations relative to other features -- very strange. I suspect that this is somehow related to the incorrect-rule bug; at least, they both involve some kind of confusion in the Undo buffer.

User avatar
simsim314
Posts: 1823
Joined: February 10th, 2014, 1:27 pm

Re: Golly scripts

Post by simsim314 » December 5th, 2014, 1:48 pm

Here is another script for glider roll-back in the spirit of last days ideas. It uses two rules, one converts gliders in 16 possible phases and orientations into a single state (and back), and then uses another rule to roll-back the "gliders" any amount of iterations, then the script switch it back to gliders and usual Life rule.

Code: Select all

import golly as g 
import os 

def CreateRules():
	fname = os.path.join(g.getdir("rules"), "GliderDetection.rule")
	with open(fname, 'wb') as f:
		f.write('@RULE GliderDetection\n')
		f.write('\n')
		f.write('@TABLE\n')
		f.write('n_states:18\n')
		f.write('neighborhood:Moore\n')
		f.write('symmetries:none\n')
		f.write('\n')
		f.write('var a = {0, 1}\n')
		f.write('var b = {a}\n')
		f.write('var c = {a}\n')
		f.write('var d = {a}\n')
		f.write('var e = {a}\n')
		f.write('var f = {a}\n')
		f.write('var g = {a}\n')
		f.write('var h = {a}\n')
		f.write('\n')
		f.write('0,1,1,0,0,1,0,1,1,2\n')
		f.write('1,1,0,0,1,0,1,1,0,3\n')
		f.write('0,1,0,1,0,0,1,1,1,4\n')
		f.write('1,1,1,0,1,0,0,1,0,5\n')
		f.write('\n')
		f.write('0,1,1,1,0,1,0,0,1,6\n')
		f.write('1,1,0,1,1,0,1,0,0,7\n')
		f.write('0,1,1,1,1,0,0,1,0,8\n')
		f.write('1,1,0,1,0,0,1,0,1,9\n')
		f.write('\n')
		f.write('0,1,0,1,1,1,1,0,0,10\n')
		f.write('1,0,1,1,0,1,0,0,1,11\n')
		f.write('0,0,1,1,1,1,0,1,0,12\n')
		f.write('1,0,0,1,0,1,1,0,1,13\n')
		f.write('\n')
		f.write('0,1,0,0,1,1,1,1,0,14\n')
		f.write('1,0,1,0,0,1,0,1,1,15\n')
		f.write('0,0,0,1,0,1,1,1,1,16\n')
		f.write('1,0,1,0,1,1,0,1,0,17\n')
		f.write('\n')
		f.write('1,a,b,c,d,e,f,g,h,0\n')
		f.write('\n')
		f.write('\n')
		f.write('0,0,0,0,13,0,0,0,0,1\n')
		f.write('13,0,0,0,0,0,0,0,0,1\n')
		f.write('0,0,0,0,0,0,0,13,0,1\n')
		f.write('0,0,13,0,0,0,0,0,0,1\n')
		f.write('0,13,0,0,0,0,0,0,0,1\n')
		f.write('\n')
		f.write('0,0,0,0,9,0,0,0,0,1\n')
		f.write('0,0,0,0,0,9,0,0,0,1\n')
		f.write('9,0,0,0,0,0,0,0,0,1\n')
		f.write('0,0,0,0,0,0,0,9,0,1\n')
		f.write('0,0,9,0,0,0,0,0,0,1\n')
		f.write('\n')
		f.write('0,0,0,0,0,0,12,0,0,1\n')
		f.write('0,0,0,12,0,0,0,0,0,1\n')
		f.write('12,0,0,0,0,0,0,0,0,0\n')
		f.write('0,0,0,0,0,0,0,12,0,1\n')
		f.write('0,12,0,0,0,0,0,0,0,1\n')
		f.write('0,0,0,0,0,0,0,0,12,1\n')
		f.write('\n')
		f.write('0,0,0,0,0,8,0,0,0,1\n')
		f.write('0,0,0,0,0,0,8,0,0,1\n')
		f.write('0,0,0,8,0,0,0,0,0,1\n')
		f.write('8,0,0,0,0,0,0,0,0,0\n')
		f.write('0,0,0,0,0,0,0,8,0,1\n')
		f.write('0,0,0,0,0,0,0,0,8,1\n')
		f.write('\n')
		f.write('0,0,0,0,0,0,5,0,0,1\n')
		f.write('0,0,0,0,0,5,0,0,0,1\n')
		f.write('0,0,0,5,0,0,0,0,0,1\n')
		f.write('5,0,0,0,0,0,0,0,0,1\n')
		f.write('0,0,0,0,0,0,0,0,5,1\n')
		f.write('\n')
		f.write('0,0,0,0,0,0,17,0,0,1\n')
		f.write('0,0,0,17,0,0,0,0,0,1\n')
		f.write('17,0,0,0,0,0,0,0,0,1\n')
		f.write('0,17,0,0,0,0,0,0,0,1\n')
		f.write('0,0,0,0,0,0,0,0,17,1\n')
		f.write('\n')
		f.write('0,0,0,0,4,0,0,0,0,1\n')
		f.write('0,0,0,0,0,4,0,0,0,1\n')
		f.write('0,0,0,4,0,0,0,0,0,1\n')
		f.write('4,0,0,0,0,0,0,0,0,0\n')
		f.write('0,0,0,0,0,0,0,4,0,1\n')
		f.write('0,0,4,0,0,0,0,0,0,1\n')
		f.write('\n')
		f.write('0,0,0,0,16,0,0,0,0,1\n')
		f.write('0,0,0,16,0,0,0,0,0,1\n')
		f.write('16,0,0,0,0,0,0,0,0,0\n')
		f.write('0,0,0,0,0,0,0,16,0,1\n')
		f.write('0,0,16,0,0,0,0,0,0,1\n')
		f.write('0,16,0,0,0,0,0,0,0,1\n')
		f.write('\n')
		f.write('0,0,0,0,11,0,0,0,0,1\n')
		f.write('0,0,0,0,0,0,11,0,0,1\n')
		f.write('11,0,0,0,0,0,0,0,0,1\n')
		f.write('0,0,0,0,0,0,0,11,0,1\n')
		f.write('0,11,0,0,0,0,0,0,0,1\n')
		f.write('\n')
		f.write('0,0,0,0,0,7,0,0,0,1\n')
		f.write('7,0,0,0,0,0,0,0,0,1\n')
		f.write('0,0,0,0,0,0,0,7,0,1\n')
		f.write('0,0,7,0,0,0,0,0,0,1\n')
		f.write('0,0,0,0,0,0,0,0,7,1\n')
		f.write('\n')
		f.write('0,0,0,0,0,10,0,0,0,1\n')
		f.write('10,0,0,0,0,0,0,0,0,0\n')
		f.write('0,0,0,0,0,0,0,10,0,1\n')
		f.write('0,0,10,0,0,0,0,0,0,1\n')
		f.write('0,10,0,0,0,0,0,0,0,1\n')
		f.write('0,0,0,0,0,0,0,0,10,1\n')
		f.write('\n')
		f.write('0,0,0,0,6,0,0,0,0,1\n')
		f.write('0,0,0,0,0,6,0,0,0,1\n')
		f.write('0,0,0,0,0,0,6,0,0,1\n')
		f.write('6,0,0,0,0,0,0,0,0,0\n')
		f.write('0,0,0,0,0,0,0,6,0,1\n')
		f.write('0,6,0,0,0,0,0,0,0,1\n')
		f.write('\n')
		f.write('0,0,0,0,0,3,0,0,0,1\n')
		f.write('0,0,0,3,0,0,0,0,0,1\n')
		f.write('3,0,0,0,0,0,0,0,0,1\n')
		f.write('0,0,3,0,0,0,0,0,0,1\n')
		f.write('0,0,0,0,0,0,0,0,3,1\n')
		f.write('\n')
		f.write('0,0,0,0,15,0,0,0,0,1\n')
		f.write('0,0,0,0,0,0,15,0,0,1\n')
		f.write('0,0,0,15,0,0,0,0,0,1\n')
		f.write('15,0,0,0,0,0,0,0,0,1\n')
		f.write('0,15,0,0,0,0,0,0,0,1\n')
		f.write('\n')
		f.write('0,0,0,0,2,0,0,0,0,1\n')
		f.write('0,0,0,0,0,2,0,0,0,1\n')
		f.write('0,0,0,0,0,0,2,0,0,1\n')
		f.write('0,0,0,2,0,0,0,0,0,1\n')
		f.write('2,0,0,0,0,0,0,0,0,0\n')
		f.write('0,2,0,0,0,0,0,0,0,1\n')
		f.write('\n')
		f.write('0,0,0,0,0,14,0,0,0,1\n')
		f.write('0,0,0,14,0,0,0,0,0,1\n')
		f.write('14,0,0,0,0,0,0,0,0,0\n')
		f.write('0,0,14,0,0,0,0,0,0,1\n')
		f.write('0,14,0,0,0,0,0,0,0,1\n')
		f.write('0,0,0,0,0,0,0,0,14,1\n')

	fname = os.path.join(g.getdir("rules"), "GliderRunBack.rule")
	with open(fname, 'wb') as f:
		f.write('@RULE GliderRunBack\n')
		f.write('\n')
		f.write('@TABLE\n')
		f.write('n_states:18\n')
		f.write('neighborhood:Moore\n')
		f.write('symmetries:none\n')
		f.write('\n')
		f.write('var a = {0, 1}\n')
		f.write('var b = {a}\n')
		f.write('var c = {a}\n')
		f.write('var d = {a}\n')
		f.write('var e = {a}\n')
		f.write('var f = {a}\n')
		f.write('var g = {a}\n')
		f.write('var h = {a}\n')
		f.write('\n')
		f.write('2,0,0,0,0,0,0,0,0,5\n')
		f.write('\n')
		f.write('5,0,0,0,0,0,0,0,0,0\n')
		f.write('0,0,0,0,0,0,0,5,0,4\n')
		f.write('\n')
		f.write('4,0,0,0,0,0,0,0,0,3\n')
		f.write('\n')
		f.write('3,0,0,0,0,0,0,0,0,0\n')
		f.write('0,3,0,0,0,0,0,0,0,2\n')
		f.write('\n')
		f.write('\n')
		f.write('7,0,0,0,0,0,0,0,0,0\n')
		f.write('0,7,0,0,0,0,0,0,0,6\n')
		f.write('\n')
		f.write('6,0,0,0,0,0,0,0,0,9\n')
		f.write('\n')
		f.write('9,0,0,0,0,0,0,0,0,0\n')
		f.write('0,0,0,9,0,0,0,0,0,8\n')
		f.write('\n')
		f.write('8,0,0,0,0,0,0,0,0,7\n')
		f.write('\n')
		f.write('\n')
		f.write('11,0,0,0,0,0,0,0,0,0\n')
		f.write('0,0,0,0,0,11,0,0,0,10\n')
		f.write('\n')
		f.write('12,0,0,0,0,0,0,0,0,11\n')
		f.write('\n')
		f.write('13,0,0,0,0,0,0,0,0,0\n')
		f.write('0,0,0,13,0,0,0,0,0,12\n')
		f.write('\n')
		f.write('10,0,0,0,0,0,0,0,0,13\n')
		f.write('\n')
		f.write('\n')
		f.write('14,0,0,0,0,0,0,0,0,17\n')
		f.write('\n')
		f.write('17,0,0,0,0,0,0,0,0,0\n')
		f.write('0,0,0,0,0,0,0,17,0,16\n')
		f.write('\n')
		f.write('16,0,0,0,0,0,0,0,0,15\n')
		f.write('\n')
		f.write('15,0,0,0,0,0,0,0,0,0\n')
		f.write('0,0,0,0,0,15,0,0,0,14\n')

def GliderBack(num):
	g.setrule("GliderDetection")
	g.run(1)
	g.setrule("GliderRunBack")
	g.run(num)
	g.setrule("GliderDetection")
	g.run(1)
	
CreateRules()
s = g.getstring("How many generation run back?", "1", "Iteration Chooser")

try:
	GliderBack(int(s))
	g.setrule("B3/S23")
	g.setalgo("HashLife")
except:
	g.show("Failed to run back" + s + "generations")
NOTE The script assumes gliders only. If you have something else, it will probably be deleted.

User avatar
calcyman
Moderator
Posts: 2936
Joined: June 1st, 2009, 4:32 pm

Re: Golly scripts

Post by calcyman » December 5th, 2014, 9:29 pm

But if you're doing a lot of editing combined with script-running, you can get into situations where as you step through Undo or Redo, changes to the universe are placed in the wrong locations relative to other features -- very strange. I suspect that this is somehow related to the incorrect-rule bug; at least, they both involve some kind of confusion in the Undo buffer.
That's basically the unique major bug in Golly -- does it still exist? I haven't noticed it recently, but then again I haven't done much manual pattern editing recently.
What do you do with ill crystallographers? Take them to the mono-clinic!

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

Re: Golly scripts

Post by dvgrn » December 5th, 2014, 11:04 pm

calcyman wrote:
But if you're doing a lot of editing combined with script-running, you can get into situations where as you step through Undo or Redo, changes to the universe are placed in the wrong locations relative to other features -- very strange. I suspect that this is somehow related to the incorrect-rule bug; at least, they both involve some kind of confusion in the Undo buffer.
That's basically the unique major bug in Golly -- does it still exist? I haven't noticed it recently, but then again I haven't done much manual pattern editing recently.
I only see it when I'm a dozen edits deep in a really complicated construction -- and then it's always hopeless to reproduce the steps that led to the bug, because I can't reconstruct more than three or four steps back, and even those aren't exact.

I believe I've seen it even in the latest beta that I'm running, which is a 2.7b2 that Andrew set up for me to try to catch another bug that I used to see all the time, having to do with menu and toolbars suddenly going transparent, and then getting fixed as soon as some window besides Golly gets and loses the focus. I don't think that bug's fixed either, but like you I haven't had time to build anything big and interesting recently.*

@simsim314: are you running Golly 2.6, or an earlier version? If it's 2.6, then at least the Undo bug related to scripts-doing-rule-changes has been seen in a recent build.


* The Demonoid spaceship is waiting in the wings, but it may have to wait for a while -- until after the new year at the very least.

User avatar
simsim314
Posts: 1823
Joined: February 10th, 2014, 1:27 pm

Re: Golly scripts

Post by simsim314 » December 6th, 2014, 10:12 am

dvgrn wrote:@simsim314: are you running Golly 2.6
Yep...

--

If we talking about major golly bugs - so the most annoying bug is when I paste something into golly and it crushes, sometimes losing work. Maybe auto-save and crush recovery option would be nice addition. I couldn't manage to reproduce this bug, but it happens from time to time.

User avatar
simsim314
Posts: 1823
Joined: February 10th, 2014, 1:27 pm

Re: Golly scripts

Post by simsim314 » December 15th, 2014, 8:41 pm

Simple glider pertrubation script:

Code: Select all

import golly as g 

gld = g.parse("3o$o$bo!", -1, -1)

def Iterate(x, y, w, h, gld, pat, pw, ph, dx, dy):

	d = ph * 3
	
	for i in xrange(0, w):
		for j in xrange(0, h):
			for k in xrange(0, 4):
				g.putcells(pat, -pw, 0 + d)
				g.putcells(g.evolve(gld, k), -pw  + x + i,  y + j + d)
				d += ph * 3
		


def ClearRect(x, y, w, h):
	for i in xrange(0, w):
		for j in xrange(0, h):
			g.setcell(x + i, y + j, 0)
		
selRect = g.getselrect()

if selRect != []:
	patW = selRect[2]
	patH = selRect[3]
	pat = g.getcells(selRect)
	patDx =  selRect[0]
	patDy =  selRect[1] + 4 * patH
	
else:
	g.exit("Please select a pattern")

moving = True
selecting = False
val = g.getxy()
x = "a"
y = "a"

g.show("left click to place, right click to rotate")
g.update()

while True:
	event = g.getevent()
	
	if "click" in event:
		if "left" in event: 
				
			if moving:	
				
				g.show("select area to petrub the glider")
				moving =  False
				selecting = True
				g.update()
			
				
		elif "right" in event and moving:
			ClearRect(x - 1, y - 1, 3, 3)
			gld = g.transform(gld,0,0, 0, -1, 1, 0)
			ClearRect(x - 1, y - 1, 3, 3)
			g.putcells(gld, x, y)
			
		elif "right" in event and selecting and g.getselrect() != []:
				selrect = g.getselrect() 
				Iterate(selrect[0], selrect[1], selrect[2], selrect[3], gld, pat, patW, patH, patDx, patDy)
				g.exit()
				
	elif event == "" and moving and not selecting:
		if g.getxy() != "":
			val = g.getxy()
			
			if x != "a":
				ClearRect(x - 1, y - 1, 3, 3)
				g.putcells(under)
			
			
		if val == "":
			continue 
		
		x = int(val.split()[0])
		y = int(val.split()[1]) 
		
		under = g.getcells([x - 1, y - 1, 3, 3])
		g.putcells(gld, x, y)
		g.update()
	
	if selecting:
		g.doevent(event)
		
		if g.getselrect() != []:
			g.show("Select perturbation area. Right mouse click to generate")
			g.update()
	  
      
Also here is glider gun scripts and p14-1000 updated collection in single rle:
Last edited by simsim314 on December 17th, 2014, 7:40 pm, edited 2 times in total.

User avatar
simsim314
Posts: 1823
Joined: February 10th, 2014, 1:27 pm

Re: Golly scripts

Post by simsim314 » December 16th, 2014, 7:18 pm

Golly script that allows smart move of reflectors in golly (will iterate reflector back, allow move diagonally only in the correct orientation, of reflector's input):

Code: Select all

#This script recognize set of reflectors, and allows only according movement, while iterating it. 
#Written by Michael Simkin 2014
import golly as g 
import copy

data = []
data.append(["2o5b2o$2o5bo$5bobo$5b2o$b2o$bobo$2bo2$5b3o$5b3o$5b3o$8b3o$8b3o$8b3o!", "P8 Reflector"])
data.append(["22b2o$22bo$11b2o7bobo$11bobo6b2o$6b2o4b3o$5bo2bo4b3o$7bo4b3o$3bo7bobo$2bob2o5b2o$2bo$b2o!", "P30 Reflector"])
data.append(["13bo$11b3o$10bo$10b2o3$18b2ob2o$19bob2o$19bo$11b2o4b3o$11b2o3bo3b2o$16b4o2bo$2b2o15bob2o$bobo12b3o2bo$bo13bo5bo$2o14b5o$18bo!", "Snark1"])
data.append(["13bo$11b3o$10bo$10b2o3$18b2o$19bo$19bob2o$11b2o4b3o2bo$11b2o3bo3b2o$16b4o$2b2o15bo$bobo12b3o$bo13bo$2o14b5o$20bo$18bo$18b2o!", "Snark2"])

def FindPeriod(obj):
	evolved = g.evolve(obj, 1)
	
	for i in xrange(1, 1000):
		if str(evolved) == str(obj):
			return i
			
		evolved = g.evolve(evolved, 1)
	
	return -1
	
def GetSize(obj):
	maxX = -1
	maxY = -1
	minX = 1000
	minY = 1000
	
	for i in xrange(0, len(obj), 2):
		if obj[i] > maxX:
			maxX = obj[i]
		
		if obj[i + 1] > maxY:
			maxY = obj[i + 1]
		
		if obj[i] < minX:
			minX = obj[i]
		
		if obj[i + 1] < minY:
			minY = obj[i + 1]
	
	return (maxX - minX, maxY - minY)
	
def GetTransList():
	transList = []
	
	for i in xrange(-1, 2, 2):
		for j in xrange(-1, 2, 2):
			transList.append((i, 0, 0, j))
			transList.append((0, i, j, 0))
	
	return transList
	
def GetObjectClickArray(obj, objName, t, period):
		
	result = []
	
	
	for i in xrange(0, len(obj), 2):
		x = obj[i]
		y = obj[i + 1]
		
		l = copy.copy(obj)
		
		for j in xrange(0, len(obj), 2):
			l[j] -= x
			l[j + 1] -= y
			
		result.append([l, objName, t, period])
	
	return result
	

def GetObjectArray(iniobj):
	result = []
	transList = GetTransList()
	period = FindPeriod(iniobj[0])
	for i in xrange(0, period):
		
		obj = g.evolve(iniobj[0], i)
		
		for t in transList:
			dxx, dxy, dyx, dyy = t
			curobj = g.transform(obj, 0, 0, dxx, dxy, dyx, dyy)
			
			result.extend(GetObjectClickArray(curobj, iniobj[1], t, period))
		
	return result 
	
def IsObjectExists(objectArray, x, y):
	for obj, objName, t, p in objectArray:
		found = True
		
		for i in xrange(0, len(obj), 2):
			dx = obj[i]
			dy = obj[i + 1]
			
			if g.getcell(x + dx, y + dy) == 0:
				found = False
				break

		if found:
			return [obj, objName, x, y, t, p]
	
	return None
	
def GetObjectByClick(event):	
	
	x = int(event.split()[1])
	y = int(event.split()[2]) 
	
	found = False
	
	for i in [0, -1, 1, -2, 2]:
		for j in [0, -1, 1]:
			if found:
				break
				
			o =  IsObjectExists(objectArray, x + i, y + j)
			
			if o != None:
				g.show("found!")
				
				for k in xrange(0, len(o[0]), 2):
					dx = o[0][k]
					dy = o[0][k + 1]
					
					g.setcell(x + i + dx, y + j + dy, 0)
					
				found = True

				g.update()
				
				
	if 	found:
		return o
	else :
		return None
		
def ClearRect(x, y, w, h):
	for i in xrange(0, w):
		for j in xrange(0, h):
			g.setcell(x + i, y + j, 0)

def GetDirection(t):
	dxx, dxy, dyx, dyy = t
	
	if dxy == 0:
		return dxx * dyy
	else:
		return dxy * dyx

def GetEvolveDirection(t):
	dxx, dxy, dyx, dyy = t
	
	if dxy == 0:
		return -dxx
	else:
		return -dxy 

	
def UpdateMove(d, w, h, x0, y0, p, t):
	
	under = d[0]
	obj = d[1]
	x = d[2]
	y = d[3]
	
	
	if under != -1:
		ClearRect(x - w, y - h, 2 * w + 1, 2 * h + 1)
		g.putcells(under)
	
	
	val = g.getxy()
	
	if val == "":
		return 
		
	
	x1 = int(val.split()[0])
	y1 = y0 + GetDirection(t) * (x1 - x0)
	
	d[0] = g.getcells([x1 - w, y1 - h, 2 * w + 1, 2 * h + 1])
	
	#ClearRect(x1 - w, y1 - h, 2 * w + 1, 2 * h + 1)
	
	g.putcells(g.evolve(obj, p + GetEvolveDirection(t) * ((4 * (x1 - x0)) % p)), x1, y1)
	
	g.update()
	
	d[2] = x1
	d[3] = y1
	
def InitUpdateMove(obj, x, y):
	return [-1, obj, x, y]
	
	
objectArray = []

for d in data:
	objectArray.extend(GetObjectArray([g.parse(d[0]), d[1]]))
	
moving = False
g.show("Select known object with left click, exit with right click")
handling = False

while True:

	event = g.getevent()
	
	if handling:
		continue 
		
	handling = True

	if "click" in event:
	
		if "right" in event:
			g.show("finish smart movement")
			
			g.exit()
			
		if not moving:
			found = GetObjectByClick(event)
			
			if found != None:
				p = found[5]
				t = found[4]
				curMove = InitUpdateMove(found[0], found[2], found[3])
				g.show("Found: "  + str(found[1]) + ", click left to place and continue, right to place and exit")
				w, h = GetSize(found[0])
				moving = True
		else:
			if "left" in event:
				moving = False
				g.show("Object moved, select known object with left click, exit with right click")
				g.update()
			
			
	if moving and event == "":
		UpdateMove(curMove, w, h, found[2], found[3], p, t)
	
	handling = False


			
Try it on this sample:

Code: Select all

x = 298, y = 155, rule = B3/S23
234b2o3b2o$234b2o2bob3o$238bo4bo$234b4ob2o2bo$234bo2bobobob2o$237bobob
obo$238b2obobo$242bo2$228b2o$229bo7b2o$229bobo5b2o$230b2o7$240b2o$240b
o$241b3o$243bo15$214b2o$213bobo$215bo34$296bo$3o292bo$3o292b3o$3o10bo$
3b3o5b3o$3b3o4bo$3b3o4b2o264bo$276b3o$8bo270bo$7bobo268b2o$8b2o2b2o
136bobo$12b2o136b2o$151bo118b2o$270bo$267b2obo$267bo2b3o4b2o$268b2o3bo
3b2o$270b4o$270bo15b2o$271b3o12bobo$274bo13bo$269b5o14b2o$269bo$271bo$
270b2o11$116bo$116b3o$119bo$118b2o7$120b3o$119bo3bo$118bo5bo$118b2obob
2o6$123b2o$123bo$124b3o$126bo22$75b2o$74b2o$76bo!
Last edited by simsim314 on December 16th, 2014, 8:26 pm, edited 1 time in total.

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

Re: Golly scripts

Post by dvgrn » December 16th, 2014, 8:05 pm

simsim314 wrote:Golly script that allows smart move of reflectors in golly (will iterate reflector back, allow move diagonally only in the correct orientation, of reflector's input):...
Nice! This isn't quite out of beta yet -- e.g., the bounding box of the reflector will overwrite nearby objects, and sometimes a reflector is removed and not replaced anywhere (no doubt there's a reason for that, but I haven't figured out how I'm clicking wrong.) But it's a very nice start on the problem, anyway.

If you're up for a little more of a challenge, a really nice improvement would be the ability to shift-click two or more reflectors and move them diagonally as a group, adjusting the phasing as before. Sample pattern for selecting one, two, three, or four reflectors:

Code: Select all

x = 106, y = 76, rule = B3/S23
29bobo$29b2o$30bo10$57bo$57b2o$56b2obo$55bo2b3o$45bo8bobobo$45b3o5bobo
bo$48bo2b3o2bo$47b2o3bob2o$o52b2o$3o47bo3bo$3bo45bobo$2b2o41b2o2b2o$
45b2o6$2b2o3b2o$5bo$2bo5bo$3b2ob2o$4bobo$5bo$5bo3$7b2o$7bo$8b3o$10bo$
46b2o$46bo$39bo4bobo$38bobo3b2o$38b2obo$38b2ob2o$38b2obo$27b2o9bobo$
26bobo10bo$26bo$25b2o4$96bo$94b3o$93bo$93b2o3$101b2o$102bo$102bob2o$
94b2o4b3o2bo$94b2o3bo3b2o$99b4o$85b2o15bo$84bobo12b3o$84bo13bo$83b2o
14b5o$103bo$101bo$101b2o!

User avatar
simsim314
Posts: 1823
Joined: February 10th, 2014, 1:27 pm

Re: Golly scripts

Post by simsim314 » December 16th, 2014, 8:52 pm

Managed to reproduce few issues:

A: If you select the eater of this one, it leaves debris.

Code: Select all

x = 31, y = 20, rule = B3/S23
5$27b2o$27bo$19bo5bobo$18b4o3b2o$17b2obobo$16b3obo2bo$17b2obobo$8b2o8b
4o$7bobo9bo$7bo$6b2o!
B: Double click and the pattern will disappear.

--

Anyway fixed the move issue (was dumb bug in the first place - I just over controlled the visualization):

Code: Select all

#This script recognize set of reflectors, and allows only according movement, while iterating it. 
#Written by Michael Simkin 2014
import golly as g 
import copy

data = []
data.append(["2o5b2o$2o5bo$5bobo$5b2o$b2o$bobo$2bo2$5b3o$5b3o$5b3o$8b3o$8b3o$8b3o!", "P8 Reflector"])
data.append(["22b2o$22bo$11b2o7bobo$11bobo6b2o$6b2o4b3o$5bo2bo4b3o$7bo4b3o$3bo7bobo$2bob2o5b2o$2bo$b2o!", "P30 Reflector"])
data.append(["13bo$11b3o$10bo$10b2o3$18b2ob2o$19bob2o$19bo$11b2o4b3o$11b2o3bo3b2o$16b4o2bo$2b2o15bob2o$bobo12b3o2bo$bo13bo5bo$2o14b5o$18bo!", "Snark1"])
data.append(["13bo$11b3o$10bo$10b2o3$18b2o$19bo$19bob2o$11b2o4b3o2bo$11b2o3bo3b2o$16b4o$2b2o15bo$bobo12b3o$bo13bo$2o14b5o$20bo$18bo$18b2o!", "Snark2"])

def FindPeriod(obj):
	evolved = g.evolve(obj, 1)
	
	for i in xrange(1, 1000):
		if str(evolved) == str(obj):
			return i
			
		evolved = g.evolve(evolved, 1)
	
	return -1
	
def GetSize(obj):
	maxX = -1
	maxY = -1
	minX = 1000
	minY = 1000
	
	for i in xrange(0, len(obj), 2):
		if obj[i] > maxX:
			maxX = obj[i]
		
		if obj[i + 1] > maxY:
			maxY = obj[i + 1]
		
		if obj[i] < minX:
			minX = obj[i]
		
		if obj[i + 1] < minY:
			minY = obj[i + 1]
	
	return (maxX - minX, maxY - minY)
	
def GetTransList():
	transList = []
	
	for i in xrange(-1, 2, 2):
		for j in xrange(-1, 2, 2):
			transList.append((i, 0, 0, j))
			transList.append((0, i, j, 0))
	
	return transList
	
def GetObjectClickArray(obj, objName, t, period):
		
	result = []
	
	
	for i in xrange(0, len(obj), 2):
		x = obj[i]
		y = obj[i + 1]
		
		l = copy.copy(obj)
		
		for j in xrange(0, len(obj), 2):
			l[j] -= x
			l[j + 1] -= y
			
		result.append([l, objName, t, period])
	
	return result
	

def GetObjectArray(iniobj):
	result = []
	transList = GetTransList()
	period = FindPeriod(iniobj[0])
	for i in xrange(0, period):
		
		obj = g.evolve(iniobj[0], i)
		
		for t in transList:
			dxx, dxy, dyx, dyy = t
			curobj = g.transform(obj, 0, 0, dxx, dxy, dyx, dyy)
			
			result.extend(GetObjectClickArray(curobj, iniobj[1], t, period))
		
	return result 
	
def IsObjectExists(objectArray, x, y):
	for obj, objName, t, p in objectArray:
		found = True
		
		for i in xrange(0, len(obj), 2):
			dx = obj[i]
			dy = obj[i + 1]
			
			if g.getcell(x + dx, y + dy) == 0:
				found = False
				break

		if found:
			return [obj, objName, x, y, t, p]
	
	return None
	
def GetObjectByClick(event):	
	
	x = int(event.split()[1])
	y = int(event.split()[2]) 
	
	found = False
	
	for i in [0, -1, 1, -2, 2]:
		for j in [0, -1, 1]:
			if found:
				break
				
			o =  IsObjectExists(objectArray, x + i, y + j)
			
			if o != None:
				g.show("found!")
				
				for k in xrange(0, len(o[0]), 2):
					dx = o[0][k]
					dy = o[0][k + 1]
					
					g.setcell(x + i + dx, y + j + dy, 0)
					
				found = True

				g.update()
				
				
	if 	found:
		return o
	else :
		return None
		
def ClearRect(x, y, w, h):
	for i in xrange(0, w):
		for j in xrange(0, h):
			g.setcell(x + i, y + j, 0)

def GetDirection(t):
	dxx, dxy, dyx, dyy = t
	
	if dxy == 0:
		return dxx * dyy
	else:
		return dxy * dyx

def GetEvolveDirection(t):
	dxx, dxy, dyx, dyy = t
	
	if dxy == 0:
		return -dxx
	else:
		return -dxy 

	
def UpdateMove(d, w, h, x0, y0, p, t):
	
	under = d[0]
	obj = d[1]
	x = d[2]
	y = d[3]
	
	
	if under != -1:
		ClearRect(x - w, y - h, 2 * w + 1, 2 * h + 1)
		g.putcells(under)
	
	
	val = g.getxy()
	
	if val == "":
		return 
		
	
	x1 = int(val.split()[0])
	y1 = y0 + GetDirection(t) * (x1 - x0)
	
	d[0] = g.getcells([x1 - w, y1 - h, 2 * w + 1, 2 * h + 1])
	
	#ClearRect(x1 - w, y1 - h, 2 * w + 1, 2 * h + 1)
	
	g.putcells(g.evolve(obj, p + GetEvolveDirection(t) * ((4 * (x1 - x0)) % p)), x1, y1)
	
	g.update()
	
	d[2] = x1
	d[3] = y1
	
def InitUpdateMove(obj, x, y):
	return [-1, obj, x, y]
	
	
objectArray = []

for d in data:
	objectArray.extend(GetObjectArray([g.parse(d[0]), d[1]]))
	
moving = False
g.show("Select known object with left click, exit with right click")
handling = False

while True:

	event = g.getevent()
	
	if handling:
		continue 
		
	handling = True

	if "click" in event:
	
		if "right" in event:
			g.show("finish smart movement")
			
			g.exit()
			
		if not moving:
			found = GetObjectByClick(event)
			
			if found != None:
				p = found[5]
				t = found[4]
				curMove = InitUpdateMove(found[0], found[2], found[3])
				g.show("Found: "  + str(found[1]) + ", click left to place and continue, right to place and exit")
				w, h = GetSize(found[0])
				moving = True
		else:
			if "left" in event:
				moving = False
				g.show("Object moved, select known object with left click, exit with right click")
				g.update()
			
			
	if moving and event == "":
		UpdateMove(curMove, w, h, found[2], found[3], p, t)
	
	handling = False
EDIT Will gladly make Shift + click if you tell me how do I know whether shift is down or not?

EDIT2 I think it's not hard to lookup in the output diagonal in search for recognizable components. for starters it can just find the first living cell on the diagonal (with some width), if the living cell belong to recognizable component, will add it as well to movement object list.

EDIT3 Moved to other thread.

User avatar
Gustavo6046
Posts: 647
Joined: December 7th, 2013, 6:26 pm
Location: Brazil.

Re: Golly scripts

Post by Gustavo6046 » February 3rd, 2015, 5:52 pm

Sorry but how do I get pyton dll? It says it didn't found Python library!
*yawn* What a nothing-to-do day! Let's be the only person in the world to do CGOL during boring times. :)

User avatar
simsim314
Posts: 1823
Joined: February 10th, 2014, 1:27 pm

Re: Golly scripts

Post by simsim314 » February 4th, 2015, 4:01 am


User avatar
Gustavo6046
Posts: 647
Joined: December 7th, 2013, 6:26 pm
Location: Brazil.

Re: Golly scripts

Post by Gustavo6046 » February 4th, 2015, 2:19 pm

Oh, thanks! But it says the site is down.
*yawn* What a nothing-to-do day! Let's be the only person in the world to do CGOL during boring times. :)

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

Re: Golly scripts

Post by dvgrn » February 4th, 2015, 2:53 pm

Gustavo6046 wrote:Oh, thanks! But it says the site is down.
Keep trying, and maybe look around the Web for alternatives -- that link works fine on my machine.

You'll want the Python 2.7.x download, by the way, not the Python 3.x.

Post Reply