I have written a script that reproduces any SW glider salvo using Extrementhusiast's clock based inserter (or at least I
hope I have).
The primary idea is to sort the gliders by distance to the south-west followed by distance to the north-west. In this lexicographic ordering a glider that it is "greater" than another can always be constructed without obstruction except in a small number of cases.
Specifically, those cases are when two gliders differ by 7 lanes and the back glider is 1, 2, 3 or 4 ticks behind the lead glider and south-east of it.
In those cases I calculate a set of more advanced gliders that need to be made before the back one. I think the code gives a more obvious description than I can:
Code: Select all
import golly as g
def chained_gliders(glider):
timing, lane = glider
return [(timing + i, lane-7) for i in [1, 2, 3, 4]]
def is_chained(glider, fullsalvo):
return any(x in fullsalvo for x in chained_gliders(glider))
def calculate_subsalvo(subsalvo, fullsalvo):
for glider in sorted(subsalvo):
if glider not in fullsalvo:
# glider must have been done ahead of order
continue
if is_chained(glider, fullsalvo):
new_subsalvo = []
t0, l0 = glider
for t1, l1 in fullsalvo:
if l1 < l0 and t0 < t1 <= t0 + 4:
new_subsalvo.append((t1, l1))
for x in calculate_subsalvo(new_subsalvo, fullsalvo):
yield x
fullsalvo.remove(glider)
yield glider
def calculate_salvo(salvo):
for x in calculate_subsalvo(salvo, set(salvo)):
yield x
g_coords = g.transform(g.parse('bo$o$3o!'), 0, -2)
g_coords = zip(g_coords[::2], g_coords[1::2])
def get_salvo():
r = g.getrect()
if not r:
return []
cells = g.getcells(r)
new_cells = g.evolve(cells, 100)
if len(new_cells) != len(cells):
return []
a, b = min(new_cells[::2]), max(new_cells[::2])
c, d = min(new_cells[1::2]), max(new_cells[1::2])
if r != [a+25, c-25, b-a+1, d-c+1]:
return []
ret = []
for i in range(4):
cells_list = zip(cells[::2], cells[1::2])
cells_set = set(cells_list)
for x0, y0 in cells_list:
if all((x0+x, y0+y) in cells_set for (x, y) in g_coords):
ret.append((2 * (y0-x0) - i, x0+y0))
cells = g.evolve(cells, 1)
return ret
clock_turner = g.parse('3bo$3bobo$2bobo$4bo3$2o$2o!', 0, -4)
g_ne = g.parse('3o$o$bo!', -6, -1)
def glider_rewind(gens):
phase = -gens % 4
glider = g.evolve(g_ne, phase)
return g.transform(glider, (gens + phase) / 4, (gens + phase) / 4)
def place_turner(glider, x_coord, width):
timing, lane = glider
g.putcells(g.evolve(clock_turner, timing % 2), x_coord - width, lane - x_coord)
g.putcells(glider_rewind(2 * lane - timing), -width, lane - 2 * x_coord)
r = g.getrect()
if r:
step = r[2] + r[3] + 20
offset = r[0] - step
for glider in calculate_salvo(get_salvo()):
place_turner(glider, offset, r[2] + 20)
offset -= step
It only does anything if it detects that the current pattern is made up solely of non-colliding SW gliders. In that case it places a bunch of NW gliders and clock-turners that (hopefully) reproduce the SW glider salvo but shifted west by some number of cells.
Here it is in action eating Evil Glider Salvo #2 for breakfast with an annoying wing of "chained" gliders added to make things more difficult. It seems to be working well but some proper crash testing is definitely in order.
Code: Select all
x = 13269, y = 26214, rule = B3/S23
13199bo$13194bobo2bobo$13194b2o3b2o$13195bo$13190bobo9bo$13190b2o5bobo
2bobo$13191bo5b2o3b2o$13186bobo9bo$13186b2o5bobo$13187bo5b2o5bobo2bo$
13194bo5b2o3bobo$13183bobo3bobo9bo3b2o$13183b2o4b2o5bobo10bo$13184bo5b
o5b2o11bobo$13197bo6bobo2b2o$13180bobo3bobo3bobo9b2o7bo$13180b2o4b2o4b
2o11bo7bobo$13181bo5bo5bo3bo10bobo2b2o$13196bo4bobo4b2o7bo$13177bobo3b
obo3bobo4b3o2b2o6bo7bobo$13177b2o4b2o4b2o11bo9bobo2b2o$13178bo5bo5bo
14bobo4b2o$13198bo6b2o6bo$13180bobo3bobo3bo3b2o8bo9bobo$13180b2o4b2o4b
obo2b2o10bobo4b2o$13181bo5bo4b2o8bobo4b2o6bo$13202b2o6bo$13183bobo3bo
13bo9bobo$13183b2o4bobo6bobo5bobo4b2o$13184bo4b2o7b2o6b2o6bo$13199bo7b
o$13186bo7bobo5bobo5bobo$13186bobo5b2o6b2o6b2o$13186b2o7bo7bo7bo$
13190bobo5bobo5bobo$13190b2o6b2o6b2o$13191bo7bo7bo$13194bobo5bobo5bo$
13194b2o6b2o6bobo$13195bo7bo6b2o$13198bobo14bo$13198b2o13b2o$13199bo
14b2o$13218bo$13217bo$13217b3o2$13221bobo$13221b2o$13222bo$13225bo$
13225bobo$13225b2o$13230bo$13228b2o$13229b2o$13233bo$13232bo$13232b3o
2$13236bobo$13236b2o$13237bo$13240bo$13240bobo$13240b2o$13245bo$13243b
2o$13244b2o$13248bo$13247bo$13247b3o2$13251bobo$13251b2o$13252bo$
13255bo$13255bobo$13255b2o$13260bo$13258b2o$13259b2o$13263bo$13262bo$
13262b3o2$13266bobo$13266b2o$13267bo132$12867bo$12867bobo$12866bobo$
12868bo3$12864b2o$12864b2o201$12666bo$12666bobo$12665bobo$12667bo3$
12663b2o$12663b2o10$13081b2o$13081bobo$13081bo190$12465bo$12465bobo$
12464bobo$12466bo3$12462b2o$12462b2o201$12264bo$12264bobo$12263bobo$
12265bo3$12261b2o$12261b2o5$13084b2o$13084bobo$13084bo194$12063bo$
12063bobo$12062bobo$12064bo3$12060b2o$12060b2o201$11862bo$11862bobo$
11861bobo$11863bo3$11859b2o$11859b2o2$13087b2o$13087bobo$13087bo150$
11662bo$11660b2o$11662b2o$11661bo3$11658b2o$11658b2o201$11461bo$11459b
2o$11461b2o$11460bo3$11457b2o$11457b2o46$13091b2o$13091bobo$13091bo
153$11260bo$11258b2o$11260b2o$11259bo3$11256b2o$11256b2o203$11059bo$
11057b2o$11059b2o$11058bo3$11055b2o$11055b2o41$13095b2o$13095bobo$
13095bo158$10858bo$10856b2o$10858b2o$10857bo3$10854b2o$10854b2o201$
10657bo$10655b2o$10657b2o$10656bo3$10653b2o$10653b2o38$13099b2o$13099b
obo$13099bo161$10456bo$10454b2o$10456b2o$10455bo3$10452b2o$10452b2o
149$10255bo$10253b2o$10255b2o$10254bo3$10251b2o$10251b2o13$13077bo$
13076b2o$13076bobo186$10054bo$10052b2o$10054b2o$10053bo3$10050b2o$
10050b2o201$9853bo$9851b2o$9853b2o$9852bo3$9849b2o$9849b2o9$13080bo$
13079b2o$13079bobo194$9652bo$9650b2o$9652b2o$9651bo3$9648b2o$9648b2o
201$9451bo$9449b2o$9451b2o$9450bo3$9447b2o$9447b2o$13083bo$13082b2o$
13082bobo198$9250bo$9248b2o$9250b2o$9249bo3$9246b2o$9246b2o201$9049bo$
9047b2o$9049b2o$9048bo3$9045b2o$9045b2o4040bo$13086b2o$13086bobo145$
8848bo$8846b2o$8848b2o$8847bo3$8844b2o$8844b2o201$8647bo$8645b2o$8647b
2o$8646bo3$8643b2o$8643b2o51$13091bo$13090b2o$13090bobo148$8446bo$
8444b2o$8446b2o$8445bo3$8442b2o$8442b2o201$8244bo$8244bobo$8243bobo$
8245bo3$8241b2o$8241b2o48$13095bo$13094b2o$13094bobo157$8044bo$8042b2o
$8044b2o$8043bo3$8040b2o$8040b2o201$7843bo$7841b2o$7843b2o$7842bo3$
7839b2o$7839b2o39$13099bo$13098b2o$13098bobo160$7642bo$7640b2o$7642b2o
$7641bo3$7638b2o$7638b2o162$13073bo$13072b2o$13072bobo8$7441bo$7439b2o
$7441b2o$7440bo3$7437b2o$7437b2o169$7240bo$7238b2o$7240b2o$7239bo3$
7236b2o$7236b2o201$7039bo$7037b2o$7039b2o$7038bo3$7035b2o$7035b2o11$
13076bo$13075b2o$13075bobo188$6838bo$6836b2o$6838b2o$6837bo3$6834b2o$
6834b2o212$6637bo$6635b2o$6637b2o$6636bo6442bo$13078b2o$13078bobo$
6633b2o$6633b2o201$6436bo$6434b2o$6436b2o$6435bo3$6432b2o$6432b2o201$
6235bo$6233b2o$6235b2o$6234bo2$13084bo$6231b2o6850b2o$6231b2o6850bobo
201$6033bo$6033bobo$6032bobo$6034bo3$6030b2o$6030b2o201$5833bo$5831b2o
$5833b2o7253bo$5832bo7254b2o$13087bobo2$5829b2o$5829b2o201$5631bo$
5631bobo$5630bobo$5632bo3$5628b2o$5628b2o200$13092bo$5431bo7659b2o$
5429b2o7660bobo$5431b2o$5430bo3$5427b2o$5427b2o201$5229bo$5229bobo$
5228bobo$5230bo3$5226b2o$5226b2o197$13096bo$13095b2o$13095bobo2$5029bo
$5027b2o$5029b2o$5028bo3$5025b2o$5025b2o201$4827bo$4827bobo$4826bobo$
4828bo3$4824b2o$4824b2o109$13069bo$13068b2o$13068bobo90$4627bo$4625b2o
$4627b2o$4626bo3$4623b2o$4623b2o201$4425bo$4425bobo$4424bobo$4426bo3$
4422b2o$4422b2o105$13072bo$13071b2o$13071bobo94$4225bo$4223b2o$4225b2o
$4224bo3$4221b2o$4221b2o201$4023bo$4023bobo$4022bobo$4024bo3$4020b2o$
4020b2o101$13075bo$13074b2o$13074bobo98$3823bo$3821b2o$3823b2o$3822bo
3$3819b2o$3819b2o201$3621bo$3621bobo$3620bobo$3622bo3$3618b2o$3618b2o
99$13078b3o$13078bo$13079bo100$3421bo$3419b2o$3421b2o$3420bo3$3417b2o$
3417b2o201$3219bo$3219bobo$3218bobo$3220bo3$3216b2o$3216b2o103$13085bo
$13084b2o$13084bobo96$3019bo$3017b2o$3019b2o$3018bo3$3015b2o$3015b2o
57$2817bo$2817bobo$2816bobo$2818bo3$2814b2o$2814b2o174$2617bo$2615b2o$
2617b2o$2616bo3$2613b2o$2613b2o63$13089bo$13088b2o$13088bobo136$2416bo
$2414b2o$2416b2o$2415bo3$2412b2o$2412b2o201$2215bo$2213b2o$2215b2o$
2214bo3$2211b2o$2211b2o60$13093bo$13092b2o$13092bobo148$2014bo$2012b2o
$2014b2o$2013bo3$2010b2o$2010b2o201$1813bo$1811b2o$1813b2o$1812bo3$
1809b2o$1809b2o2$13079b2o$13078b2o$13080bo197$1612bo$1610b2o$1612b2o$
1611bo3$1608b2o$1608b2o157$13066bo$13065b2o$13065bobo12$1410bo$1410bob
o$1409bobo$1411bo3$1407b2o$1407b2o174$1210bo$1208b2o$1210b2o$1209bo3$
1206b2o$1206b2o201$1009bo$1007b2o$1009b2o$1008bo3$1005b2o$1005b2o2$
13069bo$13068b2o$13068bobo197$808bo$806b2o$808b2o$807bo3$804b2o$804b2o
201$606bo$606bobo$605bobo$607bo2$13072bo$603b2o12466b2o$603b2o12466bob
o201$406bo$404b2o$406b2o$405bo3$402b2o$402b2o201$205bo$203b2o$205b2o$
204bo3$201b2o$201b2o11$13081bo$13080b2o$13080bobo188$4bo$2b2o$4b2o$3bo
3$2o$2o216$13085bo$13084b2o$13084bobo411$13089bo$13088b2o$13088bobo
411$13092b2o$13092bobo$13092bo411$13096b2o$13095b2o$13097bo411$13099b
3o$13099bo$13100bo410$13104bo$13103b2o$13103bobo411$13107b2o$13107bobo
$13107bo411$13111b2o$13110b2o$13112bo411$13114b3o$13114bo$13115bo410$
13119bo$13118b2o$13118bobo411$13122b2o$13122bobo$13122bo411$13126b2o$
13125b2o$13127bo411$13129b3o$13129bo$13130bo410$13134bo$13133b2o$
13133bobo411$13137b2o$13137bobo$13137bo411$13141b2o$13140b2o$13142bo
411$13144b3o$13144bo$13145bo410$13149bo$13148b2o$13148bobo189$13074b2o
$13074bobo$13074bo368$13063bo$13062b2o$13062bobo410$13066bo$13065b2o$
13065bobo410$13069bo$13068b2o$13068bobo424$13077bo$13076b2o$13076bobo
411$13081bo$13080b2o$13080bobo411$13085bo$13084b2o$13084bobo364$13071b
2o$13071bobo$13071bo368$13060bo$13059b2o$13059bobo410$13063bo$13062b2o
$13062bobo410$13066bo$13065b2o$13065bobo410$13068b2o$13068bobo$13068bo
411$13073bo$13072b2o$13072bobo411$13077bo$13076b2o$13076bobo411$13081b
o$13080b2o$13080bobo!
EDIT: here is an updated version of the script. When it finds a chained glider it advances the front by the minimum amount possible instead of always by 4 ticks. I think both approaches work but this way is more in the spirit of the intended algorithm. Also I made the placement of turners more compact by advancing by diagonally rather than by x-coordinate. The small step size of 23 is a new source of potential bugs but I think it should work properly.
Code: Select all
import golly as g
def max_chained(glider, fullsalvo):
timing, lane = glider
for t in [4, 3, 2, 1]:
if (timing + t, lane - 7) in fullsalvo:
return t
return 0
def calculate_subsalvo(subsalvo, fullsalvo):
for glider in sorted(subsalvo):
if glider not in fullsalvo:
# glider must have been done ahead of order
continue
chained = max_chained(glider, fullsalvo)
if chained:
new_subsalvo = []
t0, l0 = glider
for t1, l1 in fullsalvo:
if l1 < l0 and t0 < t1 <= t0 + chained:
new_subsalvo.append((t1, l1))
for x in calculate_subsalvo(new_subsalvo, fullsalvo):
yield x
fullsalvo.remove(glider)
yield glider
def calculate_salvo(salvo):
return [x for x in calculate_subsalvo(salvo, set(salvo))]
g_coords = g.transform(g.parse('bo$o$3o!'), 0, -2)
g_coords = zip(g_coords[::2], g_coords[1::2])
def get_salvo():
r = g.getrect()
if not r:
return []
cells = g.getcells(r)
new_cells = g.evolve(cells, 100)
if len(new_cells) != len(cells):
return []
a, b = min(new_cells[::2]), max(new_cells[::2])
c, d = min(new_cells[1::2]), max(new_cells[1::2])
if r != [a+25, c-25, b-a+1, d-c+1]:
return []
ret = []
for i in range(4):
cells_list = zip(cells[::2], cells[1::2])
cells_set = set(cells_list)
for x0, y0 in cells_list:
if all((x0+x, y0+y) in cells_set for (x, y) in g_coords):
ret.append((2 * (y0-x0) - i, x0+y0))
cells = g.evolve(cells, 1)
return ret
clock_turner = g.parse('3bo$3bobo$2bobo$4bo3$2o$2o!', 0, -4)
g_ne = g.parse('3o$o$bo!', -6, -1)
def glider_rewind(gens):
phase = -gens % 4
glider = g.evolve(g_ne, phase)
return g.transform(glider, (gens + phase) / 4, (gens + phase) / 4)
def place_turner(glider, sw_lane, width):
timing, lane = glider
z = (lane + width - sw_lane) // 2
g.putcells(g.evolve(clock_turner, timing % 2), z - width, lane - z)
g.putcells(glider_rewind(2 * lane - timing), -width, lane - 2 * z)
r = g.getrect()
if r:
step = 23
sw_lane = r[1] + r[3] - r[0] + 4 * step
width = r[2] + 20
for glider in calculate_salvo(get_salvo()):
place_turner(glider, sw_lane, width)
sw_lane += step