## 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

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().
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

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
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

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
#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
#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

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

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.