Based on Knightlife's first script, I wrote a program that tests random 90-degree radially symmetric patterns in a finite universe until they oscillate, and stops when it finds an oscillator of a sufficiently high period. The oscillation detection is based on Andrew Trevorrow's oscar.py script. The patterns are run in a finite universe so that gliders would not need to be dealt with, as they would just turn into blocks when they hit the edge.
I have very little experience with python, and so the script may not be very good (it really isn't); it merely demonstrates the idea. Code improvements would be nice (actually, you should probably just write your own script, as this one isn't that great).
Code: Select all
from glife import rect, pattern
import golly as g
#These five variables define the search
px = 5 #This defines the width of the random pattern (pattern width = 2*px)
ux = 9 #This defines the width of the finite universe (universe width = 2*ux)
d = 35 #This defines the density of the randowm pattern (density = d/100)
minp = 5 #This is the minimum period oscillator to be searched for
maxgen = 150 #this is for double checking the pattern to see if it is really an oscillator
found = False
# initialize lists
hashlist = [] # for pattern hash values
genlist = [] # corresponding generation counts
poplist = [] # corresponding population counts
boxlist = [] # corresponding bounding boxes
#Create random 90-degree radially symmetric pattern; based on Knightlife's Quadsymm script
def rand_quad(psize,density):
g.new("")
g.select([0,0,psize,psize])
g.randfill(density)
r = rect( g.getselrect() )
maxstate = g.numstates() - 1
for row in xrange(r.top, r.top + r.height):
for col in xrange(r.left, r.left + r.width):
g.setcell(r.left + r.width + r.height - 1 - (row - r.top), r.top - r.width + r.height + (col - r.left), g.getcell(col, row))
g.setcell(r.left + 2*r.width - 1 - (col - r.left), r.top + 2*r.height - 1 - (row - r.top), g.getcell(col, row))
g.setcell(r.left + r.width - r.height + (row - r.top), r.top + r.width + r.height - 1 - (col - r.left), g.getcell(col, row))
#Run the pattern until it oscillates; based on Andrew Treverrow's oscar.py script
# --------------------------------------------------------------------
def show_spaceship_speed(period, deltax, deltay):
# we found a moving oscillator
if period == 1:
g.show("Spaceship detected (speed = c)")
elif (deltax == deltay) or (deltax == 0) or (deltay == 0):
speed = ""
if (deltax == 0) or (deltay == 0):
# orthogonal spaceship
if (deltax > 1) or (deltay > 1):
speed += str(deltax + deltay)
else:
# diagonal spaceship (deltax == deltay)
if deltax > 1:
speed += str(deltax)
g.show("Spaceship detected (speed = " + speed + "c/" +str(period) + ")")
else:
# deltax != deltay and both > 0
speed = str(deltay) + "," + str(deltax)
g.show("Knightship detected (speed = " + speed + "c/" + str(period) + ")")
# --------------------------------------------------------------------
def oscillating():
# return True if the pattern is empty, stable or oscillating
# first get current pattern's bounding box
prect = g.getrect()
pbox = rect(prect)
if pbox.empty:
g.show("The pattern is empty.")
return 1
# get current pattern and create hash of "normalized" version -- ie. shift
# its top left corner to 0,0 -- so we can detect spaceships and knightships
## currpatt = pattern( g.getcells(prect) )
## h = hash( tuple( currpatt(-pbox.left, -pbox.top) ) )
# use Golly's hash command (3 times faster than above code)
h = g.hash(prect)
# determine where to insert h into hashlist
pos = 0
listlen = len(hashlist)
while pos < listlen:
if h > hashlist[pos]:
pos += 1
elif h < hashlist[pos]:
# shorten lists and append info below
del hashlist[pos : listlen]
del genlist[pos : listlen]
del poplist[pos : listlen]
del boxlist[pos : listlen]
break
else:
# h == hashlist[pos] so pattern is probably oscillating, but just in
# case this is a hash collision we also compare pop count and box size
if (int(g.getpop()) == poplist[pos]) and \
(pbox.wd == boxlist[pos].wd) and \
(pbox.ht == boxlist[pos].ht):
period = int(g.getgen()) - genlist[pos]
if period == 1:
if pbox == boxlist[pos]:
g.show("The pattern is stable.")
else:
show_spaceship_speed(1, 0, 0)
elif pbox == boxlist[pos]:
g.show("Oscillator detected (period = " + str(period) + ")")
else:
deltax = abs(boxlist[pos].x - pbox.x)
deltay = abs(boxlist[pos].y - pbox.y)
show_spaceship_speed(period, deltax, deltay)
return period
else:
# look at next matching hash value or insert if no more
pos += 1
# store hash/gen/pop/box info at same position in various lists
hashlist.insert(pos, h)
genlist.insert(pos, int(g.getgen()))
poplist.insert(pos, int(g.getpop()))
boxlist.insert(pos, pbox)
return 0
# --------------------------------------------------------------------
def fit_if_not_visible():
# fit pattern in viewport if not empty and not completely visible
r = rect(g.getrect())
if (not r.empty) and (not r.visible()): g.fit()
# --------------------------------------------------------------------
rand_quad(px,d)
per = 0
while not found:
while per <= 0:
per = oscillating()
g.select([px-ux,px-ux,2*ux,2*ux])
g.advance(0,1)
g.setgen("+1")
#g.update()
if per >= minp:
per = 0
g.select([px-ux,px-ux,2*ux,2*ux])
g.copy()
g.new("")
g.paste(0,0,"or")
while (per <= 0) and (int(g.getgen()) < maxgen):
per = oscillating()
g.run(1)
if per >= minp:
found = True
else:
rand_quad(px,d)
per = 0
else:
rand_quad(px,d)
per = 0
#g.show("Oscillator detected (period = " + str(per) + ")")
This program is very simple, and so does not separate sub-patterns from the overall pattern. What might be better is to perform a census on radially symmetric patterns so that ones consisting of disjoint objects (such as the p5 octagon and some blinkers) are not counted as a single high period oscillator. This is the reason for the removal of period 10 in the search results. The same idea can be applied to different symmetry types, such as odd 90-degree radial symmetry, bilateral symmetry, etc. and could be made to save files for results rather than just stop.
Edit: I found some oscillators in other rules with this (probably nothing new). Note, some of these were found with an odd-width symmetry search.
#C A period 8 oscillator in 2x2
x = 10, y = 10, rule = B36/S125
6bo$3bo3bo$b3o3bo$o6b2o3$b2o6bo$2bo3b3o$2bo3bo$3bo!
#C Some oscillators in Day and Night
x = 166, y = 70, rule = B3678/S34678
23bobobo21b2ob2o$22bob3obo19bob3obo73b3o$21bob5obo18b7o70b2o3bo$22b7o
20b5o71bob3o$21b9o18b7o70bob3obo$22b7o19bob3obo72b3obo$21bob5obo19b2ob
2o72bo3b2o$22bob3obo97b3o$23bobobo20$156b2o$155bo2bo$154bob2obo$27b2o
125b6o$23bob3o50bo2bob2o67bob6obo$22b8o46b9o69b6o$20bob9o17bobo2bobo
20b8o66b14o$4o16b10o19b6o17b2ob10o19bob2o41bob12obo$4o17b10o17b8o16b
15o16b3ob2o39bob14obo$4o17b10o18b6o18b14o16bo3bo40bob14obo$4o18b10o17b
6o17b16o16bo3bo40bob12obo$21b9obo16b8o17b14o16b2ob3o41b14o$22b8o19b6o
18b14o17b2obo46b6o$24b3obo19bobo2bobo16b16o64bob6obo$23b2o48b14o67b6o$
73b15o66bob2obo$75b10ob2o67bo2bo$76b8o72b2o$75b9o$75b2obo2bo5$48bob2ob
o$47bobo2bobo$47b8o$48b6o$47b8o$43b2ob10ob2o$42bob14obo$43b16o$42bob
14obo$42bob14obo$43b16o$42bob14obo$43b2ob10ob2o$47b8o$48b6o$47b8o$47bo
bo2bobo$48bob2obo!