Golly scripts

For scripts to aid with computation or simulation in cellular automata.
hotdogPi
Posts: 348
Joined: August 12th, 2020, 8:22 pm

Re: Golly scripts

Post by hotdogPi » May 13th, 2021, 7:52 pm

This is the script I've been using to find all those high-period oscillators.

Inputs:
mode: C2, C4, D4, or X4, depending on the symmetry. X4 is D4 diagonal.
input_pattern: the pattern to be inputted. If C2, you'll need to run the program twice to get everything, with the second one rotated 90°.
a (C4 only): 1 is even symmetry, 0 is odd symmetry.
start_x, end_x, start_y, end_y: The bounding boxes of the initial configurations. For C4, start_y should never be negative, and start_x and end_x are further limited based on what the current y is.
z: You may want to change this from 4 to 1 or 2 if the pattern has symmetry to avoid unnecessary duplication. (Some symmetry does this; other symmetry changes start/end x/y instead.)
Loop 1 (currently goes 250): Maximum number of generations before adding the sparks.
Loop 2 (currently goes 500): Maximum number of generations after adding the sparks.

Once a solution is found, edit these three things:
1. min_x should be what you just found.
2. The commented out line (x = -11 and y = -7 right now) should be uncommented and changed to what you just found; if there are a whole bunch of the same one, you can add 1 to y. (The advantage of not adding 1 is that sometimes multiple spark configurations work.)
3. The line near the end with -11 and -7: change to what was found so that it will only notify you instead of ending the program when it's found again.

Update #1 5/25/21:
g.copy() turns out to be a very slow function. It has been taken out, and things depending on min(edge) no longer have a ±30 attached because of the differences in g.getcells() and g.clip().
Diagonal symmetry added.
Escaping gliders are now removed from the left side, which means that sparks are no longer stuck on escaping gliders. (This isn't completely foolproof and could cause asymmetry issues if an XWSS were to hit the glider, but this is extremely rare.)

Code: Select all

import golly as g
import time

g.select([0,0,1,1])
#g.autoupdate(1)
test1 = False
mode = 'C2' #C2, C4, D4, X4
g.new("example")
input_pattern = g.parse('2bo$2ob2o$o2bo$b2o!')
#C2 b3o$bobo$o2bo$2o! to x=-5 (-15 to 15 in both x and y
g.putcells(input_pattern, 0, 0)
initial_box = g.getrect()
width = g.getrect()[2]
height = g.getrect()[3]
if mode == 'C2':
    r_up = input_pattern
    g.select(initial_box)
    g.rotate(1)
    g.rotate(1)
    g.cut()
    g.paste(0,0,"or")
    r_down = g.getcells(g.getrect())
elif mode in ('C4','X4'):
    a = 0 #1 if even symmetry, 0 if odd; C4 only
    r_n = input_pattern
    initial_box = g.getrect()
    g.select(initial_box)
    if mode == 'X4':
        g.flip(1)
    g.rotate(mode == 'C4')
    g.select(g.getrect())
    g.cut()
    g.paste(0,0,"or")
    r_e = g.getcells(g.getrect())
    g.select(g.getrect())
    if mode == 'X4':
        g.flip(1)
    g.rotate(1)
    g.cut()
    g.paste(0,0,"or")
    r_s = g.getcells(g.getrect())
    g.select(g.getrect())
    if mode == 'X4':
        g.flip(1)
    g.rotate(mode == 'C4')
    g.cut()
    g.paste(0,0,"or")
    r_w = g.getcells(g.getrect())
elif mode == 'D4':
    r_se = input_pattern
    g.select(initial_box)
    g.flip(1)
    g.select(g.getrect())
    g.cut()
    g.paste(0,0,"or")
    r_ne = g.getcells(g.getrect())
    g.select(g.getrect())
    g.flip(0)
    g.cut()
    g.paste(0,0,"or")
    r_nw = g.getcells(g.getrect())
    g.select(g.getrect())
    g.flip(1)
    g.cut()
    g.paste(0,0,"or")
    r_sw = g.getcells(g.getrect())
else:
    g.exit('Invalid symmetry input.')
g.new("example")
single_cell = g.parse('o!')
if mode == 'C2':
    start_x, end_x, start_y, end_y = -20, 20, -20, 20
elif mode == 'C4':
    start_x, end_x, start_y, end_y = -18, 18, 0, 13
elif mode == 'D4':
    start_x, end_x, start_y, end_y = width+1, width+20, height+1, height+20
elif mode == 'X4':
    start_x, end_x, start_y, end_y = -20, 20, -20, 15
for x in range(start_x, end_x+1):
    for y in range(start_y, end_y+1):
        for z in range(1 if mode in ('C2','X4') else 4):
            #if x == -11 and y < -7:
            #    continue
            if mode == 'C4' and not -y-width <= x < y:
                continue
            if mode == 'C4':
                width, height = height, width
                r_n, r_e, r_s, r_w = r_e, r_s, r_w, r_n
            if mode == 'D4':
                if z % 2 == 0:
                    r_se, r_ne, r_nw, r_sw = r_ne, r_se, r_sw, r_nw
                else:
                    r_se, r_ne, r_nw, r_sw = r_sw, r_nw, r_ne, r_se
            recent_pops = list(range(100,109))
            recent_min_x = list(range(100,108))
            current_gen = None
            g.new("example")
            if mode == 'C2':
                g.putcells(r_down, 0, 0)
                num1 = int(g.getpop())
                g.putcells(r_up, x, y)
                if int(g.getpop()) != 2 * num1:
                    continue
            elif mode == 'C4':
                g.putcells(r_n, x, y)
                num1 = int(g.getpop())
                g.putcells(r_e, y, -x-width+1-a)
                g.putcells(r_s, -x-width+1-a, -y-height+1-a)
                g.putcells(r_w, -y-height+1-a, x)
                #time.sleep(1)
                if int(g.getpop()) != 4 * num1:
                    continue
            elif mode == 'D4':
                g.putcells(r_se, x, y)
                num1 = int(g.getpop())
                g.putcells(r_ne, x, 0)
                g.putcells(r_nw, 0, 0)
                g.putcells(r_sw, 0, y)
                if int(g.getpop()) != 4 * num1:
                    continue
            elif mode == 'X4':
                g.putcells(r_n, x, y)
                num1 = int(g.getpop())
                g.putcells(r_w, 0, y-x-width+height)
                g.putcells(r_e, x+y+width-1, -width+1)
                g.putcells(r_s, y+height-1, -x-width+1)
                if int(g.getpop()) != 4 * num1:
                    continue
            g.show(str((x,y)))
            g.update()
            initial_box = g.getrect()
            initial_box[0] -= 1
            initial_box[1] -= 1
            initial_box[2] += 2
            initial_box[3] += 2
            hash1 = g.hash(initial_box)
            g.select(initial_box)
            g.flip(0)
            hash2 = g.hash(initial_box)
            g.flip(0)
            #if initial_box[2] <= 8:
            #    initial_box = [-50,-50,100,100]
            generation_snapshots = [''] * 10
            test1 = False
            for generation in range(250):
                #g.update()
                #g.show('Generation ' + str(generation))
                if generation == 0:
                    pass
                else:
                    g.new("example")
                    g.putcells(current_gen)
                if generation > 0:
                    g.run(1)
                if g.getcells(g.getrect()) == current_gen:
                    break
                recent_pops.append(int(g.getpop()))
                recent_pops.pop(0)
                if recent_pops[-1] < (8 if mode == 'C2' else 16): #no growth
                    break
                if max(recent_pops) == min(recent_pops):
                    break
                #if g.getcell(0,0) == 0: #block broken
                #    break
                min_x = g.getrect()[0]
                #if min_x == 0:
                #    current_gen = g.getcells(g.getrect())[:]
                #    continue
                #g.select([min_x,-30+y,1,80])
                #g.copy()
                #edge = g.getclip()[3::2]
                edge = g.getcells([min_x,-40+y,1,80])[1::2]
                current_gen = g.getcells(g.getrect())[:]
                if not edge:
                    continue
                #if max(edge) - len(edge) + 1 == min(edge):
                #    continue
                while max(edge) - len(edge) + 1 != min(edge):
                    edge.remove(max(edge))
                recent_min_x.append(min_x)
                recent_min_x.pop(0)
                if g.getcells([min_x+3,min(edge)-20,3,40]):
                    recent_min_x[-1] = 123
                if recent_min_x == [recent_min_x[0]]*4 + [recent_min_x[4]]*4 \
                   and recent_min_x[4] == recent_min_x[0] - 1:
                    for i in range(min_x, min_x+3):
                        for j in range(min(edge),min(edge)+3):
                            g.setcell(i,j,0)
                    g.update()
                    test1 = True
                    current_gen = g.getcells(g.getrect())[:]
                    continue
                #if not test1:
                #    continue
                if len(edge) == 1:
                    sparks = [(-2,-1),(-1,0),(-1,1),(0,1),(1,2)]
                if len(edge) == 2:
                    sparks = [(-1,),(0,),(2,),(-2,-1),(-1,0),(-1,2),(1,2),(2,3)]
                if len(edge) == 3:
                    sparks = [(-1,),(0,),(1,),(2,),(3,),(-2,-1),(-1,0),(2,3),(3,4)]
                if len(edge) >= 4:
                    sparks = [(-1,),(0,),(1,),(2,),(3,),(4,),(-2,-1),(-1,0),(0,1),(1,2),(2,3),(3,4),(4,5)]
                for spark in sparks:
                    if g.empty():
                        break
                    num1 = g.getrect()[1]+g.getrect()[3]
                    g.new("example")
                    g.putcells(current_gen)
                    for spark1 in spark:
                        if mode == 'C2':
                            g.putcells(single_cell,min_x-2,spark1+min(edge))
                            g.putcells(single_cell,-min_x+x+1+width,-spark1-min(edge)+y-1+height)
                        elif mode == 'C4':
                            g.putcells(single_cell,min_x-2,spark1+min(edge))
                            g.putcells(single_cell,-min_x+2-a,-spark1-min(edge)-a)
                            g.putcells(single_cell,-spark1-min(edge)-a,min_x-2)
                            g.putcells(single_cell,spark1+min(edge),-min_x+2-a)
                        elif mode == 'D4':
                            g.putcells(single_cell,min_x-2,spark1+min(edge))
                            g.putcells(single_cell,-min_x+x+width+1,-spark1+height+y-min(edge)-1)
                            g.putcells(single_cell,min_x-2,-spark1+height+y-min(edge)-1)
                            g.putcells(single_cell,-min_x+x+width+1,spark1+min(edge))
                        elif mode == 'X4':
                            center = (x+y+height-1+width, y-x-width+height+1) #actually twice center
                            offset_x = 2*(min_x-2)-center[0]
                            offset_y = 2*(spark1+min(edge))-center[1]
                            g.putcells(single_cell,(center[0]-offset_x)//2-1, (center[1]-offset_y)//2-1)
                            g.putcells(single_cell,(center[0]-offset_y)//2-1, (center[1]-offset_x)//2-1)
                            g.putcells(single_cell,(center[0]+offset_x)//2, (center[1]+offset_y)//2)
                            g.putcells(single_cell,(center[0]+offset_y)//2, (center[1]+offset_x)//2)
                        x1, y1 = min_x-5,spark1+min(edge)
                    #time.sleep(.1)
                    #g.update()
                    hash_list = []
                    recent_pops1 = list(range(100,139))
                    for generation1 in range(500):
                        g.run(1)
                        if int(g.getpop()) == 0:
                            break
                        if generation1 == 8:
                            if g.hash(g.getrect()) in generation_snapshots:
                                break
                            generation_snapshots.pop(0)
                            generation_snapshots.append(g.hash(g.getrect()))
                        recent_pops1.append(int(g.getpop()))
                        recent_pops1.pop(0)
                        if recent_pops1[-1] < (8 if mode == 'C2' else 16): #no growth
                            break
                        if recent_pops1[-1] > 500:
                            break
                        if max(recent_pops1) == min(recent_pops1):
                            break
                        if generation1 % 10 == 0:
                            hash_list.append(g.hash(g.getrect()))
                            if hash_list[-1] in hash_list[:-1]:
                                break
                        #if g.getcell(0,0) == 0: #block broken
                        #    break
                        if g.getcell(x1, y1) == 1: #hits sparker
                            break
                        if g.hash(initial_box) in (hash1, hash2):
                            if (x, y) == (-11,-7):
                                g.warn('Already found: %s, %s, %s' % (x, y, generation))
                            else:
                                g.warn('Found!: %s, %s, %s' % (x, y, generation))
                                g.update()
                                g.exit('Found!')
                        

hotdogPi
Posts: 348
Joined: August 12th, 2020, 8:22 pm

Re: Golly scripts

Post by hotdogPi » July 6th, 2021, 8:22 pm

I know I had the last post, but people won't see it if I just edit the most recent post.

First, I've updated the program to allow placing catalysts that get ignored when sparking (but you have to specify the correct coordinates) and also added the "rotate" variable that checks if it's rotated 90° (which would be a half-cycle).

How I've defined "common objects": top 26 in the list minus the traffic light + block sequences, Jason's p22, and rank #23 (pi + loaf). Also add honey farm in its D8 form, traffic light, interchange (zero results for some reason), angel, the six-cell edgeshooting traffic light predecessor, phi spark, line of six spark (can't remember if this returned zero results or not), fleet, bakery, and both common predecessors of two loaves that never reach 20 cells and aren't included in the list. Dove may not be complete; I initially put in an actual dove, but half the time, it forms in a way that doesn't include that phase. (Note that the E-heptomino is not on the list.) Similarly, I put the U-turner in the phase C28 found it in, but it might be useful to start it two generations later because of the sparks in its second listing in the list. I start the R-pentomino in generation 5, so something that relies on it being in an earlier generation might not have been found.

Without catalysts: Without "rotate", the top 35 or so (near the end of the list, I sought ones that had symmetry or faded quickly), including the ones explicitly excluded above, to 250-500 generations before the spark and 500 after the spark for the most common objects and 100 and 200 once you get to the blonk-tie region and below. Note that you're safe setting the number after the spark to 2000; the second loop takes much less time than the first loop, and I'm not exactly sure why. (It recognizes when it's done, although if gliders are the only movement, it will stop after 40 generations.) With "rotate", the exact list mentioned above. I've also covered more area in the more common regions; about 25 cells from the origin compared to 15 in the less common ones. I included obo sparks for much of my time, but I removed it from the program since they're hard to complete.

With catalysts: I've spent most of my time perturbing honey farms (including the phases before it reaches D8), traffic lights (I don't know of many fancy catalysts), R-pentominoes, and pi-heptominoes, and a small amount of time on lumps of muck, century, wing, and the B-heptomino. Past that, I've done almost nothing and found almost nothing. (I've noticed that you're much less likely to find something with a catalyst compared to open space, but 2 catalysts vs. 1 catalyst doesn't make much difference.) In general, anything that requires a single fishhook or block for the object mentioned above has already been tried; anything else may or may not have been. I've done significant work with the honey farm + fishhook → glider reaction, but even then, still not everything.

What I have not done any of at all: rotate True + catalysts (although I have tried flippers + catalysts), anything involving the E-heptomino (there's a different list that puts it in the top 20), sparkers that spark only one cell away like the oscillator below (not mine), obbo sparks, and rows of three or more cells as sparks.

This program runs in the rule Golly is currently in. If you delete automatic glider detection (and even if you don't, it should mostly be fine), you should be able to use it in other rules, although I haven't tried.

Code: Select all

x = 60, y = 60, rule = B3/S23
32b2o$28b2o2bo$27bo2bobo$23b2obo2bo2b2o$23bob2obobobo$28b3o3bo$24b4obo
b3obo$23bo3bo3bo3bo$24b3o5b3o$26bob3obo$27b5o$28b3o3$29b3o$28bo2b2o$
28b2o3bo2b2o$32bob4o$31bo2bo$24bo6bo2bo$23bob2o4bobo$23bo2b2o4bo$16b2o
5b2o$16b2o6bobo10b3o12bo2b2o$6b2o9bo7bo10b2o2bo10bobo2bo$5bo2bo8b3o15b
o3bo11bobobo$o2bo2bobo7bo3bo15bob2o10b2obob2o$5obob2o5bobo3bo16bo10bo
2b2o3bo$6b2o2bo3b2o2b3o22b2o3b3o3b2o2bo$2bob2o3b3o2bo28bobo2b3o2b2obob
o$bobob2o2b3o2bobo28bo2b3o3b2obo$bo2b2o3b3o3b2o22b3o2b2o3bo2b2o$2bo3b
2o2bo10bo16bo3bobo5b2obob5o$3b2obob2o10b2obo15bo3bo7bobo2bo2bo$4bobobo
11bo3bo15b3o8bo2bo$3bo2bobo10bo2b2o10bo7bo9b2o$3b2o2bo12b3o10bobo6b2o$
35b2o5b2o$27bo4b2o2bo$26bobo4b2obo$25bo2bo6bo$25bo2bo$22b4obo$22b2o2bo
3b2o$27b2o2bo$28b3o3$29b3o$28b5o$27bob3obo$25b3o5b3o$24bo3bo3bo3bo$24b
ob3obob4o$25bo3b3o$27bobobob2obo$26b2o2bo2bob2o$27bobo2bo$27bo2b2o$26b
2o!
The way this program is set currently:

Code: Select all

initial_box[0] -= 1 #must not touch initial pattern
            initial_box[1] += 4
            initial_box[2] += 2
            initial_box[3] -= 8
This is how I actually ran the program, but it's specific to what I did. It allows the glider to be out of the bounding box 16 generations earlier. It can also be used to exclude catalysts if you want to find flippers. If you're not doing something specific, you'll want it the way it is in the code below.

Code: Select all

if mode == 'C2':
    start_x, end_x, start_y, end_y = 1, 30, 6, 30

Code: Select all

            if x == 1 and y < 26:
                continue
It's only starting at (1,6) because I found something there and had to continue from there. (I don't remember why I have y as 6 in one spot and 26 in the other.) I started the search with x at -5, and I would have started y at -5 if not for the error caused by the catalyst-ignoring selection. Defaults for the other numbers are typical values for those symmetries, but you can make it higher or lower depending on how big a search space you want. The second of these snippets is for when you've already found a pattern and want to continue where you left off.

Code: Select all

            if mode == 'C4' and not -y-width <= x < y: #C4 has a diagonal bounding box
                continue
If there are no catalysts, keep this line. If there are catalysts, comment it out and put negative numbers in the lower x and y limit. This sentence does not apply to the similar-looking D8 line just below it.

Code: Select all

            if x < 0 and y < 0:
                continue
This is a useful line in C2 if there are catalysts on two sides. If there aren't, or you're not in C2, comment it out. In C2, I always put the catalysts on the south and east sides. Note that your clipboard will rotate it 180° when you start the program!

Code: Select all

                if not g.getcell(14,0) or not g.getcell(0,2) or not g.getcell(0,10): #block broken
                    break
You'll obviously want to change this depending on what catalysts you're using, or if none, comment it out entirely. Despite the comment, it doesn't have to be a block. This line appears twice, one in each loop.

Code: Select all

g.select([-50,14,100,y+height-17])
                    g.clear(1)
This tells me that I want to only place sparks more than 14 cells from the top and no more than 3 cells from the bottom. If you want to exclude certain rows but include the rest, you might want a g.clear(0) instead, which also allows more freedom in your y values. If you're not excluding rows at all (no catalysts or catalysts that are in a location that won't interfere with placing sparks), comment out the six lines beginning with the first "temp" line plus the three single lines mentioning "temp" below.

Code: Select all

if g.hash(initial_box2 if rotate else initial_box) in (hash1, hash2):
You might need to change the hash numbers if rotate is True.

Code: Select all

import golly as g
import time

'''Initializing'''
g.select([0,0,1,1])
#g.autoupdate(1)
test1 = False
test2 = 0
test2a = 0
mode = 'C2' #C2, C4, D4, X4, D8
rotate = False
copies = 8 if mode == 'D8' else 2 if mode == 'C2' else 4
g.new("example")
#input_pattern = g.parse('4b2o$4bobo$6bo$4bobo$4b2o5$14b2o$14b2o2$2b2o$3bo$3o$o!')
input_pattern = g.parse('14b2o$6b3o5b2o$5bo3bo$4bo5bo$4bo5bo$4bo5bo$5bo3bo2b2o$6b3o3bobo$14bo$14b2o$2o$2o!')
g.putcells(input_pattern, 0, 0)
initial_box = g.getrect()
width = g.getrect()[2]
height = g.getrect()[3]
'''Generating rotations and reflections'''
if mode == 'C2':
    r_up = input_pattern
    g.select(initial_box)
    g.rotate(1)
    g.rotate(1)
    g.cut()
    g.paste(0,0,"or")
    r_down = g.getcells(g.getrect())
elif mode in ('C4','X4','D8'):
    a = 1   #1 if even symmetry, 0 if odd; C4 and D8 only
    r_n = input_pattern
    initial_box = g.getrect()
    g.select(initial_box)
    if mode == 'X4':
        g.flip(1)
    g.rotate(mode != 'X4')
    g.select(g.getrect())
    g.cut()
    g.paste(0,0,"or")
    r_e = g.getcells(g.getrect())
    g.select(g.getrect())
    if mode == 'X4':
        g.flip(1)
    g.rotate(1)
    g.cut()
    g.paste(0,0,"or")
    r_s = g.getcells(g.getrect())
    g.select(g.getrect())
    if mode == 'X4':
        g.flip(1)
    g.rotate(mode != 'X4')
    g.cut()
    g.paste(0,0,"or")
    r_w = g.getcells(g.getrect())
    if mode == 'D8':
        g.select(g.getrect())
        g.flip(0)
        g.rotate(1)
        g.rotate(1)
        g.cut()
        g.paste(0,0,"or")
        r_nw = g.getcells(g.getrect())
        g.select(g.getrect())
        g.rotate(1)
        g.cut()
        g.paste(0,0,"or")
        r_ne = g.getcells(g.getrect())
        g.select(g.getrect())
        g.rotate(1)
        g.cut()
        g.paste(0,0,"or")
        r_se = g.getcells(g.getrect())
        g.select(g.getrect())
        g.rotate(1)
        g.cut()
        g.paste(0,0,"or")
        r_sw = g.getcells(g.getrect())
elif mode == 'D4':
    r_se = input_pattern
    g.select(initial_box)
    g.flip(1)
    g.select(g.getrect())
    g.cut()
    g.paste(0,0,"or")
    r_ne = g.getcells(g.getrect())
    g.select(g.getrect())
    g.flip(0)
    g.cut()
    g.paste(0,0,"or")
    r_nw = g.getcells(g.getrect())
    g.select(g.getrect())
    g.flip(1)
    g.cut()
    g.paste(0,0,"or")
    r_sw = g.getcells(g.getrect())
else:
    g.exit('Invalid symmetry input.')
g.new("example")
#single_cell = g.parse('o!')
'''Starting and ending bounds'''
if mode == 'C2':
    start_x, end_x, start_y, end_y = 1, 30, 6, 30
elif mode == 'C4':
    start_x, end_x, start_y, end_y = -15, 15, 0, 10
elif mode == 'D4':
    start_x, end_x, start_y, end_y = width+1, width+15, height+1, height+15
elif mode == 'X4':
    start_x, end_x, start_y, end_y = -20, 20, -20, 15
elif mode == 'D8':
    start_x, end_x, start_y, end_y = 0, 15, 0, 15
'''Main loop'''
for x in range(start_x, end_x+1):
    for y in range(start_y, end_y+1):
        for z in range(1 if mode in ('C2','X4') else 8 if mode == 'D8' else 4):
            if x == 1 and y < 26:
                continue
            if mode == 'C4' and not -y-width <= x < y: #C4 has a diagonal bounding box
                continue
            if x < 0 and y < 0:
                continue
            if mode == 'D8' and y > x: #D8 takes only an eighth
                continue
            if mode == 'C4': #rotating
                width, height = height, width
                r_n, r_e, r_s, r_w = r_e, r_s, r_w, r_n
            if mode == 'D8':
                if z % 4 == 0:
                    r_n, r_e, r_s, r_w, r_ne, r_se, r_sw, r_nw = \
                         r_ne, r_se, r_sw, r_nw, r_n, r_e, r_s, r_w
                width, height = height, width
                r_n, r_e, r_s, r_w, r_ne, r_se, r_sw, r_nw = \
                     r_w, r_n, r_e, r_s, r_se, r_sw, r_nw, r_ne
            if mode == 'D4': #flipping
                if z % 2 == 0:
                    r_se, r_ne, r_nw, r_sw = r_ne, r_se, r_sw, r_nw
                else:
                    r_se, r_ne, r_nw, r_sw = r_sw, r_nw, r_ne, r_se
            recent_pops = list(range(100,109)) #9 same population in a row: end
            recent_min_x = list(range(100,108)) #checking for escaping gliders
            current_gen = None
            g.new("example")
            '''Putting patterns in place'''
            if mode == 'C2':
                g.putcells(r_down, 0, 0)
                num1 = int(g.getpop())
                g.putcells(r_up, x, y)
            elif mode == 'C4':
                g.putcells(r_n, x, y)
                num1 = int(g.getpop())
                g.putcells(r_e, y, -x-width+1-a)
                g.putcells(r_s, -x-width+1-a, -y-height+1-a)
                g.putcells(r_w, -y-height+1-a, x)
            elif mode == 'D4':
                g.putcells(r_se, x, y)
                num1 = int(g.getpop())
                g.putcells(r_ne, x, 0)
                g.putcells(r_nw, 0, 0)
                g.putcells(r_sw, 0, y)
            elif mode == 'X4':
                g.putcells(r_n, x, y)
                num1 = int(g.getpop())
                g.putcells(r_w, 0, y-x-width+height)
                g.putcells(r_e, x+y+width-1, -width+1)
                g.putcells(r_s, y+height-1, -x-width+1)
            elif mode == 'D8':
                g.putcells(r_n, x, y)
                num1 = int(g.getpop())
                g.putcells(r_ne, -x-width+1-a, y)
                g.putcells(r_e, y, -x-width+1-a)
                g.putcells(r_se, y, x)
                g.putcells(r_s, -x-width+1-a, -y-height+1-a)
                g.putcells(r_sw, x, -y-height+1-a)
                g.putcells(r_w, -y-height+1-a, x)
                g.putcells(r_nw, -y-height+1-a, -x-width+1-a)
            if int(g.getpop()) != copies * num1:
                continue
            if rotate and (g.getrect()[2] + g.getrect()[3]) % 2 == 1:
                continue
            g.show(str((x,y)))
            g.update()
            initial_box = g.getrect()
            initial_box[0] -= 1 #must not touch initial pattern
            initial_box[1] -= 1
            initial_box[2] += 2
            initial_box[3] += 2
            hash1 = g.hash(initial_box)
            g.select(initial_box)
            if rotate:
                g.rotate(1)
                initial_box2 = g.getrect()
                initial_box2[0] -= 1 #must not touch initial pattern
                initial_box2[1] -= 1
                initial_box2[2] += 2
                initial_box2[3] += 2
            else:
                g.flip(0)
            hash2 = g.hash(initial_box2 if rotate else initial_box) #for flippers
            if rotate:
                if mode == 'C2':
                    g.flip(0)
                    hash3 = g.hash(initial_box2)
                    g.flip(0)
                g.rotate(0)
            else:
                g.flip(0)
            generation_snapshots = [''] * 200 #prevents same sequence from repeating
            test1 = False
            for generation in range(500):
                '''Outer loop'''
                #g.show('Generation ' + str(generation))
                if generation == 0:
                    #g.run(15)
                    pass
                else:
                    g.new("example")
                    g.putcells(current_gen)
                if generation > 0:
                    g.run(1)
                if g.getcells(g.getrect()) == current_gen:
                    break
                recent_pops.append(int(g.getpop()))
                recent_pops.pop(0)
                if recent_pops[-1] < 4 * copies: #no growth
                    break
                if recent_pops[-1] > 125 * copies:
                    break
                if max(recent_pops) == min(recent_pops): #9 generations with same population
                    break
                if not g.getcell(14,0) or not g.getcell(0,2) or not g.getcell(0,10): #block broken
                    break
                for w in range(2):
                    if w == 1:
                        g.new("example")
                        g.putcells(current_gen)
                    temp = g.getcells(g.getrect())
                    g.select([-50,14,100,y+height-17])
                    g.clear(1)
                    if g.empty():
                        g.putcells(temp,0,0)
                        current_gen = g.getcells(g.getrect())[:]
                        continue
                    min_x = g.getrect()[0]
                    #if min_x == x or min_x == 0: #used when there's an eater or still life
                    #    current_gen = g.getcells(g.getrect())[:]
                    #    continue
                    edge = g.getcells([min_x,-40+y,1,80])[1::2]
                    if not edge:
                        g.putcells(temp,0,0)
                        current_gen = g.getcells(g.getrect())[:]
                        continue
                    if w == 1 and max(edge) - len(edge) + 1 == min(edge):
                        g.putcells(temp,0,0)
                        current_gen = g.getcells(g.getrect())[:]
                        continue
                    while max(edge) - len(edge) + 1 != min(edge):
                        if w == 1:
                            edge.remove(max(edge))
                        else:
                            edge.remove(min(edge))
                    g.putcells(temp,0,0)
                    current_gen = g.getcells(g.getrect())[:]
                    #g.update()
                    #time.sleep(.5)
                    if w == 0:
                        recent_min_x.append(min_x)
                        recent_min_x.pop(0)
                        '''Checking for gliders'''
                        if g.getcells([min_x+3,min(edge)-8,3,16]): #not by itself
                            recent_min_x[-1] = 123
                        if recent_min_x == [recent_min_x[0]]*4 + [recent_min_x[4]]*4 \
                           and recent_min_x[4] == recent_min_x[0] - 1:
                            for i in range(min_x, min_x+3):
                                for j in range(min(edge),min(edge)+3):
                                    g.setcell(i,j,0) #delete glider
                            test1 = True
                            current_gen = g.getcells(g.getrect())[:]
                            continue
                        #if not test1:
                        #    continue
                    '''Determine sparks'''
                    if len(edge) == 1:
                        sparks = [(-2,-1),(-1,0),(0,1),(1,2)]
                    if len(edge) == 2:
                        sparks = [(-1,),(0,),(2,),(-2,-1),(-1,0),(1,2),(2,3)]
                    if len(edge) == 3:
                        sparks = [(-1,),(0,),(1,),(2,),(3,),(-2,-1),(-1,0),(2,3),(3,4)]
                    if len(edge) >= 4:
                        sparks = [(-1,),(0,),(1,),(2,),(3,),(4,),(-2,-1),(-1,0),(0,1),(1,2),(2,3),(3,4),(4,5)]
                    #sparks = [(-20,)]
                    for spark in sparks:
                        if g.empty():
                            break
                        '''Add sparks'''
                        num1 = g.getrect()[1]+g.getrect()[3]
                        g.new("example")
                        g.putcells(current_gen)
                        for spark1 in spark:
                            if mode == 'C2':
                                g.setcell(min_x-2,spark1+min(edge),1)
                                g.setcell(-min_x+x+1+width,-spark1-min(edge)+y-1+height,1)
                            elif mode in ('C4','D8'):
                                g.setcell(min_x-2,spark1+min(edge),1)
                                g.setcell(-min_x+2-a,-spark1-min(edge)-a,1)
                                g.setcell(-spark1-min(edge)-a,min_x-2,1)
                                g.setcell(spark1+min(edge),-min_x+2-a,1)
                            elif mode == 'D4':
                                g.setcell(min_x-2,spark1+min(edge),1)
                                g.setcell(-min_x+x+width+1,-spark1+height+y-min(edge)-1,1)
                                g.setcell(min_x-2,-spark1+height+y-min(edge)-1,1)
                                g.setcell(-min_x+x+width+1,spark1+min(edge),1)
                            elif mode == 'X4':
                                center = (x+y+height-1+width, y-x-width+height+1) #actually twice center
                                offset_x = 2*(min_x-2)-center[0]
                                offset_y = 2*(spark1+min(edge))-center[1]
                                g.setcell((center[0]-offset_x)//2-1, (center[1]-offset_y)//2-1, 1)
                                g.setcell((center[0]-offset_y)//2-1, (center[1]-offset_x)//2-1, 1)
                                g.setcell((center[0]+offset_x)//2, (center[1]+offset_y)//2, 1)
                                g.setcell((center[0]+offset_y)//2, (center[1]+offset_x)//2, 1)
                            if mode == 'D8':
                                g.setcell(min_x-2,-spark1-min(edge)-a,1)
                                g.setcell(-min_x+2-a,spark1+min(edge),1)
                                g.setcell(spark1+min(edge),min_x-2,1)
                                g.setcell(-spark1-min(edge)-a,-min_x+2-a,1)
                            x1, y1 = min_x-5,spark1+min(edge)
                        #g.update()
                        #time.sleep(.5)
                        hash_list = []
                        test2a += 1
                        recent_pops1 = list(range(100,139)) #40 generations same population: end
                        for generation1 in range(2000):
                            '''Inner loop'''
                            g.run(1)
                            if not int(g.getpop()): #g.getrect() crashes if empty
                                break
                            if 5 <= generation1 <= 8: #prevents repeating evolution
                                if g.hash(g.getrect()) in generation_snapshots:
                                    generation_snapshots.pop(0)
                                    generation_snapshots.append(g.hash(g.getrect()))
                                    if int(g.getpop()) > 6:
                                        test2 += 1
                                    #g.show(str(test2/test2a))
                                    break
                                generation_snapshots.pop(0)
                                generation_snapshots.append(g.hash(g.getrect()))
                            recent_pops1.append(int(g.getpop()))
                            recent_pops1.pop(0)
                            #if recent_pops1[-1] < 4 * copies: #no growth
                            #    break
                            if recent_pops1[-1] > 125 * copies: #too complicated, very unlikely
                                break
                            if max(recent_pops1) == min(recent_pops1):
                                break
                            if generation1 % 10 == 0: #checks for same pattern
                                hash_list.append(g.hash(g.getrect()))
                                if hash_list[-1] in hash_list[:-1]:
                                    break
                            if not g.getcell(14,0) or not g.getcell(0,2) or not g.getcell(0,10): #block broken
                                break
                            if g.getcell(x1, y1): #hits sparker
                                break
                            if g.hash(initial_box2 if rotate else initial_box) in (hash1, hash2):
                            #if g.hash(initial_box) in (hash1, hash2):
                                if (x, y) == (1,26):
                                    g.warn('Already found: %s, %s, %s' % (x, y, generation))
                                    generation_snapshots = [''] * 200
                                else:
                                    g.warn('Found!: %s, %s, %s' % (x, y, generation))
                                    g.update()
                                    g.exit('Found!')

hotdogPi
Posts: 348
Joined: August 12th, 2020, 8:22 pm

Re: Golly scripts

Post by hotdogPi » July 19th, 2021, 2:50 pm

Here's my two-spark program. I only use C2 and D4; support remains for C4 and X4 (but not D8), but I don't use them since the sparkers would interfere with each other most of the time.

It's currently in the middle of doing traffic lights in C2. I've done all honey farms in C2 and D4 and traffic lights in C2 up to what the program shows.

Outputs are 5 numbers: (x, y, a, b, c)
a: number of generations between where you jumped to (the beginning if you didn't jump) and the first spark
b: number of generations between the first and second spark
c: number of generations after the second spark minus 1
The period is the sum of those three numbers plus 1 plus the number of generations you jumped, all times two if it's a flipper.

I've commented out a few things and changed a number or two to account for honey farms and traffic lights having 8-way symmetry. Without symmetry, x and y can be negative in C2, z should be range(4) in D4, and the D4 rotate section shouldn't be commented out.

Compared to the one-spark program, the "debris hits sparker" check is only two cells behind the spark, not three (shown as -4 in the program because the spark is already -2). This is because I was getting so many unsalvageable results.

After finding something, it will show what it found in the background along with the five numbers above. (The one-spark program didn't show what it found until the program actually ended.) Hitting OK will continue the program (and discard what was found), while hitting Cancel will quit the program and allow you to interact with what it found. To continue where you left off, change this number, where the 13 is "a" above plus the number it was already at. (It resets to 0 when x and/or y change.) You might need to occasionally increase it by one more if you get a whole bunch of the same result.

Code: Select all

if (x,y) == (5,5):
    g.run(13)

Code: Select all

import golly as g
import time

'''Initializing'''
g.select([0,0,1,1])
#g.autoupdate(1)
test1 = False
test2 = 0
test2a = 0
mode = 'C2' #C2, C4, D4, X4
rotate = False
copies = 2 if mode == 'C2' else 4
g.new("example")
input_pattern = g.parse('3o$obo$3o!')
g.putcells(input_pattern, 0, 0)
initial_box = g.getrect()
width = g.getrect()[2]
height = g.getrect()[3]
'''Generating rotations and reflections'''
if mode == 'C2':
    r_up = input_pattern
    g.select(initial_box)
    g.rotate(1)
    g.rotate(1)
    g.cut()
    g.paste(0,0,"or")
    r_down = g.getcells(g.getrect())
elif mode in ('C4','X4'):
    a = 1   #1 if even symmetry, 0 if odd; C4 and D8 only
    r_n = input_pattern
    initial_box = g.getrect()
    g.select(initial_box)
    if mode == 'X4':
        g.flip(1)
    g.rotate(mode != 'X4')
    g.select(g.getrect())
    g.cut()
    g.paste(0,0,"or")
    r_e = g.getcells(g.getrect())
    g.select(g.getrect())
    if mode == 'X4':
        g.flip(1)
    g.rotate(1)
    g.cut()
    g.paste(0,0,"or")
    r_s = g.getcells(g.getrect())
    g.select(g.getrect())
    if mode == 'X4':
        g.flip(1)
    g.rotate(mode != 'X4')
    g.cut()
    g.paste(0,0,"or")
    r_w = g.getcells(g.getrect())
    if mode == 'D8':
        g.select(g.getrect())
        g.flip(0)
        g.rotate(1)
        g.rotate(1)
        g.cut()
        g.paste(0,0,"or")
        r_nw = g.getcells(g.getrect())
        g.select(g.getrect())
        g.rotate(1)
        g.cut()
        g.paste(0,0,"or")
        r_ne = g.getcells(g.getrect())
        g.select(g.getrect())
        g.rotate(1)
        g.cut()
        g.paste(0,0,"or")
        r_se = g.getcells(g.getrect())
        g.select(g.getrect())
        g.rotate(1)
        g.cut()
        g.paste(0,0,"or")
        r_sw = g.getcells(g.getrect())
elif mode == 'D4':
    r_se = input_pattern
    g.select(initial_box)
    g.flip(1)
    g.select(g.getrect())
    g.cut()
    g.paste(0,0,"or")
    r_ne = g.getcells(g.getrect())
    g.select(g.getrect())
    g.flip(0)
    g.cut()
    g.paste(0,0,"or")
    r_nw = g.getcells(g.getrect())
    g.select(g.getrect())
    g.flip(1)
    g.cut()
    g.paste(0,0,"or")
    r_sw = g.getcells(g.getrect())
else:
    g.exit('Invalid symmetry input.')
g.new("example")
#single_cell = g.parse('o!')
'''Starting and ending bounds'''
if mode == 'C2':
    start_x, end_x, start_y, end_y = 5, 20, 0, 20
elif mode == 'C4':
    start_x, end_x, start_y, end_y = -15, 15, 0, 10
elif mode == 'D4':
    start_x, end_x, start_y, end_y = width+1, width+15, height+1, height+15
elif mode == 'X4':
    start_x, end_x, start_y, end_y = 0, 20, -20, 15
'''Main loop'''
for x in range(start_x, end_x+1):
    for y in range(start_y, end_y+1):
        for z in range(1 if mode in ('C2','X4') else 1 if mode == 'D8' else 1):
            if x == 5 and y < 5:
                continue
            if mode == 'C4' and not -y-width <= x < y: #C4 has a diagonal bounding box
                continue
            #if x < 0 and y < 0:
            #    continue
            if mode == 'D8' and y > x: #D8 takes only an eighth
                continue
            if mode == 'C4': #rotating
                width, height = height, width
                r_n, r_e, r_s, r_w = r_e, r_s, r_w, r_n
            #if mode == 'D4': #flipping
            #    if z % 2 == 0:
            #        r_se, r_ne, r_nw, r_sw = r_ne, r_se, r_sw, r_nw
            #    else:
            #        r_se, r_ne, r_nw, r_sw = r_sw, r_nw, r_ne, r_se
            recent_pops = list(range(100,109)) #9 same population in a row: end
            recent_min_x = list(range(100,108)) #checking for escaping gliders
            current_gen = None
            g.new("example")
            '''Putting patterns in place'''
            if mode == 'C2':
                g.putcells(r_down, 0, 0)
                num1 = int(g.getpop())
                g.putcells(r_up, x, y)
            elif mode == 'C4':
                g.putcells(r_n, x, y)
                num1 = int(g.getpop())
                g.putcells(r_e, y, -x-width+1-a)
                g.putcells(r_s, -x-width+1-a, -y-height+1-a)
                g.putcells(r_w, -y-height+1-a, x)
            elif mode == 'D4':
                g.putcells(r_se, x, y)
                num1 = int(g.getpop())
                g.putcells(r_ne, x, 0)
                g.putcells(r_nw, 0, 0)
                g.putcells(r_sw, 0, y)
            elif mode == 'X4':
                g.putcells(r_n, x, y)
                num1 = int(g.getpop())
                g.putcells(r_w, 0, y-x-width+height)
                g.putcells(r_e, x+y+width-1, -width+1)
                g.putcells(r_s, y+height-1, -x-width+1)
            if int(g.getpop()) != copies * num1:
                continue
            g.show(str((x,y)))
            g.update()
            initial_box = g.getrect()
            initial_box[0] -= 1 #must not touch initial pattern
            initial_box[1] -= 1
            initial_box[2] += 2
            initial_box[3] += 2
            hash1 = g.hash(initial_box)
            g.select(initial_box)
            g.flip(0)
            hash2 = g.hash(initial_box)
            g.flip(0)
            '''g.rotate(1)
            initial_box2 = g.getrect()
            initial_box2[0] -= 1 #must not touch initial pattern
            initial_box2[1] -= 1
            initial_box2[2] += 2
            initial_box2[3] += 2
            hash3 = g.hash(initial_box2)
            g.flip(0)
            hash4 = g.hash(initial_box2)
            g.flip(0)
            g.rotate(0)'''
            generation_snapshots = [''] * 200 #prevents same sequence from repeating
            test1 = False
            for generation in range(200):
                '''Outer loop'''
                recent_min_y = list(range(100,108)) #checking for escaping gliders
                #g.show('Generation ' + str(generation))
                if generation == 0:
                    if (x,y) == (5,5):
                        g.run(13)
                    pass
                else:
                    g.new("example")
                    g.putcells(current_gen)
                if generation > 0:
                    g.run(1)
                if g.getcells(g.getrect()) == current_gen:
                    break
                recent_pops.append(int(g.getpop()))
                recent_pops.pop(0)
                if recent_pops[-1] < 4 * copies: #no growth
                    break
                if recent_pops[-1] > 125 * copies:
                    break
                if max(recent_pops) == min(recent_pops): #9 generations with same population
                    break
                #if not g.getcell(14,0) or not g.getcell(0,1): #block broken
                #    break
                for w in range(2):
                    if w == 1:
                        g.new("example")
                        g.putcells(current_gen)
                    min_x = g.getrect()[0]
                    edge = g.getcells([min_x,-40+y,1,80])[1::2]
                    if not edge:
                        current_gen = g.getcells(g.getrect())[:]
                        continue
                    if w == 1 and max(edge) - len(edge) + 1 == min(edge):
                        current_gen = g.getcells(g.getrect())[:]
                        continue
                    while max(edge) - len(edge) + 1 != min(edge):
                        if w == 1:
                            edge.remove(max(edge))
                        else:
                            edge.remove(min(edge))
                    current_gen = g.getcells(g.getrect())[:]
                    #g.update()
                    #time.sleep(.5)
                    if w == 0:
                        recent_min_x.append(min_x)
                        recent_min_x.pop(0)
                        '''Checking for gliders'''
                        if g.getcells([min_x+3,min(edge)-8,3,16]): #not by itself
                            recent_min_x[-1] = 123
                        if recent_min_x == [recent_min_x[0]]*4 + [recent_min_x[4]]*4 \
                           and recent_min_x[4] == recent_min_x[0] - 1:
                            for i in range(min_x, min_x+3):
                                for j in range(min(edge),min(edge)+3):
                                    g.setcell(i,j,0) #delete glider
                            test1 = True
                            current_gen = g.getcells(g.getrect())[:]
                            continue
                        #if not test1:
                        #    continue
                    '''Determine sparks'''
                    if len(edge) == 1:
                        sparks = [(-2,-1),(-1,0),(0,1),(1,2)]
                    if len(edge) == 2:
                        sparks = [(-1,),(0,),(2,),(-2,-1),(-1,0),(1,2),(2,3)]
                    if len(edge) == 3:
                        sparks = [(-1,),(0,),(1,),(2,),(3,),(-2,-1),(-1,0),(2,3),(3,4)]
                    if len(edge) >= 4:
                        sparks = [(-1,),(0,),(1,),(2,),(3,),(4,),(-2,-1),(-1,0),(0,1),(1,2),(2,3),(3,4),(4,5)]
                    for spark in sparks:
                        #if g.empty():
                        #    break
                        '''Add sparks'''
                        #num1 = g.getrect()[1]+g.getrect()[3]
                        g.new("example")
                        g.putcells(current_gen)
                        for spark1 in spark:
                            if mode == 'C2':
                                g.setcell(min_x-2,spark1+min(edge),1)
                                g.setcell(-min_x+x+1+width,-spark1-min(edge)+y-1+height,1)
                            elif mode == 'C4':
                                g.setcell(min_x-2,spark1+min(edge),1)
                                g.setcell(-min_x+2-a,-spark1-min(edge)-a,1)
                                g.setcell(-spark1-min(edge)-a,min_x-2,1)
                                g.setcell(spark1+min(edge),-min_x+2-a,1)
                            elif mode == 'D4':
                                g.setcell(min_x-2,spark1+min(edge),1)
                                g.setcell(-min_x+x+width+1,-spark1+height+y-min(edge)-1,1)
                                g.setcell(min_x-2,-spark1+height+y-min(edge)-1,1)
                                g.setcell(-min_x+x+width+1,spark1+min(edge),1)
                            elif mode == 'X4':
                                center = (x+y+height-1+width, y-x-width+height+1) #actually twice center
                                offset_x = 2*(min_x-2)-center[0]
                                offset_y = 2*(spark1+min(edge))-center[1]
                                g.setcell((center[0]-offset_x)//2-1, (center[1]-offset_y)//2-1, 1)
                                g.setcell((center[0]-offset_y)//2-1, (center[1]-offset_x)//2-1, 1)
                                g.setcell((center[0]+offset_x)//2, (center[1]+offset_y)//2, 1)
                                g.setcell((center[0]+offset_y)//2, (center[1]+offset_x)//2, 1)
                            x1, y1 = min_x-4,spark1+min(edge)
                            current_gen_a = g.getcells(g.getrect())[:]
                        g.update()
                        #time.sleep(.1)
                        hash_list = []
                        recent_pops1 = list(range(100,139)) #40 generations same population: end
                        current_gen1 = None
                        for generation1 in range(200):
                            '''Inner loop'''
                            #g.show('Generation ' + str(generation))
                            if generation1 == 0:
                                #g.run(15)
                                pass
                            else:
                                g.new("example")
                                g.putcells(current_gen1)
                            if generation1 > 0:
                                g.run(1)
                            if g.getcells(g.getrect()) == current_gen1:
                                break
                            if not int(g.getpop()): #g.getrect() crashes if empty
                                break
                            if 5 <= generation1 <= 8: #prevents repeating evolution
                                if g.hash(g.getrect()) in generation_snapshots:
                                    generation_snapshots.pop(0)
                                    generation_snapshots.append(g.hash(g.getrect()))
                                    break
                                generation_snapshots.pop(0)
                                generation_snapshots.append(g.hash(g.getrect()))
                            recent_pops1.append(int(g.getpop()))
                            recent_pops1.pop(0)
                            #if recent_pops1[-1] < 4 * copies: #no growth
                            #    break
                            if recent_pops1[-1] > 125 * copies: #too complicated, very unlikely
                                break
                            if max(recent_pops1) == min(recent_pops1):
                                break
                            if generation1 % 10 == 0: #checks for same pattern
                                hash_list.append(g.hash(g.getrect()))
                                if hash_list[-1] in hash_list[:-1]:
                                    break
                            #if not g.getcell(14,0) or not g.getcell(0,1): #block broken
                            #    break
                            if g.getcell(x1, y1): #hits sparker
                                break
                            #if g.hash(initial_box2 if rotate else initial_box) in (hash1, hash2):
                            #if g.hash(initial_box) in (hash1, hash2):
                            #g.show('Generation ' + str(generation))
                            for w1 in range(2):
                                if w1 == 1:
                                    g.new("example")
                                    g.putcells(current_gen1)
                                min_y = g.getrect()[1]
                                edge1 = g.getcells([-40+x,min_y,80,1])[::2]
                                if not edge1:
                                    current_gen1 = g.getcells(g.getrect())[:]
                                    continue
                                if w1 == 1 and max(edge1) - len(edge1) + 1 == min(edge1):
                                    current_gen1 = g.getcells(g.getrect())[:]
                                    continue
                                while max(edge1) - len(edge1) + 1 != min(edge1):
                                    if w1 == 1:
                                        edge1.remove(max(edge1))
                                    else:
                                        edge1.remove(min(edge1))
                                current_gen1 = g.getcells(g.getrect())[:]
                                #g.update()
                                #time.sleep(.5)
                                if w1 == 0:
                                    '''Checking for gliders'''
                                    recent_min_y.append(min_y)
                                    recent_min_y.pop(0)
                                    if g.getcells([min(edge1)-8,min_y+3,16,3]): #not by itself
                                        recent_min_y[-1] = 123
                                    if recent_min_y == [recent_min_y[0]]*4 + [recent_min_y[4]]*4 \
                                       and recent_min_y[4] == recent_min_y[0] - 1:
                                        for i in range(min_y, min_y+3):
                                            for j in range(min(edge1),min(edge1)+3):
                                                g.setcell(j,i,0) #delete glider
                                        test1 = True
                                        current_gen1 = g.getcells(g.getrect())[:]
                                        continue
                                    #if not test1:
                                    #    continue
                                '''Determine sparks'''
                                if len(edge1) == 1:
                                    sparks2 = [(-2,-1),(-1,0),(0,1),(1,2)]
                                if len(edge1) == 2:
                                    sparks2 = [(-1,),(0,),(2,),(-2,-1),(-1,0),(1,2),(2,3)]
                                if len(edge1) == 3:
                                    sparks2 = [(-1,),(0,),(1,),(2,),(3,),(-2,-1),(-1,0),(2,3),(3,4)]
                                if len(edge1) >= 4:
                                    sparks2 = [(-1,),(0,),(1,),(2,),(3,),(4,),(-2,-1),(-1,0),(0,1),(1,2),(2,3),(3,4),(4,5)]
                                #sparks = [(-20,)]
                                for spark2 in sparks2:
                                    #if g.empty():
                                    #    break
                                    '''Add sparks'''
                                    #num1 = g.getrect()[1]+g.getrect()[3]
                                    g.new("example")
                                    g.putcells(current_gen1)
                                    for spark3 in spark2:
                                        if mode == 'C2':
                                            #g.setcell(min_x-2,spark1+min(edge),1)
                                            #g.setcell(-min_x+x+1+width,-spark1-min(edge)+y-1+height,1)
                                            g.setcell(spark3+min(edge1),min_y-2,1)
                                            g.setcell(-spark3-min(edge1)+x-1+width,-min_y+y+1+height,1)
                                        elif mode == 'C4':
                                            #g.setcell(min_x-2,spark1+min(edge),1)
                                            #g.setcell(-min_x+2-a,-spark1-min(edge)-a,1)
                                            #g.setcell(-spark1-min(edge1)-a,min_x-2,1)
                                            #g.setcell(spark1+min(edge1),-min_x+2-a,1)
                                            g.setcell(spark3+min(edge1),min_y-2,1)
                                            g.setcell(-spark3-min(edge1)-a,-min_y+2-a,1)
                                            g.setcell(min_y-2,-spark1-min(edge1)-a,1)
                                            g.setcell(-min_y+2-a,spark1+min(edge1),1)
                                        elif mode == 'D4':
                                            #g.setcell(min_x-2,spark1+min(edge1),1)
                                            #g.setcell(-min_x+x+width+1,-spark1+height+y-min(edge1)-1,1)
                                            #g.setcell(min_x-2,-spark1+height+y-min(edge1)-1,1)
                                            #g.setcell(-min_x+x+width+1,spark1+min(edge1),1)
                                            g.setcell(spark3+min(edge1),min_y-2,1)
                                            g.setcell(-spark3+width+x-min(edge1)-1,-min_y+y+height+1,1)
                                            g.setcell(-spark3+width+x-min(edge1)-1,min_y-2,1)
                                            g.setcell(spark3+min(edge1),-min_y+y+height+1,1)
                                        elif mode == 'X4':
                                            center = (x+y+height-1+width, y-x-width+height+1) #actually twice center
                                            #offset_x = 2*(min_x-2)-center[0]
                                            #offset_y = 2*(spark1+min(edge1))-center[1]
                                            offset_x = 2*(spark3+min(edge1))-center[1]
                                            offset_y = 2*(min_y-2)-center[0]
                                            g.setcell((center[0]-offset_x)//2-1, (center[1]-offset_y)//2-1, 1)
                                            g.setcell((center[0]-offset_y)//2-1, (center[1]-offset_x)//2-1, 1)
                                            g.setcell((center[0]+offset_x)//2, (center[1]+offset_y)//2, 1)
                                            g.setcell((center[0]+offset_y)//2, (center[1]+offset_x)//2, 1)
                                        x2, y2 = spark3+min(edge1),min_y-4
                                        current_gen1a = g.getcells(g.getrect())[:]
                                    #g.update()
                                    #time.sleep(.01)
                                    hash_list = []
                                    recent_pops2 = list(range(100,139)) #40 generations same population: end
                                    for generation2 in range(1000):
                                        '''Inner loop'''
                                        g.run(1)
                                        if not int(g.getpop()): #g.getrect() crashes if empty
                                            break
                                        recent_pops2.append(int(g.getpop()))
                                        recent_pops2.pop(0)
                                        #if recent_pops2[-1] < 4 * copies: #no growth
                                        #    break
                                        if recent_pops2[-1] > 125 * copies: #too complicated, very unlikely
                                            break
                                        if max(recent_pops2) == min(recent_pops2):
                                            break
                                        if g.getcell(x1, y1) or g.getcell(x2, y2): #hits sparker
                                            break
                                        if g.hash(initial_box) in (hash1, hash2):
                                            if (generation, generation1, generation2) == (2,16,13):
                                                continue
                                            g.putcells(current_gen_a, 100, 0)
                                            g.putcells(current_gen1a, 200, 0)
                                            g.update()
                                            g.warn('Found: %s, %s, %s, %s, %s' % (x, y, generation, generation1, generation2))
                                            generation_snapshots = [''] * 200

HartmutHolzwart
Posts: 604
Joined: June 27th, 2009, 10:58 am
Location: Germany

Re: Golly scripts

Post by HartmutHolzwart » July 20th, 2021, 5:22 pm

Dumb question: Could this script be modified to find spaceship hasslers like the PPS?
https://www.conwaylife.com/wiki/Pre-pulsar_spaceship

hotdogPi
Posts: 348
Joined: August 12th, 2020, 8:22 pm

Re: Golly scripts

Post by hotdogPi » July 22nd, 2021, 11:28 am

HartmutHolzwart wrote:
July 20th, 2021, 5:22 pm
Dumb question: Could this script be modified to find spaceship hasslers like the PPS?
https://www.conwaylife.com/wiki/Pre-pulsar_spaceship
What you would need to do is:

1. Instead of initial_box being fixed in place, just the RLE needs to match, so it can be anywhere in the Life universe. You might or might not want to make it have to be exact; if junk is allowed, you'll have a lot of partials that can't be completed, but if you don't allow junk, it will miss those with dying sparks or escaping gliders.
2. The way the sparks are added right now, it's symmetrical. A spaceship can't form this way, so you'll have to add sparks to only one side.

You'll probably want the one-spark program for this, not the two-spark program.

Of note is that my programs work in whatever rule Golly is currently running in, so if you want to use it for an OCA, you can. Glider detection in rules without monotonic c/4 spaceships will almost always be ignored, with very little chance of messing things up. In rules with those spaceships, whether orthogonal or diagonal, anything in a 3×3 box or less, like Life's glider, will work perfectly, but if a larger such ship exists, you might need to change a few numbers in that section of code.

Post Reply