Page 7 of 23

Re: Script request thread

Posted: August 31st, 2017, 11:30 am
by muzik
I've been trying to make the phaselister script, but, being the idiot that I am, I'm getting stuck on step 1. I get an input box with stuff already in it just fine, but when i submit the information I get errors. Tried making it display the inputted variables on the top information bar thing in golly, which leads off into this error right here:

Code: Select all

Traceback (most recent call last):
File "<string>", line 1, in <module>
File
"C:\Users\.\Documents\CA\apps\sim\golly-3.0b3-win-64bit\golly-3.0b...\phaselister.py",
line 32, in <module>
g.show(x + y)
TypeError: must be string, not int
So either I'm lazy, not seeing something laughably obvious, or the script is trying to call another script and is getting invalid answers from it.

Here's the script so far, in case it is a fault with it directly:

Code: Select all

from glife import validint, inside
from string import lower
import golly as g

selrect = g.getselrect()
if len(selrect) == 0: g.exit("Error: Nothing seems to be selected")

# use same file name as in shift.lua
INIFileName = g.getdir("data") + "shift.ini"
oldparams = "10 10 and"
try:
    f = open(INIFileName, 'r')
    oldparams = f.readline()
    f.close()
except:
    # should only happen 1st time (INIFileName doesn't exist)
    pass

answer = g.getstring("enter rectangle dimensions\n" +
                     "(valid modes are h, default is or):",
                     oldparams, "Shift selection")
xym = answer.split()

# extract x and y amounts
if len(xym) == 0: g.exit()
if len(xym) == 1: g.exit("Supply x and y amounts separated by a space.")
if not validint(xym[0]): g.exit("Bad x value: " + xym[0])
if not validint(xym[1]): g.exit("Bad y value: " + xym[1])
x = int(xym[0])
y = int(xym[1])
gens = xym[2]
g.show(x + y)

Re: Script request thread

Posted: August 31st, 2017, 11:46 am
by dvgrn
muzik wrote:I've been trying to make the phaselister script, but, being the idiot that I am, I'm getting stuck on step 1. I get an input box with stuff already in it just fine, but when i submit the information I get errors. Tried making it display the inputted variables on the top information bar thing in golly, which leads off into this error right here:

Code: Select all

Traceback (most recent call last):
File "<string>", line 1, in <module>
File
"C:\Users\.\Documents\CA\apps\sim\golly-3.0b3-win-64bit\golly-3.0b...\phaselister.py",
line 32, in <module>
g.show(x + y)
TypeError: must be string, not int
No need to beat yourself up for getting errors -- that happens to everybody.

Also, Python often gives annoyingly irrelevant errors, in cases where the problem is really something like a missing parenthesis on the previous line... so watch out for that as you go forward. In this case Python really is trying hard to explain the actual problem to you, involving g.show(x + y).

g.show needs a string input, but you've put in a number. Whenever this kind of thing comes up, use str() to convert to a string: g.show(str(x + y))... or in this case, g.show("x="+str(x)+", y="+str(y)), or slightly less awkward might be g.show(str([x, y]) .

Re: Script request thread

Posted: September 16th, 2017, 1:17 am
by Saka
Can someone strip down the nt rule generator script to generate the transitions only? I'm absolutely horrible at classes.

Re: Script request thread

Posted: October 11th, 2017, 5:40 pm
by muzik
How about something like hexgrid.lua, but for simulating triangular rules?

Re: Script request thread

Posted: October 22nd, 2017, 9:06 pm
by muzik
Here's an idea I've had for a while: a script that takes a specified high-period oscillator and meshes together multiple copies of it, printing out any resultant guns, breeders, and new resultant oscillator periods that pop up.

Re: Script request thread

Posted: October 24th, 2017, 10:27 pm
by drc
Can someone modify nbsearch1 to make a separate layer and save all the unique results there?

Re: Script request thread

Posted: October 30th, 2017, 6:21 am
by wildmyron
drc wrote:Can someone modify nbsearch1 to make a separate layer and save all the unique results there?
This does the first part of what you want and also runs a lot faster by virtue of not calling g.new() for every pattern tested. There's still some further optimisation that could be done and there's no duplicate checking on the results, but I'll leave that for now. (Have a look at my scripts in the rulesrc thread for inspiration on that front). You could also very easily adapt this to check for spaceships at the same time as searching for oscillators if you so desired.

Code: Select all

import golly as g
import math

rule=g.getstring("Rule:","B3/S23")
algo=g.getstring("Algorithm:","QuickLife")

max_period=20
result_spacing=50

exclude_periods=[1]
if rule=="GlideLife":
    exclude_periods=[1,2,4]
if rule=="olife":
    exclude_periods=[1,2,3,4,5,12,10,35,6]
if rule=="B3/S23":
    exclude_periods=[1,2,3,15,8,5,4,6,30]
if rule=="tlife":
    exclude_periods=[1,2,5,4,3,6,8,33,12]
if rule=="salad":
    exclude_periods=[1,2,4,5,3,10,29,6,7]
if rule=="B2i3-r4cS23":
    exclude_periods=[1,2,5,8,16,10,14,13,3,4]
if rule=="B2inkce_S12":
    exclude_periods=[1,6,4,3,2,14,5,10,12]
if rule=="B2inkce3_S1":
    exclude_periods=[1,8,4,6]
if rule=="B3678/S235678":
    exclude_periods=[1,2,3,4,5,6,14,12,8,10,17,24,7,34,9,15,11]
if rule=="B013578/S02":
    exclude_periods=[1,2,3,4,5,6,7,8,9,10,11,12,15,16,20,21,22,23,24,29,30,32,33,34,47,48]
if rule=="MoveIt":
    exclude_periods=[1,2,24,8,12,4,3,16,48,6,32,5,14,11,10]
if rule=="B34tw5y_S23":
    exclude_periods=[1,2,4,7,3,10]
if rule=="B35678/S357":
    exclude_periods=[1,2,6,3,4,8,5,35,14,12,13]
if rule=="B2-aS12":
    exclude_periods=[1,3,4,6,26,14,2,12,7,5,10,42,19,11,16,28,9,78,24,8]
if rule=="B1e4ay5ai6i7eS0123eijr4atwri5ayn6cai7":
    exclude_periods=[1]
if rule=="B2in3S2-in37":
    exclude_periods=[1,2,5,3,4,8,10,6,12]
if rule=="B2in3S02-in3-n":
    exclude_periods=[1,4,2,8,7,6,5,10,3,9,16,12]
if rule=="B37/S2-i34q":
    exclude_periods=[1,2,5,4,3]
if rule=="B3/S235e":
    exclude_periods=[1,2,5,3,15,8]
if rule=="PuffLife":
    exclude_periods=[1,4,2,3,6,8]
if rule=="B3-k/S2-i3-k4cen":
    exclude_periods=[1,2,5,4,3]
if rule=="B34ek5ak/S2-c34iz5y":
    exclude_periods=[1,2,4,6]
if rule=="b2ce3aiys12aei3r":
    exclude_periods=[1,2,6,8,4,14,10]
if rule=="B3-cnry4-acery5i/S23-a4-jknqr5y8":
    exclude_periods=[1,2,4]
if rule=="B3/S23-a4eiktz":
    exclude_periods=[1,2,4,5,3,6,9,7]
if rule=="B34e5e/S2-in3-y5jk":
    exclude_periods=[1,2,4,13,3,10,6]
if rule=="B2e3-r5i8/S23-a4kz7c":
    exclude_periods=[1,2,7,4,9,14,5,6,3]


def osc_test():
    if g.empty():
        return [False]
    g.setstep(0)
    cells=g.getcells(g.getrect())
    hash=g.hash(g.getrect())
    for i in range(1,max_period):
        g.step()
        if g.empty():
            return [False]
        if g.hash(g.getrect())==hash:
            if g.getcells(g.getrect())==cells:
                if i not in exclude_periods:
                    return [True,i]
                else:
                    return [False]
    return [False]


def put_symm(cell_list,x0=0,y0=0,axx=1,axy=0,ayx=0,ayy=1,mode="or"):
    
    g.putcells(cell_list,x0,y0,axx,axy,ayx,ayy,mode)
    if symm=="C2_1" or symm=="C4_1" or symm=="D4_+1" or symm=="D8_1" or symm=="D4_x1":
        g.putcells(cell_list,-x0,-y0,-axx,-axy,-ayx,-ayy,mode)
    
    if symm=="C4_1" or symm=="D8_1":
        g.putcells(cell_list,y0,-x0,ayx,ayy,-axx,-axy,mode)
        g.putcells(cell_list,-y0,x0,-ayx,-ayy,axx,axy,mode)
    
    if symm=="C2_2" or symm=="D4_+2":
        g.putcells(cell_list,-x0-1,-y0,-axx,-axy,-ayx,-ayy,mode)
    
    if symm=="C2_4" or symm=="C4_4" or symm=="D4_+4" or symm=="D8_4" or symm=="D4_x4":
        g.putcells(cell_list,-x0-1,-y0-1,-axx,-axy,-ayx,-ayy,mode)
    
    if symm=="D2_+1" or symm=="D8_1" or symm=="D4_+1":
        g.putcells(cell_list,-x0,y0,-axx,-axy,ayx,ayy,mode)
    
    if symm=="D4_+1" or symm=="D8_1" or symm=="D4_+2":
        g.putcells(cell_list,x0,-y0,axx,axy,-ayx,-ayy,mode)
    
    if symm=="D2_+2" or symm=="D4_+2" or symm=="D4_+4" or symm=="D8_4":
        g.putcells(cell_list,-x0-1,y0,-axx,-axy,ayx,ayy,mode)
    
    if symm=="D4_+4" or symm=="D8_4":
        g.putcells(cell_list,x0,-y0-1,axx,axy,-ayx,-ayy,mode)
    
    if symm=="C4_4" or symm=="D8_4":
        g.putcells(cell_list,y0,-x0-1,ayx,ayy,-axx,-axy,mode)
        g.putcells(cell_list,-y0-1,x0,-ayx,-ayy,axx,axy,mode)
    
    if symm=="D8_4":
        g.putcells(cell_list,-y0-1,-x0-1,-ayx,-ayy,-axx,-axy,mode)
    
    if symm=="D2_x" or symm=="D8_1" or symm=="D8_4" or symm=="D4_x1" or symm=="D4_x4":
        g.putcells(cell_list,y0,x0,ayx,ayy,axx,axy,mode)
    
    if symm=="D4_x1" or symm=="D8_1":
        g.putcells(cell_list,-y0,-x0,-ayx,-ayy,-axx,-axy,mode)
    
    if symm=="D4_x4" or symm=="D8_4":
        g.putcells(cell_list,-y0-1,-x0-1,-ayx,-ayy,-axx,-axy,mode)
    
x=int(g.getstring("Size:","4"))

start=int(g.getstring("Start:"))

def next(max_x):
    w=0
    h=0
    
    while g.getcell(w,h)==1:
        g.setcell(w,h,0)
        w+=1
        if w==max_x:
            w=0
            h+=1
            if h==max_x:
                return True
    g.setcell(w,h,1)
    return False

def clear_layer():
    r = g.getrect()
    if r:
        g.select(r)
        g.clear(0)
    return

def main():
    g.new("BrutOsc")
    global symm
    
    count=start
    if start>2**(x**2):
        g.show("Start > "+str(2**(x**2)))
        return False
    for i in range(start):
        next(x)
    cell_list=g.getcells([0,0,x,x])
    
    g.setrule(rule)
    g.setalgo(algo)
    
    test_layer=g.getlayer()
    if g.numlayers()<g.maxlayers():
        results_layer=g.addlayer()
        g.setname('OscResults')
        g.setlayer(test_layer)
    else:
        resultslayer=-1
    results=0
    
    while True:
        for i in range(16):
            clear_layer()
            g.setbase(2)
            g.setstep(6)
            
            symm=["C1", "C2_1", "C2_2", "C2_4", "D2_x", "D2_+1", "D2_+2", "C4_1", "C4_4", "D4_x1", "D4_x4", "D4_+1", "D4_+2", "D4_+4", "D8_1", "D8_4"][i]
            put_symm(cell_list)
            
            g.step()
            
            v=osc_test()
            if v[0]:
                g.show(str(count)+"*16,   Period "+str(v[1]))
                osc = g.getcells(g.getrect())
                results+=1
                if results_layer>=0:
                    g.setlayer(results_layer)
                    g.putcells(osc, result_spacing*results, 0)
                    g.setname('OscResults (%d)' % results)
                    g.fit()
                    g.update()
                    g.setlayer(test_layer)
                else:
                    return True
        
        count+=1
        
        if count>2**(x**2):
            if results==0:
                g.setlayer(results_layer)
                g.dellayer()
                g.setlayer(test_layer)
            else:
                g.setlayer(results_layer)
            g.show("%d*16 patterns tested, %d solutions found." %(2**(x**2), results))
            return False
        
        if count%100==0:
            g.show("%d*16 patterns tested, %d solutions found so far." %(count, results))
            g.new("")
        else:
            clear_layer()
            
        g.putcells(cell_list)
        next(x)
        
        cell_list=g.getcells([0,0,x,x])

main()

Re: Script request thread

Posted: October 30th, 2017, 6:27 am
by Saka
That one "direct cycle oscar" thing (I think it's called bijoscar?) but for linear growths? Please?

Re: Script request thread

Posted: October 30th, 2017, 11:32 pm
by wildmyron
Saka wrote:That one "direct cycle oscar" thing (I think it's called bijoscar?) but for linear growths? Please?
This already exists in the form of linearlyse() from the Python version of apgsearch.
Is there anything preventing you from using linearlyse() to do what you want?

Re: Script request thread

Posted: October 31st, 2017, 3:40 am
by Saka
wildmyron wrote: This already exists in the form of linearlyse() from the Python version of apgsearch.
Is there anything preventing you from using linearlyse() to do what you want?
Ooh nice I didn't see that even I scrolled past it like 5 times.

Re: Script request thread

Posted: October 31st, 2017, 3:17 pm
by dani
wildmyron wrote:This does the first part of what you want and also runs a lot faster by virtue of not calling g.new() for every pattern tested.
Nice! I find this looks great with 'Tile Layers' on, as it makes a great side-by-side view of the search and its results.
Having a nbsearch2 version of this would be great, but I won't hassle you.

Re: Script request thread

Posted: November 8th, 2017, 6:04 am
by wildmyron
danny wrote:
wildmyron wrote:This does the first part of what you want and also runs a lot faster by virtue of not calling g.new() for every pattern tested.
Nice! I find this looks great with 'Tile Layers' on, as it makes a great side-by-side view of the search and its results.
Having a nbsearch2 version of this would be great, but I won't hassle you.
I was going to suggest that you give modifying nbsearch2 a go yourself - it's definitely worthwhile having enough of an understanding of programming languages to make small changes like this one. But I couldn't resist.

Code: Select all

import golly as g
import math
import random
from timeit import default_timer as timer

rule=g.getstring("Rule:","B3/S23")
algo=g.getstring("Algorithm:","QuickLife")
s=g.getstring("Symmetry","All")

symm=0
if s!="All":
    symm=s

#symm can be either C1, C2_1, C2_2, C2_4, D2_x, D2_+1, D2_+2, C4_1, C4_4, D4_x1, D4_x4, D4_+1, D4_+2, D4_+4, D8_1, D8_4, All, Rot

max_period=300
result_spacing=100
stab_step=7

exclude_periods=[1]
if rule=="GlideLife":
    exclude_periods=[1,2,4,6,12,16]
if rule=="olife":
    exclude_periods=[1,2,3,4,5,6,9,10,12,15,18,20,26,30,35]
if rule=="B3/S23":
    exclude_periods=[1,2,3,6,8,4,5,10,15,30,14]
if rule in ["tlife","B3/S2-i34q"]:
    exclude_periods=[1,2,4,5,160]
if rule=="salad":
    exclude_periods=[1,2,4]
if rule=="B2inkce_S12":
    exclude_periods=[1,2,4]
if rule=="B3678/S235678":
    exclude_periods=[1,2,3,4,6,12,8]
if rule=="MoveIt":
    exclude_periods=[1,2,3,4,6,8,12,16,24,32,48]
if rule=="B35678/S357":
    exclude_periods=[1,2,6,4,3,8,12,35,5,14,24,13,10,15]
if rule=="B2-aS12":
    exclude_periods=[1,14,6,3,2,4,7,26,42,9,28,12,78,16,48,236,24,84,182,13,156,5,130,21,10,208,234,15,11,70,8,19]
if rule=="B2i35r_S023-a4i":
    exclude_periods=[1,2,4]
if rule=="B2in3S02-in3-n":
    exclude_periods=[1,4,5,8,7,6,20,12,28,2,9,16,36,10,42,72,14,56,3,40,63,30,140,45,35]
if rule=="B37/S2-i34q":
    exclude_periods=[1,2,5,4,3,20]
if rule=="B3/S235e":
    exclude_periods=[1,2,15,3,5,10,8,30,4,6,14,40]
if rule=="randomnn":
    exclude_periods=[20,4,14,7,28,140,84]
if rule=="Rotator":
    exclude_periods=[12,40,120,4,60,10,20,24,8]
if rule=="B2ein3/S13":
    exclude_periods=[1,2,4,6,5,10]
if rule=="PuffLife":
    exclude_periods=[1,2,4,8,3,6,16,12]
if rule=="B3-k/S2-i3-k4cen":
    exclude_periods=[1,2,5,4,3]
if rule=="B34ek5ak/S2-c34iz5y":
    exclude_periods=[1,2,4,6]
if rule=="B35/S2":
    exclude_periods=[2,4,1,3]
if rule=="B3568/S256":
    exclude_periods=[1,2,3,4,6,12,5,10,15,20,14,42]
if rule=="B356/S234i":
    exclude_periods=[1,2,4,6,12]
if rule=="b2ce3aiys12aei3r":
    exclude_periods=[1,2,4,6,7,8,10,12,14,15,24,26,28,29,30,58,42,62,94,126,138,170,186,202,234,266]
if rule=="B3-cnry4-acery5i/S23-a4-jknqr5y8":
    exclude_periods=[1,2,36,92,4,28,12,18,8]
if rule=="B3/S23-a4eiktz":
    exclude_periods=[1,2,4,5,10,78,7,14,9,36,3,6]
if rule=="B34e5e/S2-in3-y5jk":
    exclude_periods=[1,2,4,10,13,26,6,3]
if rule=="B2e3-r5i8/S23-a4kz7c":
    exclude_periods=[1,2,7,14,4]
if rule=="B3/S23-e4k":
    exclude_periods=[1,2,4,5,6,10,98,294,14,22,12]
if rule=="B34aq5c/S135":
    exclude_periods=[1,2,4,3,6,13,26,8,12,52,39]
if rule=="B2-a3/S1c23-ainr4cekn":
    exclude_periods=[1,2,4,12,31,6,62,8,5,10,124,28,20]
if rule=="B2-a3-in/S23":
    exclude_periods=[1,2,6,4,44,12,3,16,9,18,132,5,8,36,220,20,30,22,60]
if rule=="B2-a3-in/S235c":
    exclude_periods=[1,2,4,3,6,44,12,10,20,132,16,60,5,58,8]

def osc_test():
    if g.empty():
        return False
    testcells=g.getcells(g.getrect())
    testpop=g.getpop() # String representation
    testhash=g.hash(g.getrect())
    for i in range(1,max_period):
        g.run(1)
        if g.empty():
            return False
        if g.getpop()==testpop and g.hash(g.getrect())==testhash:
            if g.getcells(g.getrect())==testcells:
                if i not in exclude_periods:
                    return True
                else:
                    return False
    return False


def put_symm(cell_list,x0=0,y0=0,axx=1,axy=0,ayx=0,ayy=1,mode="or"):
    global symm
   
    if s=="All":
        symm=["C1", "C2_1", "C2_2", "C2_4", "D2_x", "D2_+1", "D2_+2", "C4_1", "C4_4", "D4_x1", "D4_x4", "D4_+1", "D4_+2", "D4_+4", "D8_1", "D8_4"][random.randrange(16)]

    if s=="Rot":
        symm=["C1", "C2_1", "C2_2", "C2_4", "C4_1", "C4_4"][random.randrange(6)]
   
    # g.putcells(cell_list,x0,y0,axx,axy,ayx,ayy,mode)
    if symm=="C2_1" or symm=="C4_1" or symm=="D4_+1" or symm=="D8_1" or symm=="D4_x1":
        g.putcells(cell_list,-x0,-y0,-axx,-axy,-ayx,-ayy,mode)
   
    if symm=="C4_1" or symm=="D8_1":
        g.putcells(cell_list,y0,-x0,ayx,ayy,-axx,-axy,mode)
        g.putcells(cell_list,-y0,x0,-ayx,-ayy,axx,axy,mode)
   
    if symm=="C2_2" or symm=="D4_+2":
        g.putcells(cell_list,-x0-1,-y0,-axx,-axy,-ayx,-ayy,mode)
   
    if symm=="C2_4" or symm=="C4_4" or symm=="D4_+4" or symm=="D8_4" or symm=="D4_x4":
        g.putcells(cell_list,-x0-1,-y0-1,-axx,-axy,-ayx,-ayy,mode)
   
    if symm=="D2_+1" or symm=="D8_1" or symm=="D4_+1":
        g.putcells(cell_list,-x0,y0,-axx,-axy,ayx,ayy,mode)
   
    if symm=="D4_+1" or symm=="D8_1" or symm=="D4_+2":
        g.putcells(cell_list,x0,-y0,axx,axy,-ayx,-ayy,mode)
   
    if symm=="D2_+2" or symm=="D4_+2" or symm=="D4_+4" or symm=="D8_4":
        g.putcells(cell_list,-x0-1,y0,-axx,-axy,ayx,ayy,mode)
   
    if symm=="D4_+4" or symm=="D8_4":
        g.putcells(cell_list,x0,-y0-1,axx,axy,-ayx,-ayy,mode)
   
    if symm=="C4_4" or symm=="D8_4":
        g.putcells(cell_list,y0,-x0-1,ayx,ayy,-axx,-axy,mode)
        g.putcells(cell_list,-y0-1,x0,-ayx,-ayy,axx,axy,mode)
   
    if symm=="D8_4":
        g.putcells(cell_list,-y0-1,-x0-1,-ayx,-ayy,-axx,-axy,mode)
   
    if symm=="D2_x" or symm=="D8_1" or symm=="D8_4" or symm=="D4_x1" or symm=="D4_x4":
        g.putcells(cell_list,y0,x0,ayx,ayy,axx,axy,mode)
   
    if symm=="D4_x1" or symm=="D8_1":
        g.putcells(cell_list,-y0,-x0,-ayx,-ayy,-axx,-axy,mode)
   
    if symm=="D4_x4" or symm=="D8_4":
        g.putcells(cell_list,-y0-1,-x0-1,-ayx,-ayy,-axx,-axy,mode)

def clear_layer():
    r = g.getrect()
    if r:
        g.select(r)
        g.clear(0)
    return

x=10
main_fill=50

def main():
    g.new("RandOsc")
    g.setrule(rule)
    g.setalgo(algo)
    g.setbase(2)
    
    test_layer=g.getlayer()
    if g.numlayers()<g.maxlayers():
        results_layer=g.addlayer()
        g.setname('OscResults')
        g.setlayer(test_layer)
    else:
        resultslayer=-1
    results=0
   
    count=0
    prevcount=0
    t_start=timer()
    t_prev=t_start
    while True:
        clear_layer()
       
        g.select([0,0,x,x])
        g.randfill(main_fill)
        cell_list=g.getcells([0,0,x,x])
        # g.clear(0)
        put_symm(cell_list)
       
        g.setstep(stab_step)
        g.step()
       
        if osc_test():
            osc = g.getcells(g.getrect())
            results+=1
            if results_layer>=0:
                g.setlayer(results_layer)
                g.putcells(osc, result_spacing*results, 0)
                g.setname('OscResults (%d)' % results)
                g.fit()
                g.update()
                g.setlayer(test_layer)
            else:
                return True
       
        count+=1
        if count%1000==0:
            t_end=timer()
            g.show("%d results found after %d soups tested (%d/sec current, %d/sec overall)" % (results, count, (count-prevcount)/(t_end-t_prev), (count)/(t_end-t_start)))
            g.select([])
            g.update()
            g.new("")
            g.setbase(2)
            t_prev=t_end
            prevcount=count

main()
I also couldn't resist making a few performance improvements. You should see about a six-fold performance improvement for CGoL. I haven't performance tested the script with any other rules though, but I expect that they'll be similar. I also modified the base step and the excluded periods list for tlife. I haven't added any duplicate checking to this script, so it will output results similarly to nbsearch1. Abort the script with 'Esc' to view the results.

Re: Script request thread

Posted: December 1st, 2017, 11:26 am
by gameoflifemaniac
This script:

Code: Select all

local g = golly()
g.reset()
g.randfill(50)
g.flip(0)
g.putcells(g.getselrect(), 8, 0, 0, 0, 0, 0, "or")
g.run(10000)
g.setmag(1)
was supposed to run symmetric soups, but it isn't working as I wanted to. Can someone help me?

Re: Script request thread

Posted: December 1st, 2017, 11:48 am
by wildmyron
gameoflifemaniac wrote:This script:

Code: Select all

local g = golly()
g.reset()
g.randfill(50)
g.flip(0)
g.putcells(g.getselrect(), 8, 0, 0, 0, 0, 0, "or")
g.run(10000)
g.setmag(1)
was supposed to run symmetric soups, but it isn't working as I wanted to. Can someone help me?
There are three problems:
* g.getselrect() gives you a rect list, not a cell list. You want g.getcells(g.getselrect())
* If you flip the selection, then copy the current selection and paste it - you will have two copies of the same pattern, neither of them flipped.
* What does the magic number 8 refer to? It doesn't relate to the current selection, whatever that is. Better to make the selection in the script so you control everything, or determine where to paste based on the current selection, not hardcoded.

Re: Script request thread

Posted: December 1st, 2017, 12:05 pm
by dvgrn
gameoflifemaniac wrote:This script...was supposed to run symmetric soups, but it isn't working as I wanted to. Can someone help me?
One problem is your "8,0,0,0,0,0" affine transformation -- too many zeroes. Also there's an implicit assumption that the selection is always in the same place. And also I misquoted some code in my last post -- said listofcells = g.getselrect() when I should have said listofcells = g.getcells(g.getselrect()).

If the selection really is in a standard location every time -- upper left-hand corner always at (0,0), let's say -- then you could get away with something like

Code: Select all

local g = golly()
g.randfill(50)
g.putcells(g.getcells(g.getselrect()), 0, 0, -1, 0, 0, 1, "or")
g.run(10000)
g.setmag(1)
Or

g.putcells(g.getcells(g.getselrect()), -1, 0, -1, 0, 0, 1, "or")

if you want even symmetry instead of odd symmetry.

Otherwise, as wildmyron says, you're better off doing something like a g.select(0,0,x,y), to avoid having to do slightly more complicated math to figure out what the correct affine transformation is for that particular selection. And probably a g.new() before that, so you're sure there isn't any leftover non-symmetric junk in the universe.

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

Those six affine transformation values are very simple math, but not so easy to explain in words. From Golly help:
transform(cell_array, x0, y0, axx=1, axy=0, ayx=0, ayy=1)
Apply an affine transformation to the given cell array and return the resulting cell array. For each x,y cell in the input array the corresponding xn,yn cell in the output array is calculated as xn = x0 + x*axx + y*axy, yn = y0 + x*ayx + y*ayy.
Short summary: the first two numbers are (delta x, delta y). The default (identity) transformation would be (1, 0, 0, 1) for the other four parameters, which means:

To get the new X value, multiply the old X value by 1 and add the old Y value multiplied by 0.
To get the new Y value, multiply the old X value by 0 and add the old Y value multiplied by 1.

So if you're saying "don't move or rotate or reflect anything", that's "0, 0, 1, 0, 0, 1" -- not all zeroes.

If you experiment with affine transformations enough, they'll start to make a whole lot of sense -- and they tie in with sines and cosines and IFS fractals and all kinds of other fun stuff. So taking the time to develop a low-level understanding of them would definitely not be a wasted investment.

Re: Script request thread

Posted: December 3rd, 2017, 8:51 am
by gameoflifemaniac
I wanted to do a script that returns all the digits representing all transitions in a rule in the status bar or anywhere else.
I don't know how to do this. At least I tried:

Code: Select all

local g = golly()
local gp = require "gplus"
g.new("Rule string")
g.show(g.getrule())
g.setcursor("Draw")
Something like this was in the universal megafier script, but don't fully understand how this works.

Re: Script request thread

Posted: December 3rd, 2017, 10:32 am
by dvgrn
gameoflifemaniac wrote:I wanted to do a script that returns all the digits representing all transitions in a rule in the status bar or anywhere else.
...
Something like this was in the universal megafier script, but don't fully understand how this works.
Specifics, please. I'm guessing you want 512 binary digits, representing transitions for all possible Moore neighborhoods. But that's too much information to fit in the status bar. Maybe you want a similar report just for Life-like rules, or just for isotropic rules?

The universal megafier script collects the 512 bits of information described above, so if that's what you're looking for it should be possible to re-use the same code. That function works by drawing all possible neighborhoods for both possible center-cell states, running the whole test pattern for one tick, and seeing what happens.

Unfortunately this doesn't work correctly in cases where Golly is doing its anti-strobe simulation trick for rules with B0. It has been on my to-do list to fix that, but it's going to be slightly annoying so I've been avoiding it. One way would be to redraw all the neighborhoods at T=1, run for another tick, and collect 512 more bits of information. If the two sets of 512 bits are different, then compare them to deduce the actual rule that Golly is simulating.

I shouldn't say "slightly annoying" -- I should say "a nice challenge that I'll leave as an exercise for the reader."

Re: Script request thread

Posted: December 15th, 2017, 3:48 pm
by muzik
I've had an idea for a (probably super inefficient) soup-searching script for a while now: how about it runs through all possible fillings of a nxn square using a binary counter and counting the bottom right corner as the last digit?

Oh, and it would probably upload results to catagolue while it's at it as well.

Re: Script request thread

Posted: December 15th, 2017, 4:12 pm
by Apple Bottom
muzik wrote:I've had an idea for a (probably super inefficient) soup-searching script for a while now: how about it runs through all possible fillings of a nxn square using a binary counter and counting the bottom right corner as the last digit?

Oh, and it would probably upload results to catagolue while it's at it as well.
This would be doable for small n anyway. (I'll leave it up to you to determine the number of equivalent soups of size n by n though.)

The script already exists, too; it's called apgsearch. All you really need to do is modify hashsoup() and tweak the main loop's logic a bit.

Re: Script request thread

Posted: December 15th, 2017, 4:36 pm
by dvgrn
Apple Bottom wrote:The script already exists, too; it's called apgsearch. All you really need to do is modify hashsoup() and tweak the main loop's logic a bit.
Even that modification has already been done.

Re: Script request thread

Posted: December 20th, 2017, 5:34 pm
by AforAmpere
This is a complicated one, but is it possible to modify qfind, gfind or zfind into searching knightships, with speeds of (3,2)c/10 for example? Knight2 and knightt kind of do, but they don't work for higher periods. On another note, where can I find WLS? I can't seem to find the link I had seen before.

Re: Script request thread

Posted: December 21st, 2017, 4:42 am
by Apple Bottom
AforAmpere wrote:On another note, where can I find WLS? I can't seem to find the link I had seen before.
It's on the wiki!

Re: Script request thread

Posted: December 27th, 2017, 4:07 pm
by AforAmpere
I know I keep requesting things but, can this glider script from David Eppstein be modified to work on non-totalistic rules? I am not very good with c scripts, so I am not sure exactly how I could modify it. I will use this for adding in NT ships to a downloadable file, so known ships can be searched.

Re: Script request thread

Posted: December 28th, 2017, 4:08 am
by Macbi
Does anyone have some python code for parsing rulestrings? Ideally I'd like it to at least work for anything that Golly or apgsearch accepts. Doesn't really matter what form the output takes since that will be easy enough to change.

Re: Script request thread

Posted: December 28th, 2017, 9:41 am
by calcyman
Macbi wrote:Does anyone have some pyhton code for parsing rulestrings? Ideally I'd like it to at least work for anything that Golly or apgsearch accepts. Doesn't really matter what form the output takes since that will be easy enough to change.
The rule-parsing code in apgluxe is entirely written in Python. Look at def main in the following file:

https://gitlab.com/apgoucher/lifelib/bl ... ule2asm.py

For non-totalistic isotropic rules, it delegates to ntcanon.py. The relevant initial segment of the script is:

Code: Select all

#!/usr/bin/python

from sys import argv

rulestring = argv[1]
isotrans = {}
centre = 0

for c in rulestring.lower().replace('v', 'r'):
    if c in '012345678':
        lastloc = int(c)
        isotrans[(centre, lastloc)] = "+";
    elif (c == 'b'):
        centre = 0
    elif (c == 's'):
        centre = 1
    elif (c == '/'):
        centre = 1 - centre
    elif c in 'ceaiknjqrytwz-':
        isotrans[(centre, lastloc)] += c

lord = "";
lord += "_ceaccaieaeaknja_ceaccaieaeaknjaekejanaairerririekejanaairerriri";
lord += "ccknncqnaijaqnwaccknncqnaijaqnwakykkqyqjrtjnzrqakykkqyqjrtjnzrqa";
lord += "ekirkyrtejerkkjnekirkyrtejerkkjnekejjkrnejecjyccekejjkrnejecjycc";
lord += "anriqyzraariqjqaanriqyzraariqjqajkjywkqkrnccqkncjkjywkqkrnccqknc";
lord += "cnkqccnnkqkqyykjcnkqccnnkqkqyykjaqjwinaarzjqtrnaaqjwinaarzjqtrna";
lord += "ccyyccyennkjyekeccyyccyennkjyekenykknejeirykrikenykknejeirykrike";
lord += "aqrznyirjwjqkkykaqrznyirjwjqkkykaqrqajiarqcnnkccaqrqajiarqcnnkcc";
lord += "intrneriaanajekeintrneriaanajekeajnkaeaeiaccaec_ajnkaeaeiaccaec_";
popcounts = [0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4]
lord2 = []

for i in xrange(512):

    centre = (i >> 4) & 1
    ncount = popcounts[i & 15] + popcounts[i >> 5]
    if (centre, ncount) in isotrans:
        fragment = isotrans[(centre, ncount)]
        if (len(fragment) == 1):
            lord2.append(1)
        else:
            l = 1 if (fragment[1] == '-') else 0
            for c in fragment:
                if (c == lord[i]):
                    l = 1 - l
            lord2.append(l)
    else:
        lord2.append(0)

rule_letters = {}
rule_letters[1] = "ce" ;
rule_letters[2] = "ceaikn" ;
rule_letters[3] = "ceaiknjqry" ;
rule_letters[4] = "ceaiknjqrytwz" ;
rule_letters[5] = "ceaiknjqry" ;
rule_letters[6] = "ceaikn" ;
rule_letters[7] = "ce" ;

canonicals = [['' for i in xrange(9)] for j in xrange(2)]
canstring = ''

for i in xrange(512):
    centre = (i >> 4) & 1
    ncount = popcounts[i & 15] + popcounts[i >> 5]
    if (lord2[i] == 1):
        canonicals[centre][ncount] += lord[i]

for (centre, z) in enumerate('bs'):
    canstring += z
    for ncount in xrange(9):
        goodies = set(canonicals[centre][ncount])
        if (len(goodies) == 0):
            continue
        canstring += str(ncount)
        if ncount not in rule_letters:
            continue
        a = ''.join(sorted([c for c in rule_letters[ncount] if c in goodies]))
        b = '-' + (''.join(sorted([c for c in rule_letters[ncount] if c not in goodies])))
        if (len(b) == 1):
            continue
        elif (len(b) < len(a)):
            canstring += b
        else:
            canstring += a

if (rulestring != canstring):
    print('\033[31;1mError:\033[0m %s is a non-canonical version of %s' % (rulestring, canstring))
    print('Please re-run the code with the canonical rulestring:')
    print('./recompile.sh --rule \033[36;1m%s\033[0m' % canstring)
    exit(1)

print lord2
It produces a 512-bit list of binary digits (lord2), indexed by a 9-bit integer whose bits correspond to the neighbourhood read in lexicographical order. It accepts outer-totalistic and non-totalistic isotropic rules in basically any format (such as Golly's B3/S23, Life32's 23/3, and apgsearch's b3s23).

EDIT: Technically you only need the top half of the code snippet I posted, because the second half converts lord2 back into a canonical rulestring to see whether it matches the original rulestring.