Code: Select all
def convert_rle_to_grid(rle):
if 'B3/S23' in rle:
rle = rle[rle.index('B3/S23')+6:] #starts after the dimension and rule identifiers
x = 0
y = 0
pattern = {}
num = '' #num keeps track of digits and then processes it when it hits a b, o, or $
while rle:
if rle[0] in '0123456789': #digit
num += rle[0]
rle = rle[1:] #remove leftmost character
elif rle[0] in ('o','b'):
if num == '': #no number: only one
num = 1
num = int(num)
for i in range(num):
pattern[(x,y)] = (1 if rle[0] == 'o' else 0)
x += 1
num = ''
rle = rle[1:] #remove leftmost character
elif rle[0] == '$':
if num == '':
num = 1
num = int(num)
for i in range(num):
y += 1
x = 0
num = ''
rle = rle[1:] #remove leftmost character
elif rle[0] == '!':
break
elif rle[0] in ' \n\t*': #asterisk is used to mark as period 1000+; just for this program, not typical RLE
rle = rle[1:] #remove leftmost character
else:
raise ValueError('Invalid RLE', rle)
max_x = max((-1000 if pattern[cell] == 0 else cell[0]) for cell in pattern)
max_y = max((-1000 if pattern[cell] == 0 else cell[1]) for cell in pattern)
for i in range(max_x+1):
for j in range(max_y+1):
pattern[(i,j)] = pattern.get((i,j), 0)
return pattern
def print_grid(pattern): #shows pattern as a readable grid
min_x = min((1000 if pattern[cell] == 0 else cell[0]) for cell in pattern) #only reads cells that are on
max_x = max((-1000 if pattern[cell] == 0 else cell[0]) for cell in pattern)
min_y = min((1000 if pattern[cell] == 0 else cell[1]) for cell in pattern)
max_y = max((-1000 if pattern[cell] == 0 else cell[1]) for cell in pattern)
for y in range(min_y, max_y+1):
for x in range(min_x, max_x+1):
print(('o' if pattern[(x,y)] == 1 else '.'), end='')
print('') #newline
def run_pattern(pattern, extended):
initial_pattern = pattern.copy()
pattern_120 = None
min_x = 0 #these four are the temporary minima and maxima
max_x = max((0 if initial_pattern[cell] == 0 else cell[0]) for cell in pattern)
min_y = 0
max_y = max((0 if initial_pattern[cell] == 0 else cell[1]) for cell in pattern)
initial_box = (min_x, max_x, min_y, max_y)
cell_count = sum(initial_pattern.get(cell, 0) for cell in pattern)
min_min_x = min_x #these four are the permanent minima and maxima, used for determining maximum pattern size
max_max_x = max_x
min_min_y = min_y
max_max_y = max_y
for period in range(1, 100000 if extended else 1000): #maximum oscillator period
if period == 120:
pattern_120 = pattern.copy()
if period == 122:
identical = True
for i in pattern_120: #checks if it has returned to its original state
if pattern.get(i, 0) != pattern_120.get(i, 0):
identical = False
break
if identical:
print('Not an oscillator, generations 120 and 122 are identical: %s' % convert_grid_to_rle(initial_pattern))
return
if not sum(pattern.get(cell, 0) for cell in pattern):
print('Not an oscillator, dies out completely: %s' % convert_grid_to_rle(initial_pattern))
return
new_pattern = {}
for x in range(min_x-1, max_x+2):
for y in range(min_y-1, max_y+2): #for each cell
count = 0
for x1 in range(-1,2):
for y1 in range(-1,2): #check adjacent cells
if (x1 != 0 or y1 != 0) and pattern.get((x+x1,y+y1), 0) == 1:
count += 1
if count == 3: #3: always alive
new_pattern[(x,y)] = 1
elif count == 2: #2: stays the way it was before
new_pattern[(x,y)] = (pattern.get((x,y), 0) == 1)
else: #0, 1, 4+: dead
new_pattern[(x,y)] = 0
min_x = min((1000 if new_pattern[cell] == 0 else cell[0]) for cell in new_pattern)
max_x = max((-1000 if new_pattern[cell] == 0 else cell[0]) for cell in new_pattern)
min_y = min((1000 if new_pattern[cell] == 0 else cell[1]) for cell in new_pattern)
max_y = max((-1000 if new_pattern[cell] == 0 else cell[1]) for cell in new_pattern)
new_pattern2 = new_pattern.copy()
for i in new_pattern: #reduces size if it's smaller
if not (min_x <= i[0] <= max_x) or not (min_y <= i[1] <= max_y):
if new_pattern[i] == 1:
raise ValueError('Live cell outside grid: %s, %s' % (i[0],i[1])) #should never happen, ideally
else:
new_pattern2[i] = new_pattern[i]
min_min_x = min(min_min_x, min_x) #sets new absolute minima and maxima
max_max_x = max(max_max_x, max_x)
min_min_y = min(min_min_y, min_y)
max_max_y = max(max_max_y, max_y)
pattern = new_pattern2.copy()
if max_max_x - min_min_x > 40 + (initial_box[1]-initial_box[0]) or max_max_y - min_min_y > 40 + (initial_box[1]-initial_box[0]):
print('Not an oscillator, bounding box limit: %s' % convert_grid_to_rle(initial_pattern))
return
identical = (cell_count == sum(pattern.get(cell, 0) for cell in pattern))
for i in initial_pattern: #checks if it has returned to its original state
if pattern.get(i, 0) != initial_pattern.get(i, 0):
identical = False
break
if identical:
if period == 1 and sum(pattern.get(cell, 0) for cell in pattern) >= 24:
return
return (convert_grid_to_rle(pattern), period, max_max_x-min_min_x+1, max_max_y-min_min_y+1, -min_min_x, -min_min_y)
#0: RLE. 1: period. 2, 3: maximum bounding box for x and y. 4, 5: Greatest negative for calculating offset.
print('Not an oscillator, maximum generations reached: %s' % convert_grid_to_rle(initial_pattern))
return
#these create the digits for labeling periods
zero = 'x = 8, y = 14, rule = B3/S23\n2b2obo$2bob2o$2o4b2o$o5bo$bo5bo$2o4b2o$o5bo$bo5bo$2o4b2o$o5bo$bo5bo$2o4b2o$2b2obo$2bob2o!'
one = 'x = 2, y = 14, rule = B3/S23\n2o$bo$o$2o2$2o$bo$o$2o2$2o$bo$o$2o!'
two = 'x = 8, y = 14, rule = B3/S23\n2b2obo$2bob2o$6b2o$6bo$7bo$6b2o$2b2obo$2bob2o$2o$o$bo$2o$2b2obo$2bob2o!'
three = 'x = 6, y = 14, rule = B3/S23\n2obo$ob2o$4b2o$4bo$5bo$4b2o$2obo$ob2o$4b2o$4bo$5bo$4b2o$2obo$ob2o!'
four = 'x = 8, y = 14, rule = B3/S23\n2o4b2o$bo5bo$o5bo$2o4b2o$2bob2o$2b2obo$6b2o$7bo$6bo$6b2o3$6b2o$6b2o!'
five = 'x = 8, y = 14, rule = B3/S23\n2bob2o$2b2obo$2o$bo$o$2o$2bob2o$2b2obo$6b2o$7bo$6bo$6b2o$2bob2o$2b2obo!'
six = 'x = 8, y = 14, rule = B3/S23\n2b2obo$2bob2o$2o$o$bo$2o$2b2obo$2bob2o$2o4b2o$o5bo$bo5bo$2o4b2o$2b2obo$2bob2o!'
seven = 'x = 6, y = 14, rule = B3/S23\nbob2o$b2obo$5b2o$6bo$5bo$5b2o$3b2o$4bo$3bo$3b2o$b2o$2bo$bo$b2o!'
eight = 'x = 8, y = 14, rule = B3/S23\n2b2obo$2bob2o$2o4b2o$o5bo$bo5bo$2o4b2o$2b2obo$2bob2o$2o4b2o$o5bo$bo5bo$2o4b2o$2b2obo$2bob2o!'
nine = 'x = 8, y = 14, rule = B3/S23\n2b2obo$2bob2o$2o4b2o$o5bo$bo5bo$2o4b2o$2b2obo$2bob2o$6b2o$6bo$7bo$6b2o$2b2obo$2bob2o!'
num_dict = {'0':'zero','1':'one','2':'two','3':'three','4':'four','5':'five','6':'six','7':'seven','8':'eight','9':'nine'}
digit_rles = [zero,one,two,three,four,five,six,seven,eight,nine]
height = 600 #note: if a single period is taller than height variable, it won't work properly
#These aren't quite valid RLEs in reality, as there needs to be a newline after the rule.
#The program ignores anything before and including "B3/S23". If you need to save space, it can omitted, too.
patterns = ['x = 24, y = 12, rule = B3/S23 $2o20b2o$bo20bo$bobo16bobo$2b2o16b2o2$5b6o2b6o2$2b2o16b2o$bobo16bobo$b\
o20bo$2o20b2o!',
'x = 11, y = 15, rule = B3/S23 4b2o$5bo$4bo$3bob3o$3bobo2bo$2obo2b2obo$bobobobobo$bobobobob2o$2bo4bo\
2bo$3b2o3bo$5b3o$b3o$bo2b2o$4bobo$5bo!',
'x = 14, y = 14, rule = B3/S23 10b2o$6b2o2bo$6bobobo$7bo2bob2o$10bob2o$10bo$b2o5bobo$bobo4b2o$2bo3b2o\
$7bo$7o$o$3b2o$3b2o!',
'x = 22, y = 25, rule = B3/S23 10b2o$9bobo$9bo$7b2ob4o$6bobobo2bo$6bobobo$4b2o2b2o$3bo4bo$3b5o$b2o3bo\
4bo$o2b3o3b2ob2o$2obo5b2ob2o3b2o$3bo14bo$3b2o3b2ob2o5bob2o$8b2ob2o3b3o\
2bo$10bo4bo3b2o$14b5o$13bo4bo$12b2o2b2o$11bobobo$8bo2bobobo$8b4ob2o$\
12bo$10bobo$10b2o!',
'x = 31, y = 12, rule = B3/S23 2o$bo27b2o$bobo25bo$2b2o23bobo$7bo4bo14b2o$5b2ob4ob2o3bo4bo$7bo4bo3b2o\
b4ob2o$2b2o14bo4bo$bobo23b2o$bo25bobo$2o27bo$29b2o!',
'x = 20, y = 24, rule = B3/S23 \
2o16b2o$bo7b2o7bo$bobo3bo4bo3bobo$2b2o2bo6bo2b2o$5bo8bo$5bo8bo$5bo8bo$\
2b2o2bo6bo2b2o$bobo3bo4bo3bobo$bo7b2o7bo$2o16b2o$7b2o2b2o$7b2o2b2o$2o\
16b2o$bo7b2o7bo$bobo3bo4bo3bobo$2b2o2bo6bo2b2o$5bo8bo$5bo8bo$5bo8bo$2b\
2o2bo6bo2b2o$bobo3bo4bo3bobo$bo7b2o7bo$2o16b2o!',
'x = 22, y = 24, rule = B3/S23 \
2o16b2o$bo7b2o7bo$bobo3bo4bo3bobo$2b2o2bo6bo2b2o$5bo8bo$5bo8bo$5bo8bo$\
2b2o2bo6bo2b2o$bobo3bo4bo3bobo$bo7b2o7bo$2o16b2o$10b2o2b2o$10b2o2b2o$\
2b2o16b2o$3bo16bo$3bobo12bobo$4b2o12b2o$8b8o$8bob4obo$8b8o$4b2o12b2o$\
3bobo12bobo$3bo16bo$2b2o16b2o!',
'x = 23, y = 23, rule = B3/S23 \
10b3o$10bo$13bo$12b2o$8bo3bo$9bobo$10bo2$18bo$2b2o13bo$o2b2o11bo4b2o$o\
4bo11bo4bo$2o4bo11b2o2bo$5bo13b2o$4bo2$12bo$11bobo$10bo3bo$9b2o$9bo$\
12bo$10b3o!',
'x = 13, y = 12, rule = B3/S23 11b2o$11bo$8b2obo$6bo3bo$5bo$5bo$7bo$7bo$2bo3bo$bob2o$bo$2o!',
'x = 15, y = 15, rule = B3/S23\
10bo$9bobo$10bo2$8b5o$7bo5bo$10b3obo$5bo3b2obobo$4bo4bo3bo$bo2bo2b2o$o\
bobob2o$bo2bobo$4bob2o$5bo2bo$6b2o!',
'x = 10, y = 10, rule = B3/S23 2o5bo$o2b2obobo$b2o4bobo$8bo$b4o$bo3bo2bo$2bo2bo2bo$3bobobo$4b2obobo$8b2o!',
'x = 16, y = 14, rule = B3/S236b2o$5bo2bo3$7b2o2b2o$2b2obob2o3bo$o2bob5o2bob2o$2obo2b5obo2bo$3bo3b2o\
bob2o$3b2o2b2o3$7bo2bo$8b2o!',
'x = 19, y = 19, rule = B3/S23\
10b2o$8bo2bo$8b3o2$6b7o$5bo7bo$4bob3ob3obo$2o2bobo5bobo$obobobo5bobob\
2o$2bobo9bobo$b2obobo5bobobobo$4bobo5bobo2b2o$4bob3ob3obo$5bo7bo$6b7o\
2$8b3o$7bo2bo$7b2o!',
'x = 47, y = 16, rule = B3/S23\
6b2o18b2o8b2o$7bo18bo2bo6b2o$4b3o20b3o10bo$4bo4bo2bo2bo2bo2bo2bo9b7o$\
2bobob26o2bo$bobobo26bobob2o2b3o$bobobob2o2b3o2b3o2b3o2b3o2b2ob2obo3bo\
bob2o$2ob2obo3b2o3b2o3b2o3b2o5bo2b3o4b2obo$bobobob2o2b3o2b3o2b3o2b3ob\
2o2bo2bo3bobo2bo$bobobo25bobo6b3o2b2o$2bobob25obob4o$4bo4bo2bo2bo2bo2b\
o2bo2bo2bobobo4bob2o$4b3o24bobo2b4obo$7bo25bob2o5bo$6b2o25bo5b3o$32b2o5bo!',
'x = 12, y = 12, rule = B3/S23 4b2o$3bo2bo$4b2obo$5bobo2bo$2b4obobobo$bo5b3obo$ob3o5bo$obobob4o$bo2bo\
bo$4bob2o$5bo2bo$6b2o!',
'x = 33, y = 33, rule = B3/S23\
14b2o$14b2o2b2o$12b2obo2b2o$12b3o3$13b2o$10bo2b2o$9bo$8bo$9b2o$9b3o$3b\
4o4b2o$2bo4bo4b2o16b2o$bobo3bo4b3o15b2o$obo3bo7b2o$o14b2o$o14b3o12b3o$\
o2bo13b2o6b2o2bob2o$b2o15b2o5b2o2b2o$18b3o8b2o$20b2o$21b2o2bo$21b2obo$\
23bo$18b2o$17bo2bo$20bo$20bo$14bo3bobo$13bo3bobo$13bo4bo$14b4o!',
'x = 107, y = 21, rule = B3/S23\
b2o100b2o$b2o99bo2bo$105bo$bo103bo$obo96bo3bobo$o2bo2b2o90bo3bobo$4bob\
2o90bo4bo$2b2o95b4o2$7bobo2bob2obo2bob2obo2bob3o4b4o4b4o4b3obo2bob2obo\
2bob3o4b4o4b4o4b4o$7bob4ob2ob4ob2ob4ob4o2b6o2b6o2b4ob4ob2ob4ob4o2b6o2b\
6o2b6o$7bobo2bob2obo2bob2obo2bob2obo2bob2obo2bob2obo2bob2obo2bob2obo2b\
ob2obo3b4o4b4o4b4o$100b2o$2b2o95b4o$2b2o2b2o90bobo2bo$2obo2b2o90b2o2bo\
bo$3o100bobo$105b2o$104b3o$b2o100bobo$b2o100b2o!',
'x = 28, y = 19, rule = B3/S23\
2o24b2o$2o24b2o$8b2o$7bo2bo$8b2o2$12b3o$12bobo$12b3o$13b2o$13b3o$13bob\
o$13b3o2$18b2o$17bo2bo$18b2o$2o24b2o$2o24b2o!',
'x = 31, y = 15, rule = B3/S23\
19bo$18bob2o$18bob2o$19b2o2$8b2o12b2o$8b2o12b2o3$7bobo$6bo18b2o$b2o2bo\
4bo10b2obo2bob2o$b2obo2bob2o10b2o2bo4bo$5b2o19bo$27bobo!',
'x = 23, y = 39, rule = B3/S23\
3b2o10b2o$2bo2bo8bo2bo$2b3o2b6o2b3o$5b2o6b2o$4bo10bo$4b2obo4bob2o$9b2o\
$18bo$4bo12b2o$4b2o$10b3o2b3o2bobo$obo2b3o2b3o4bob4o$4obo3bo3bo7b2o$2o\
9bo$11bo2$10b2o$9bo2bo$10b2o2$10b2o$9bo2bo$10b2o2$11bo$2o9bo$4obo3bo3b\
o7b2o$obo2b3o2b3o4bob4o$10b3o2b3o2bobo$4b2o$4bo12b2o$18bo$9b2o$4b2obo\
4bob2o$4bo10bo$5b2o6b2o$2b3o2b6o2b3o$2bo2bo8bo2bo$3b2o10b2o!',
'x = 41, y = 52, rule = B3/S23\
13b3o$14bo10b3o$14bo11bo$13b3o10bo$25b3o$13b3o$13b3o9b3o$25b3o$13b3o$\
14bo10b3o$14bo11bo$13b3o10bo$25b3o6$8o$ob4obo8b2o15b8o$8o8bobo14bob4ob\
o$16bo16b8o4$13b2o12b2o$13b2o12b2o4$16bo16b8o$8o8bobo14bob4obo$ob4obo\
8b2o15b8o$8o6$25b3o$13b3o10bo$14bo11bo$14bo10b3o$13b3o$25b3o$13b3o9b3o\
$13b3o$25b3o$13b3o10bo$14bo11bo$14bo10b3o$13b3o!',
'x = 20, y = 20, rule = B3/S23\
10b2o$10bo$2bob2ob2obo5b2o$2b2obobobo6bo$8bo8bo$16b2o$10bo$9bo6b2o$o8b\
o2bobo2bo$3o6b2o5bo$3bo13b3o$2bobo14bo$2b2o2$2b2o$2bo8bo$3bo6bobobob2o\
$2b2o5bob2ob2obo$9bo$8b2o!',
'x = 30, y = 30, rule = B3/S23\
19b3o$19b3o$12b2o3b2o2b3o$12b2o3b2o$17b3o$19bo$2bo10b2o4bo$2bo9bo2bo$\
3o9bobo$2o7bo3bo4b3o$2o2b3o2bo$2b3o4bo5bo6bo$2b3o9bo7bo3b2o$14bo2bobob\
obo2b2o$7bo6b2o6b2o$6bobo$2b2o2bo2bo$2b2o3b2o16b3o$20bo4b3o$20bo2b3o2b\
2o$9b3o4bo3bo7b2o$15bobo9b3o$14bo2bo9bo$10bo4b2o10bo$10bo$10b3o$11b2o\
3b2o$6b3o2b2o3b2o$8b3o$8b3o!',
'x = 35, y = 23, rule = B3/S23\
25b2o$25bo$17bob2ob2obo5b2o$10b2o5b2obobobo6bo$10bo12bo8bo$2bob2ob2obo\
20b2o$2b2obobobo15bo$8bo4b3o8bo6b2o$24bo2bobo2bo$10bo6bo6b2o5bo$9bo7bo\
14b3o$o8bo2bobobobo15bo$3o6b2o6b2o$3bo$2bobo$2b2o15b3o4bo$25bobobob2o$\
2b2o20bob2ob2obo$2bo8bo12bo$3bo6bobobob2o5b2o$2b2o5bob2ob2obo$9bo$8b2o!',
'x = 17, y = 17, rule = B3/S23\
5b2o3b2o$5bobobobo$7bobo$7bobo$7bobo$2o4bo3bo4b2o$o4bo5bo4bo$b4o7b4o2$\
b4o7b4o$o4bo5bo4bo$2o4bo3bo4b2o$7bobo$7bobo$7bobo$5bobobobo$5b2o3b2o!',
'x = 11, y = 11, rule = B3/S23 5b2o$4bobo$bo2bob2o$obobo3bo$bo2bo3b3o$4bo5bo$5b5o2$7bo$6bobo$7bo!',
'x = 10, y = 12, rule = B3/S23 2o$bo$bobo$2b2o4b2o$9bo$5b4o$5bo$2bo3b3o$2b4o2bo$5bo$4bo$4b2o!',
'x = 13, y = 12, rule = B3/S23 11b2o$11bo$9bobo$9b2o$5b2o$6bo$6bo$6b2o$2b2o$bobo$bo$2o!',
'x = 25, y = 15, rule = B3/S23\
$5bo$4o3bo11bo$3bo3bo9bo3b4o$7bo3b3o3bo3bo$4bo7bo4bo$5b2o13bo$18b2o2$\
5b2o8b2o$5bo2b6o2bo$6b2o6b2o$3b3o10b3o$3bo2bobo4bobo2bo$4b2o4b2o4b2o!',
'x = 33, y = 13, rule = B3/S23\
17bo$16b2o$15b3obo9b2o$14b2o13b2o$15b2o$16bo2$16bo$15b2o$2b2o10b2o13b\
2o$2b2o11b3obo9b2o$16b2o$17bo!',
'x = 33, y = 26, rule = B3/S23\
11b2o7b2o$10bo2bo5bo2bo$3bo5bobobo5bobobo5bo$2b2o4b3obo7bob3o4b2o$bob\
2o3b3o11b3o3b2obo$3o2bo21bo2b3o$2bobobo19bobobo$3bobobo17bobobo$4bo2b\
3o13b3o2bo$5b2obo3b3o3b3o3bob2o$6b2o4bobo3bobo4b2o$6bo5b3o3b3o5bo3$6bo\
19bo$6b2o17b2o$5b2obo15bob2o$4bo2b3o13b3o2bo$3bobobo17bobobo$2bobobo\
19bobobo$3o2bo21bo2b3o$bob2o3b3o11b3o3b2obo$2b2o4b3obo7bob3o4b2o$3bo5b\
obobo5bobobo5bo$10bo2bo5bo2bo$11b2o7b2o!',
'x = 23, y = 7, rule = B3/S23\
obobo$obobo11b3ob3o$o3bo3bo2bobo5bo$bobo5bo3bo2b2o3b2o$o3bo3bo2bobo5bo$obobo11b3ob3o$obobo!',
'x = 18, y = 21, rule = B3/S23\
3bob2o4b2obo$3b2o2bo2bo2b2o$b2o3bo4bo3b2o$o3b2ob4ob2o3bo$b3obobo2bobob3o$3bob\
obo2bobobo$6bo4bo$7b4o$8b2o2$4b2o6b2o$4bo8bo$5b3o2b3o2$3b4o4b4o$2bo4b4o4bo$3b\
12o2$3b3ob4ob3o$2bo2b8o2bo$2b2o10b2o!',
'x = 21, y = 22, rule = B3/S23\
7b2o$3b2o2b2o2b2o$3b2o2bo2bobo$9b3o$9b2o4$9b3o$8bo3bo$4b2o2bo3bo2b2o$\
4b2o2bo3bo2b2o2$10bo$4bo11bo$3bobo3b3o3bobo$3bob4o3b4obo$2obo13bob2o$\
2ob2o2b2o3b2o2b2ob2o$3bo13bo$3bobo9bobo$4b2o3b3o3b2o!',
'x = 33, y = 26, rule = B3/S23\
7b2o15b2o$8bo15bo$6bo19bo$6b5o11b5o$10bo11bo$4b4o17b4o$4bo2bo17bo2bo$\
21bo$21bo$9bo4b2ob2o2bob2o$8b3o3b2obo6b2o$7bo2b2o6bo$7b3o12bo$22bobo$\
3b2o11b2o4bo2bo2b2o$3bo12b2o5b2o4bo$2obo12b2o11bob2o$ob2ob2o19b2ob2obo\
$5bo21bo$5bobo17bobo$6b2o17b2o$10bo11bo$6b5o11b5o$6bo19bo$8bo15bo$7b2o15b2o!',
'x = 65, y = 65, rule = B3/S23\
27b2o$27bobo$29bo4b2o$25b4ob2o2bo2bo$25bo2bo3bobob2o$28bobobobo$29b2ob\
obo$33bo2$19b2o$20bo8bo$20bobo5b2o$21b2o$35bo$36bo$34b3o2$25bo$25b2o$\
24bobo4b2o22bo$31bo21b3o$32b3o17bo$34bo17b2o2$45bo$46b2o12b2o$45b2o14b\
o$3b2o56bob2o$4bo9b2o37bo5b3o2bo$2bo10bobo37b2o3bo3b2o$2b5o8bo5b2o35b\
2obo$7bo13bo22b2o15bo$4b3o12bobo21bobo12b3o$3bo15b2o22bo13bo$3bob2o35b\
2o5bo8b5o$b2o3bo3b2o37bobo10bo$o2b3o5bo37b2o9bo$2obo56b2o$3bo14b2o$3b\
2o12b2o$19bo2$11b2o17bo$12bo17b3o$9b3o21bo$9bo22b2o4bobo$38b2o$39bo2$\
28b3o$28bo$29bo$42b2o$35b2o5bobo$35bo8bo$44b2o2$31bo$30bobob2o$30bobob\
obo$27b2obobo3bo2bo$27bo2bo2b2ob4o$29b2o4bo$35bobo$36b2o!',
'x = 19, y = 15, rule = B3/S23 \
2o15b2o$obo13bobo$2bo13bo$2b3o9b3o$6bo5bo$2b5o5b5o$2bo4bo3bo4bo$4b4o3b\
5o$3b2o4bo5bobo$7b6o3b2o$6bo4bobo$7b4o2bo$9bo3bob2o$11bobo2bo$10b2ob2o!',
'x = 12, y = 12, rule = B3/S23 2o$o2bo$bobo2$3bobo2$5bobo2$7bob2o2$9bobo$10b2o!',
'x = 18, y = 12, rule = B3/S23 4b2o6b2o$3bobo6bobo$3bo10bo$2obo10bob2o$2obobo2b2o2bobob2o$3bobobo2bob\
obo$3bobobo2bobobo$2obobo2b2o2bobob2o$2obo10bob2o$3bo10bo$3bobo6bobo$4b2o6b2o!',
'x = 16, y = 16, rule = B3/S23 3b2o$3bobo$2bo4bo5bo$3bobob2o2b2ob2o$3bo3bo7bo$12bobo2$3bo7b3o$2b3o7bo\
2$bobo$o7bo3bo$2ob2o2b2obobo$2bo5bo4bo$10bobo$11b2o!',
'x = 27, y = 10, rule = B3/S23\
2o25b$bo25b$bobo13b3o7b$2b2o3bo8bo3bo6b$6bob2o6bo4bo5b$5bo4bo6b2obo6b$6bo3bo8bo3b2o2b$7b3o13bobob$25bob$25b2o!',
'x = 49, y = 31, rule = B3/S23\
22b2o7bo$23bo8bo2bo$23bobo4bo4bo4b2o$24b2o13bo2bo$29bo8b2ob2o$28b2ob2o\
8bo$28bo2bo13b2o$29b2o4bo4bo4bobo$35bo2bo8bo$39bo7b2o4$23bo8b2o$16bo5b\
2o7bobo$15bobo3bo10bo$15b2o5bobo$22bobo2$19b2o$2o16bo2bo$bo16b2obo$bob\
o4b3o5bo2b2o$2b2o4bobo4bo$7bo3bo3bo3bo$7bo3bo3bo3bo$11bo4bobo4b2o$6b2o\
2bo5b3o4bobo$5bob2o16bo$5bo2bo16b2o$6b2o!',
'x = 33, y = 23, rule = B3/S23\
12b2o5b2o12b$7b2o3bo7bo3b2o7b$8bo4bo5bo4bo8b$5b2obob3obo3bob3obob2o5b$\
8bobo3bo3bo3bobo8b$6bobo5bobobo5bobo6b$7bobo2b2obobob2o2bobo7b$8bo3bo\
2bobo2bo3bo8b$4b2o8b2ob2o8b2o4b$2o2bo23bo2b2o$obobo4bo13bo4bobobo$2bob\
2o3b2o11b2o3b2obo2b$obobo4bo13bo4bobobo$2o2bo23bo2b2o$4b2o8b2ob2o8b2o\
4b$8bo3bo2bobo2bo3bo8b$7bobo2b2obobob2o2bobo7b$6bobo5bobobo5bobo6b$8bo\
bo3bo3bo3bobo8b$5b2obob3obo3bob3obob2o5b$8bo4bo5bo4bo8b$7b2o3bo7bo3b2o\
7b$12b2o5b2o!',
'x = 21, y = 54, rule = B3/S23\
3bob2o4b2obo$3b2o2bo2bo2b2o$b2o3bo4bo3b2o$o3b2ob4ob2o3bo$b3obobo2bobo\
b3o$3bobob4obobo$5bo2b2o2bo$6b2o2b2o3$4b2o6b2o$4bobo4bobo$5b2o4b2o$8b\
2o$3b5o2b5o$2bo12bo$3b3o6b3o$6bo4bo$3b3ob4ob3o$2bo2bo6bo2bobo$2b2o10b\
2ob3o$6bo8bo4bo$10bo3bo2b3o$14bo2bo4$10b3o$10bo$10bo$14b2obo$8b2o4b2o\
b3o$6bo4bo8bo$2b2o10b2ob3o$2bo2bo6bo2bobo$3b3ob4ob3o$6bo4bo$3b3o6b3o$\
2bo12bo$3b5o2b5o$8b2o$5b2o4b2o$4bobo4bobo$4b2o6b2o3$6b2o2b2o$5bo2b2o2b\
o$3bobob4obobo$b3obobo2bobob3o$o3b2ob4ob2o3bo$b2o3bo4bo3b2o$3b2o2bo2bo2b2o$3bob2o4b2obo!']
def spacing(period): #both for horizontal and vertical spacing
if period == 1:
return 3
elif 2 <= period <= 9:
return 5
else:
return 7
def create_column(pattern_dict):
global grid
pattern_dict_copy = pattern_dict.copy()
for i in pattern_dict_copy:
if i[1]+pattern_dict[i][3] >= period_y:
del pattern_dict[i]
max_y = max(i[1]+pattern_dict[i][3] for i in pattern_dict)
rows = max(i[2] for i in pattern_dict)
while max(i[1]+pattern_dict[i][3]+rows for i in pattern_dict) <= height:
if max(i[1] for i in pattern_dict) < 30:
break #prevent infinite loop on single line
pattern_dict_copy = {}
for i in pattern_dict:
pattern_dict_copy[(i[0],i[1]+i[2], i[2])] = pattern_dict[i] #spaces out patterns vertically
pattern_dict = pattern_dict_copy.copy()
for x1 in range(-len(str(period))*12 - 5 + column_x, 120 + column_x): #negative numbers used for creating the digits
for y1 in range(0, height-1):
grid[(x1,y1)] = 0 #fill everything with off scells
for i in pattern_dict:
grid_form = convert_rle_to_grid(pattern_dict[i][0])
for j in grid_form:
if grid_form.get(j, 0) == 1:
grid[(j[0]+i[0], j[1]+i[1])] = 1 #paste patterns in
def convert_grid_to_rle(grid):
min_x = min(i[0] for i in grid)
min_y = min(i[1] for i in grid)
max_x = max(i[0] for i in grid)
max_y = max(i[1] for i in grid)
to_return = 'x = %s, y = %s, rule = B3/S23\n' % (max_x-min_x+1, max_y-min_y+1) #\n is newline
for j in range(min_y,max_y+1):
while to_return[-1] == 'b': #remove blanks at the end of a line
to_return = to_return[:-1]
to_return += '$'
for i in range(min_x,max_x+1):
to_return += ('o' if grid.get((i,j),0) == 1 else 'b')
while to_return[-1] == 'b': #remove blanks at the end of the last line
to_return = to_return[:-1]
while to_return[-1] == '$': #remove empty lines at the end
to_return = to_return[:-1]
to_return += '!'
while '\n$' in to_return:
to_return = to_return.replace('\n$', '\n')
for i in ('b','o','$'):
for j in ('b','o','$','\n'):
if j != i:
to_return = to_return.replace(j+i+i, j+'2'+i) #bb becomes 2b, but bbbbbbb becomes 2bbbbb, not 2b2b2b
num = 2
while (str(num) + i + i) in to_return:
to_return = to_return.replace(str(num) + i + i,str(num+1) + i) #2bbbb becomes 3bbbb, 3bbbb becomes 4bb, etc.
num += 1
to_return = to_return.replace('B3/S23 $','B3/S23 ') #remove newlines at the beginning
return to_return
def open_file(file, distance):
f = open(file, 'r')
f1 = f.read()
f1 = convert_rle_to_grid(f1)
start_x = 0
while sum(n for n in f1.values()):
found = False
for x in range(start_x,max(i[0] for i in f1)+1):
if found:
break
for y in range(0,max(j[1] for j in f1)+1):
if found:
break
if f1.get((x,y),0) == 1:
pattern_min_x = x
pattern_min_y = y-distance
pattern_max_x = x+distance
pattern_max_y = y+distance
previous = (pattern_min_x, pattern_min_y, pattern_max_x, pattern_max_y)
while True:
for x1 in range(pattern_min_x, pattern_max_x+1):
for y1 in range(pattern_min_y, pattern_max_y+1):
if f1.get((x1,y1),0) == 1:
#pattern_min_x = min(x1-distance, pattern_min_x)
pattern_min_y = min(y1-distance, pattern_min_y)
pattern_max_x = max(x1+distance, pattern_max_x)
pattern_max_y = max(y1+distance, pattern_max_y)
if previous == (pattern_min_x, pattern_min_y, pattern_max_x, pattern_max_y):
found = True
break
previous = (pattern_min_x, pattern_min_y, pattern_max_x, pattern_max_y)
grid = {}
for x in range(pattern_min_x, pattern_max_x-distance+1):
for y in range(pattern_min_y+distance, pattern_max_y-distance+1):
grid[(x,y)] = f1.get((x,y),0)
to_add = convert_grid_to_rle(grid)
if to_add not in digit_rles and to_add not in patterns: #no digits, no duplicates
patterns.append(to_add)
print(len(patterns), end=('\n' if len(patterns) % 10 == 0 else ' '))
for x in range(pattern_min_x, pattern_max_x+1):
for y in range(pattern_min_y, pattern_max_y+1):
f1[(x,y)] = 0
start_x = pattern_min_x
open_file('/Volumes/Golly/golly-4.0.1-mac/Patterns/Life/Oscillators/billiard-table.rle', 3)
open_file('/Volumes/Golly/golly-4.0.1-mac/Patterns/Life/Oscillators/unique-high-period.rle', 5)
open_file('/Volumes/Golly/golly-4.0.1-mac/Patterns/Life/Oscillators/low-period.rle', 3)
open_file('/Volumes/Golly/golly-4.0.1-mac/Patterns/Life/Oscillators/traffic-light-hasslers.rle', 5)
open_file('/Volumes/Golly/golly-4.0.1-mac/Patterns/Life/Oscillators/honey-farm-hasslers.rle', 5)
data = [(0,1234567,0,0,0,0)] #this period 1234567 marks the end of the file
count = 0
for i in patterns:
count += 1
if count % 50 == 0:
print(str(count) + ' done')
data.append(run_pattern(convert_rle_to_grid(i), '*' in i)) #max period 1000 without *, 100000 with *
while None in data: #non-oscillators:
data.remove(None)
#for i in num_dict.values(): #digits from other files
# if eval(i) in data:
# data.remove(eval(i))
data.sort(key=lambda a:(a[1],a[3])) #first by period, then height
grid = {}
column = 1 #column number
column_x = 0 #column x offset
period = 1
period_y = 0 #y value at the beginning of the period
x = 0
y = 0
pattern_dict = {}
pattern_list = [] #pattern_list empties into pattern_dict at the end of each row, column, and period
while len(set(j[1] for j in data)): #this allows repeating periods that couldn't fit due to end of a column
x = column_x
rows = 0
for period in sorted(set(j[1] for j in data)): #lowest periods first; they get deleted as they're completed
if period == 1234567: #end of file
period_y = height + 100 #so that everything will be included
period = max((j[1] * (j[1] != 1234567)) for j in data) #so it doesn't try to place a 7-digit number
create_column(pattern_dict)
data = [] #empties data to complete program
break
period = int(period)
if y < period_y + 28 and y > 0:
y = period_y + 28 #so displayed digits don't conflict
elif y > 0:
y += spacing(period)
period_y = y #becomes the y value at the beginning of the period
period_str = str(period)
for digit in range(len(period_str)): #creates displayed digits
pattern_dict[-12*(len(period_str)-digit)-5+column_x, y, rows] = (eval(num_dict[period_str[digit]]),1,14,8,0,0)
period_patterns = list(filter(lambda a:a[1]==period, data)) #only patterns of the correct period
for pattern in period_patterns:
if x + spacing(period) + pattern[2] >= 120 + column_x or y + pattern[3] + spacing(period) >= height: #end of row or column
if y + pattern[3] + spacing(period) >= height: #end of column
create_column(pattern_dict)
column += 1
column_x += 140 + len(str(period))*12
#130 probably works as long as you don't have two consecutive columns with a 2-digit difference
y = -1 #-1 is used to break out of loop
period_y = 0
pattern_list = []
pattern_dict = {}
rows = 0
break
while x + len(pattern_list) <= 120 + column_x: #end of row
for i in pattern_list:
i[1] += i[2] #i[2] is the pattern number in the row; this spaces the row out to fill the full 120 cells
x += len(pattern_list)
for i in pattern_list:
pattern_dict[(i[1], y+pattern[5], rows)] = i[0] #puts the list into a dict
x = column_x
rows += 1
y += pattern_list[-1][0][3] + spacing(period) #will return an error if a single pattern is more than 120 rows wide
pattern_list = []
pattern_list.append([pattern, x+pattern[4], len(pattern_list)])
x += pattern[2] + spacing(period)
if y == -1: #end of column; beginning of new column
y = 0
break
data = list(filter(lambda a:a[1] > period, data)) #removes a period when it's done
print('Period done: ' + str(period))
while x + len(pattern_list) <= 120 + column_x: #these lines are the same as the end-of-row lines
for i in pattern_list:
i[1] += i[2]
x += len(pattern_list)
for i in pattern_list:
pattern_dict[(i[1], y+pattern[5], rows)] = i[0]
rows += 1
y += pattern_list[-1][0][3] + spacing(period)
pattern_list = []
x = column_x
print(convert_grid_to_rle(grid))
This contains two rows of P5s and P9s and a few of other periods. It probably has bugs with other data sets, though. Note that I set maximum y to 200; this would be a higher number in reality, but I'm showing it as an example.
Edit 1: Fixed a bug that causes an infinite loop when the last column has a single row. Made height a variable instead of typing 200 everywhere. Added a few P12s and P32s, plus some more P5s.
Edit 2: Fixed it going past the height limit.
Edit 3: Fixed the code that shifts the oscillator when it doesn't belong in the top left corner. This is most noticeable with the P138.
Edit 4: Commented the code to make it more readable. Added a few more oscillators.
Edit 5: Major. Includes file paths that you will either need to comment out or change to your own file path, making the number of oscillators 281 without having to write all of them in the code. (I couldn't add any file with high periods because it would see them separately and not as a single oscillator.) More checks to make sure the code to run the pattern doesn't crash (if it dies to nothing) or take a really long time (escaping gliders). Note that all still lifes with 24 or more cells will be rejected.
Edit 6: Three high period files added, with greater checking distance for those files only so that more of the oscillators will be correctly recognized as a single object. Height increased from 250 to 600.