dvgrn wrote: March 12th, 2020, 11:04 am
Goldtiger997 wrote: March 12th, 2020, 10:02 amTo place the edgeshooters I used an edgeshooter placing script that I made which I will post soon once I make it more user-friendly.
Looking forward to it!
Here's the script (
Edit on 14/08/2022: replaced the glider detection with a better method, and did a little bit of cleanup):
Code: Select all
# place-edgeshooters-automatic.py
# Goldtiger997 February 2020
# Improved August 2022
import golly as g
gap_size = int(g.getstring("Please enter the diagonal spacing between the edgeshooters","50"))
flip_mode = int(g.getstring("Which mode?\n\n1) gliders are preferred to inserted from alternating sides\n2) gliders are preferred to be inserted all from the same side","1"))
safe_space = int(g.getstring("How much additional spacing do you want between the gliders and the edgeshooters? Increase this parameter if the script places gliders too close to the edgeshooters","300"))
edgeshooter_preference = g.getstring("Please enter your order of preference of the following four edgshooter types by entering the numbers that correspond to those edgeshooters in order of preference (most preferred to least preferred) separated by commas.\n Omit a number if you wish the corresponding edgeshooter to be banned\n\n1: NW31\n2: BNE14T30\n3: RNE-19T84\n4: SW47T214\n5: Fx119\n\nFor example the input '1,5,2' would indicate that NW31 edgeshooters are most preferred, Fx199s are second-most preferred, BNE14T30s are least preferred and the others are outright banned from being used.\n\nAlternatively just enter 'n' for the default settings (equivalent to '1,2,3,4')","n").split(",")
sel_desc = g.getselrect()
selection = g.getcells(g.getselrect())
glider_phases = [g.parse("3o$2bo$bo!"),g.parse("bo$b2o$obo!"),g.parse("b2o$obo$2bo!"),g.parse("2o$b2o$o!")]
gliders = []
gliders_sorted = []
gliders_lanes = []
the_numbers = ["1","2","3","4","5"] #full list ["1","2","3","4","5","6","7","8","9","0"]
#edgeshooters
#format is [rle, output glider lane adjustment, input glider lane adjustment, input glider positioning adjustment,delay of edgeshooter,flip_adjust,flip_time_adjust]
edgeshooter1 = [g.parse("18bb$17b2b$16b3b$15b4b$14b4b$13b4b$12b4b$11b4b$10b4b$9b4b$8b4b$8b4b$7b5b$4b9b$4b9b$4b9b$4b10b$3b12b$2b13b8b2o$3b11b9bo$4b12b4bbobo$4b15bbb2o13b2o$4b17b14bb2ob$4b17b15b2b$bbb17b17b2b3bb$2o19b15b4bbb2o$2obb19b11b8b2o$bb4b20b2b2b2b6b2obbb$6b32b2o$6b9bb24b$7b7b2b28b$7b7b2b28b$7b6b4b26b2o$7b7b10b4bb14b2o$7b6b12b4b2b11bbb$6b7b13b4b2b10b$7b6b14b14b$8b5b15b14b$8b6b14b13b$10b4b14b13b$9bb2o2b2b2ob2o2b2o3b8bb4b$10b2o5bobo2bobo3b8b$17bo2b2obb4b8b$18bobo2b2b3b10b$17b2obobbo2bb7b2b2o$20bobobo9b2bo$17b4o2bob8b4b3o$17bo3b2o3b7b6bo$19bobb6b6b$18b2ob2ob3b7b$21b2obb8b$18b2o3b10b$18bo4b6b2o3b$19bo3b6b2o2b5b2o$18b2o3b10b5bo$22b11b2bbobo$22b12bbb2o$21b15b$20b16b$17b2bb16b$16b2o18b$16b2obb17b$17bbb4bb8b2b4b$24b7b4b4b$25b6b5b4b$27b4b6b4b$29b3bo5b4b$30bbobo5b3b$31bobo6b2b$32bo8bb$33b3o$35bo!"),20,0,27,745,19,-100]
edgeshooter2 = [g.parse("22b4b$21b4b$20b4b$19b4b$18b4b5b2o$17b6b3bo2bo$16b8bbbbobo$16b10b2o2b2o$15b11b2b2o2bo$15b11b2o3b2o$15b10b2bo$15b9b2bo$10b14b3b3o$9b13b7bo$9b14b$9b14b$9b13b$10b11b$9b14b$9b2b2o11b$10bb2o11b$10b14b$10b4bb8b$11b2bb9b3b2o$14b8b3bobo$14b8b3bo$14b9bb2o$13b11b$12b12b$12b12b$5b2o6b10b$6bo7b11b$6bobobb14b$7b2obb13b2o$9b15b2o$8b15bbb$9b14b$7b2obb11b$6bobob3b9b$6bo8b8b$5b2o9b7b$13b11b$12b12b$12b12b$12b11b$2ob2o2b2o3b8bb4b$bobo2bobo3b7b4b2o$bo2b2obb4b7b4bo$2bobo2b2bbbb6b6b3o$b2obobbo10b8bo$4bobobo9b$b4o2bob8b$bo3b2o4b6b$3bobb6b6b$2b2ob2ob3b7b$5b2obb8b$2b2o3b10b$2bo4b6b2o3b$3bo3b6b2o2b5b2o$2b2o3b10b5bo$6b11b2bbobo$6b12bbb2o$5b15b$4b16b$b2bb16b$2o18b$2obb17b$bbb4bb8b2b4b$8b7b4b4b$9b6b5b4b$11b4b6b4b$13b3bo5b4b$14bbobo5b4b$15bobo$16bo$17b3o$19bo!"),24,12,48,783,23,-184]
edgeshooter3 = [g.parse("18b4b$17b4b$16b4b$15b4b$14b6b7b2o$13b7b7bo$13b9b2bbobo$9bb2b11bbb2o$9b2bb9bo3b$9b3bb7bobo2b$9b11bobo2b$10b4bbb2b3bo3b$11b4b4b6b$12b4b4b6b$13b4b3b6b$14b4b2b5b$15b14b$16b14b$17b13b$10b2o5b13b$11bo5b11bbb2o$11bobob2b10b2bbobo$12b2obb9b7bo$14b11b7b2o$14b13b$14b9bbb2obo$15b7b2bb2ob3o$14b8b4bb4bo$15b8b2b2ob3o$16b7b3bobo$13b11b2bobo$12b11b4bo$12b11b$12b11b$2ob2o2b2o3b8b2bb2o$bobo2bobo3b7b3bbobo$bo2b2obb4b7b6bo$2bobo2b2b3b6b7b2o$b2obobbob2b7b$4bobobo2b7b$b4o2bo4b5b$bo3b2o4b6b$3bobb6b6b$2b2ob2ob3b7b$5b2obb8b$2b2o3b10b$2bo4b6b2o3b$3bo3b6b2o2b5b2o$2b2o3b10b5bo$6b11b2bbobo$6b12bbb2o$5b15b$4b16b$b2bb16b$2o18b$2obb17b$bbb4bb8b2b4b$8b7b4b4b$9b6b5b4b$11b4b6b4b$13b3bo5b4b$14bbobo5b4b$15bobo6b4b$16bo8b4b$17b3o6b4b$19bo7b4b$28b4b!"),20,4,37,758,19,-140]
edgeshooter4 = [g.parse("17b4b$16b4b$15b4b$14b4b$13b4b$12b4b$11b4b$10b4b$9b7b$9b9b$8b11b$5b13b$4b14b$3b16b$3b17b$2b18b$2b19b$b20b19bo$20b20b3o$b21b21bo$b21b20b2o$3b19b20bb8bo$2bbb17b19b3b6b3o$4b18b16b6b4bo$4b20b11b10b3b2o$5b22b2b2b3b16b$5b34b2o7b$7b32b2o9b$8b42b$8b42b$8b44b$8b13b4b4bb13bb9b$8b6b4b3b5b3b5bbb19b$7b7b5b4b4b4b12b14b$8b6b7b2o6b2o11b15b$9b6b6bo7bo12b14b$9b6b7b3o5b3o9b13b$8b8b8bo7bo6b15b$9b6b17bobob2b15b$8b7b18b2obb17b$6b11b18b19b$4b9b2o2bbb15b19b$4b9b2o3b2o15b20b2b2o$4b14b2o13b2obb16b2obobo$5b14b13bobob2b13bbb2obo$5b3bb2b2bb2b5b11bo6b11b4bb2bo$5b2o5b3b4b2o10b2o7b11b2b2ob2o$6bo5bb2ob3bo17b14b3bobo$3b3o7b2o5b3o13b16b2bobo$3bo18bo4b2o7b13bbb2ob2o$26bo2bo2b2o2b13bbbobo$27b2o2bobo2b8bb2b6bo$29b2obb3b7b10b2o$29bo2b2b2b7b$26b2obobbo2bb6b$26bob2obobo8b$30bobob8b$27b2o2bo2b7b$25b3ob2o4b6b$24bo4bb6b6b$25b3ob2ob3b7b$27bob2obb8b$31b10b$31b6b2o3b$31b6b2o2b5b2o$31b10b5bo$30b11b2bbobo$30b12bbb2o$29b15b$28b16b$25b2bb16b$24b2o18b$24b2obb17b$25bbb4bb8b2b4b$32b7b4b4b$33b6b5b4b$35b4b6b4b$37b3bo5b4b$38bbobo5b4b$39bobo6b4b$40bo8b3b$41b3o6bb$43bo!"),19,0,30,831,18,-112]
edgeshooter5 = [g.parse("14b2o$14bo$12bobo$12b2o$8bo$7bobo15bo$7bobo13b3o$8bo13bo$22b2o23b2o$47b2o$18b2o12b2o$18b2o11bo2bo$31b2obo$28b2obo2bob2o$28bo2bobo2b2o$2o28b2ob2o$2o5$24b2o13b2o$24b2o13b2o$54b2o$53bo2bo$54b2obo$57bo$57b2o$42b2o$43bo$40b3o$40bo$3b2o$2bobo$2bo$b2o12b2obo$15b2ob3o$21bo$15b2ob3o$13bo2bobo$13b2o!"),3,-39,-21,781,2,92]
edgeshooters_unordered = [edgeshooter1,edgeshooter2,edgeshooter3,edgeshooter5,edgeshooter4]
#order edgeshooters according to preferences
if edgeshooter_preference[0] == "n":
edgeshooters = edgeshooters_unordered
else:
edgeshooters = []
for i in edgeshooter_preference:
try:
edgeshooters.append(edgeshooters_unordered[(int(i)-1)%5])
except ValueError:
g.note("Your edgeshooter preferences cannot be understood so the default preferences will be used")
edgeshooters = edgeshooters_unordered
break
if g.getrule() != "B3/S23":
g.warn("Please change the rule to life.")
g.exit()
elif g.getselrect() == []:
g.warn("Please select some northeast-heading gliders")
g.exit()
all_cells = g.getcells(g.getselrect())
all_cells = list(zip(all_cells[::2], all_cells[1::2]))
g.shrink()
gliders = []
glider_ne = g.parse('3o$2bo$bo!', -2, 0)
for phase in range(4):
cells = g.evolve(glider_ne, phase)
cells = list(zip(cells[::2], cells[1::2]))
for x, y in all_cells:
if all(g.getcell(x+dx, y+dy) for dx, dy in cells):
gliders.append((y + x, -4 * x - phase))
if len(gliders) == 0:
g.warn("Your selection has no (detectable) gliders")
g.exit()
gliders_sorted = sorted(gliders, key = lambda x: x[0])[::-1]
last_selected_glider = 0
completed_gliders = []
for i in gliders:
completed_gliders.append(False)
g.putcells(selection,-safe_space - gap_size*len(gliders),safe_space + gap_size*len(gliders),1,0,0,1,"or")
g.update()
edgeshooter_gap = 150
edgeshooters_placed_count = 0
edgeshooter_storage = [] #to facilitate deletion
def place_edgeshooter(num,gap,count):
a = gliders_sorted[last_selected_glider%len(gliders)][0]
b = gliders_sorted[last_selected_glider%len(gliders)][1]
if flipped%2 == 0:
edge_x = -gap - edgeshooters[num][1] + edgeshooters[num][2] + sel_desc[0]
edge_y = a + gap - edgeshooters[num][2] - sel_desc[0]
g.putcells(edgeshooters[num][0],edge_x,edge_y,1,0,0,1,"or")
delay = edgeshooters[num][4] - b - 4*safe_space - 4*sel_desc[0]
x = edge_x - delay//4 + gap_size*(len(gliders) - count)
y = edge_y + edgeshooters[num][3] - delay//4 + gap_size*(len(gliders) - count)
g.putcells(g.evolve(g.parse("$b3o$bo$2bo!"),delay%4),x-1,y-1,1,0,0,1,"copy")
else:
edge_x = -gap - edgeshooters[num][1] + edgeshooters[num][2] + edgeshooters[num][5] + sel_desc[0]
edge_y = a + gap - edgeshooters[num][2] + edgeshooters[num][5] + 1 - sel_desc[0]
g.putcells(edgeshooters[num][0],edge_x,edge_y,0,-1,-1,0,"or")
delay = edgeshooters[num][4] - b + edgeshooters[num][6] - 4*safe_space - 4*sel_desc[0]
x = edge_x + delay//4 - gap_size*(len(gliders) + count) + 1 + 2*gap_size*count
y = edge_y + edgeshooters[num][3] + delay//4 - gap_size*(len(gliders) + count) + 2*gap_size*count
g.putcells(g.evolve(g.parse("$b3o$bo$2bo!"),delay%4),x-1,y-1,-1,0,0,-1,"copy")
#remove the comparison glider
dumb_fix = 0 if b%4 == 0 else 1
g.putcells(g.evolve(glider_ne,(-b)%4),-(b//4)-dumb_fix - safe_space - gap_size*len(gliders),a+(b//4)+dumb_fix + safe_space + gap_size*len(gliders),1,0,0,1,"xor")
edgeshooter_storage.append([edge_x,edge_y,x,y,num,last_selected_glider%len(gliders),flipped%2])
def remove_edgeshooter(e):
g.putcells(edgeshooters[e[4]][0],e[0],e[1],1-e[6],-e[6],-e[6],1-e[6],"xor")
g.putcells(g.parse("4o$4o$4o$4o!"),e[2]-1-e[6]*3,e[3]-1-e[6]*3,1,0,0,1,"not")
completed_gliders[e[5]] = False
a = gliders_sorted[last_selected_glider%len(gliders)][0]
b = gliders_sorted[last_selected_glider%len(gliders)][1]
dumb_fix = 0 if b%4 == 0 else 1
g.putcells(g.evolve(glider_ne,(-b)%4),-(b//4)-dumb_fix - safe_space - gap_size*len(gliders),a+(b//4)+dumb_fix + safe_space + gap_size*len(gliders),1,0,0,1,"or")
edgeshooter_storage.pop()
flipped = 0
prev_flipped = 1
no_successes_count = -1
i = 0
while edgeshooters_placed_count < len(gliders):
if flip_mode == 2 or prev_flipped == 1:
a = 1
else:
a = -1
last_selected_glider = (a*i)%len(gliders)
g.show(str(edgeshooters_placed_count) + " gliders done. " + str(len(gliders)-edgeshooters_placed_count) + " gliders remain.")
if completed_gliders[(a*i)%len(gliders)] != True:
for x in range(0,len(edgeshooters)):
place_edgeshooter(x%4,edgeshooter_gap,edgeshooters_placed_count)
edgeshooters_placed_count += 1
edgeshooter_gap += gap_size
g.run(4*safe_space + 4*gap_size*len(gliders))
if g.getcells(sel_desc) == selection:
g.reset()
completed_gliders[last_selected_glider%len(gliders)] = True
prev_flipped = flipped
flipped = (flip_mode - flipped)%2
no_successes_count = -1
g.update()
break
else:
g.reset()
remove_edgeshooter(edgeshooter_storage[-1])
edgeshooters_placed_count -= 1
edgeshooter_gap -= gap_size
no_successes_count += 1
i += 1
if no_successes_count == (len(gliders)-edgeshooters_placed_count) and edgeshooters_placed_count != len(gliders):
flipped = (prev_flipped)%2
elif no_successes_count > 2*(len(gliders)-edgeshooters_placed_count) and edgeshooters_placed_count != len(gliders):
g.warn("No method of inserting the remaining gliders could be found")
g.exit("")
g.show("Success!")
To use the script select some northeast-heading gliders and run the script. The script will ask you several questions at the start all of which should be sufficiently explained in the diaolog boxes I think. For most purposes you can just use the default answers anyway. The script will then attempt to insert the all the gliders in the salvo with the four edgeshooters it knows of from both sides of the salvo. To do this the script sorts the gliders by how "easy to insert" they look and then loops through the list of sorted gliders trying all four edgeshooters on each glider until it finds an edgeshooter that works. It then repeats this process with the remaining gliders until all gliders have edgeshooters that insert them or it can't find any way of inserting any of the remaining gliders.
Even though the script doesn't have powerful glider inserters like the clock inserter it seems to work for the majority of salvoes (e.g. it worked on all four of the spider's salvoes). For the salvoes that cannot be done with this script (e.g. two gliders 14-ticks apart) I think a decent approach is to use my script to solve all the "easy" gliders and then use
chris_c's script to solve the hard remaining ones. I'm also pretty confident that the script should find a solution with its 4 edgshooters if such a solution does exist since its edgeshooter test method involves testing whether all the gliders can make it to the required final location after the edgeshooter is placed (a feature which chris_c's script didn't have).
For example, paste the following salvo anywhere in the Golly grid with rule set to Life:
Code: Select all
x = 34, y = 59, rule = B3/S23
25b3o$27bo$26bo$14b3o$16bo$15bo$19bo$19b2o$18bobo10b3o$33bo$32bo2$7b2o
$6bobo6b2o$8bo7b2o$15bo8bo$24b2o$23bobo2$b2o$2b2o7b2o$bo10b2o$11bo2$b
2o$obo$2bo4$11bo$11b2o$10bobo3$2b2o$bobo$3bo19$17b3o$19bo$18bo!
Run the script with default settings and after about 20 seconds the following result should be produced:
Code: Select all
x = 1381, y = 1325, rule = B3/S23
7bo$5bobo$6b2o203$5bobo$6b2o$6bo183$888b3o$890bo$889bo$877b3o$879bo$
878bo$882bo$882b2o$881bobo10b3o$896bo$895bo2$870b2o$869bobo6b2o$871bo
7b2o$11bobo864bo8bo$12b2o873b2o$12bo873bobo2$864b2o$865b2o7b2o$864bo
10b2o$874bo2$864b2o$863bobo$865bo4$874bo$874b2o$873bobo3$865b2o$864bob
o$866bo19$880b3o$882bo$881bo123$621b2o$618b2o2bo$616b3ob2o$615bo$612bo
2b4ob2o$612b3o3bob2o$615bo$614b2o26b2o$642bo$640bobo$640b2o$600bo$598b
3o$597bo$597b2o$582b2o60b2o$583bo60bobo$583bob2o59bo$584bo2bo49b2o7b2o
$obo582b2o50b2o$b2o597b2o$bo598b2o3$620b2o3b2o$609bo3b2o6bo3bo$608bobo
3bo3b3o5b3o$607bobo3bo4bo9bo$603b2obobo3bo15bobo$603b2obo2b4obo14b2o$
607bobo3bobo$603b2ob2o2bo2bobo$604bobo2b2o3bo$592b2o10bobo$592b2o11bo
21b2o$628bo$615b2o11bobo$616bo12b2o$616bobo$617b2o2b2o$621b2o4$616b2o
4b2o$616b2o4b2o7$617b2o$616bobo$616bo$615b2o5$718b2o$718bo$716bobo$
716b2o13b2o$731b2o3$695b2o40b2o$695b2o40b2o$733b2o$733b2o4$738b2o$738b
2o7$705b2o4b2ob2o2b2o$705b2o5bobo2bobo$712bo2b2o$713bobo$712b2obo2bo
12b2o$715bobobo11bo$712b4o2bo13b3o$712bo3b2o16bo$714bo$713b2ob2o$716b
2o$713b2o$713bo10b2o$714bo9b2o7b2o$713b2o18bo$731bobo$731b2o4$711b2o$
711b2o2$521b2o$518b2o2bo$516b3ob2o$515bo211bo$512bo2b4ob2o204bobo$512b
3o3bob2o204bobo$515bo211bo$514b2o26b2o184b3o$542bo187bo$540bobo$540b2o
$500bo$498b3o$497bo$497b2o$482b2o60b2o$483bo60bobo$483bob2o59bo$484bo
2bo49b2o7b2o88bo$485b2o50b2o97b3o$500b2o137bo$500b2o136b2o$647bo$645b
3o$520b2o3b2o117bo$509bo3b2o6bo3bo118b2o$508bobo3bo3b3o5b3o$507bobo3bo
4bo9bo106b2o$503b2obobo3bo15bobo104b2o$503b2obo2b4obo14b2o$507bobo3bob
o$503b2ob2o2bo2bobo$504bobo2b2o3bo$492b2o10bobo$492b2o11bo21b2o$528bo
88b2o6b2o$515b2o11bobo86bo7bo$516bo12b2o87b3o5b3o$516bobo101bo7bo$517b
2o2b2o105bobo$521b2o106b2o2$609b2o$609b2o3b2o37b2o$516b2o4b2o90b2o13b
2o18b2obobo$516b2o4b2o104bobo18b2obo$628bo24bo$601b2o12b2o10b2o20b2ob
2o$602bo6b2o4bo34bobo$599b3o7b2o5b3o31bobo$599bo18bo4b2o22b2ob2o$622bo
2bo2b2o17bobo$517b2o104b2o2bobo19bo$516bobo106b2o22b2o$516bo108bo$515b
2o105b2obo2bo$622bob2obobo$626bobo$623b2o2bo$621b3ob2o$620bo$621b3ob2o
$623bob2o2$633b2o$633b2o7b2o$642bo$640bobo$640b2o4$620b2o$620b2o5$636b
o$635bobo$635bobo$636bo$637b3o$639bo11$421b2o$418b2o2bo$416b3ob2o$415b
o$412bo2b4ob2o$412b3o3bob2o$415bo$414b2o26b2o$442bo$440bobo$440b2o$
400bo$398b3o$397bo$397b2o$382b2o60b2o$383bo60bobo$383bob2o59bo$384bo2b
o49b2o7b2o$385b2o50b2o$400b2o$400b2o3$420b2o3b2o$409bo3b2o6bo3bo$408bo
bo3bo3b3o5b3o$407bobo3bo4bo9bo$403b2obobo3bo15bobo$403b2obo2b4obo14b2o
87b2o$407bobo3bobo102bo$403b2ob2o2bo2bobo100bobo$404bobo2b2o3bo101b2o
13b2o$392b2o10bobo124b2o$392b2o11bo21b2o$428bo$415b2o11bobo64b2o40b2o$
416bo12b2o64b2o40b2o$416bobo114b2o$417b2o2b2o110b2o$421b2o3$538b2o$
416b2o4b2o114b2o$416b2o4b2o6$505b2o4b2ob2o2b2o$21bo395b2o86b2o5bobo2bo
bo$19bobo394bobo93bo2b2o$20b2o394bo96bobo$415b2o95b2obo2bo12b2o$515bob
obo11bo$512b4o2bo13b3o$512bo3b2o16bo$514bo$513b2ob2o$516b2o$513b2o$
513bo10b2o$514bo9b2o7b2o$513b2o18bo$531bobo$531b2o4$511b2o$511b2o5$
527bo$526bobo$526bobo$527bo$528b3o$530bo31$331b2o$331b2o5b2o$338b2o3$
311bo5b2o17b2o98bo$309b3o6bo17b2o98b3o$308bo9bobo21b2o95bo$308b2o9b2o
21b2o94b2o$293b2o152bo$294bo150b3o$294bob2o146bo$295bo2bo145b2o$296b2o
$311b2o122b2o$311b2o122b2o5$319bo3b2o21bo$318bobo3bo19b3o$314b2obobo3b
o19bo73b2o6b2o$314b2obo4bo20b2o72bo7bo$318b5obo93b3o5b3o$310b2obob2obo
4b2o95bo7bo$310bob2obo2bob2o106bobo$303b2o12b2obob3o104b2o$303b2o19bo$
409b2o$409b2o3b2o37b2o$414b2o13b2o18b2obobo$428bobo18b2obo$323b2o103bo
24bo$323b2o76b2o12b2o10b2o20b2ob2o$402bo6b2o4bo34bobo$399b3o7b2o5b3o
31bobo$399bo18bo4b2o22b2ob2o$422bo2bo2b2o17bobo$423b2o2bobo19bo$425b2o
22b2o$425bo$422b2obo2bo$338b2o82bob2obobo$338b2o86bobo$423b2o2bo$421b
3ob2o$420bo$421b3ob2o$423bob2o2$433b2o$433b2o7b2o$442bo$440bobo$440b2o
4$420b2o$420b2o5$436bo$435bobo$435bobo$436bo$437b3o$439bo26$221b2o$
218b2o2bo$216b3ob2o$215bo$212bo2b4ob2o$212b3o3bob2o$215bo$214b2o26b2o$
242bo$240bobo$240b2o$200bo$198b3o$197bo$197b2o$182b2o60b2o$183bo60bobo
$183bob2o59bo$184bo2bo49b2o7b2o70b2o$185b2o50b2o79bo$200b2o114bobo$
200b2o114b2o13b2o$331b2o2$220b2o3b2o$209bo3b2o6bo3bo69b2o40b2o$208bobo
3bo3b3o5b3o66b2o40b2o$207bobo3bo4bo9bo104b2o$203b2obobo3bo15bobo102b2o
$10bo192b2obo2b4obo14b2o$8bobo196bobo3bobo$9b2o192b2ob2o2bo2bobo$204bo
bo2b2o3bo123b2o$192b2o10bobo131b2o$192b2o11bo21b2o$228bo$215b2o11bobo$
216bo12b2o$216bobo$217b2o2b2o$221b2o82b2o4b2ob2o2b2o$305b2o5bobo2bobo$
312bo2b2o$313bobo$216b2o4b2o88b2obo2bo12b2o$216b2o4b2o91bobobo11bo$
312b4o2bo13b3o$312bo3b2o16bo$314bo$313b2ob2o$316b2o$313b2o$217b2o94bo
10b2o$216bobo95bo9b2o7b2o$216bo96b2o18bo$215b2o114bobo$331b2o4$311b2o$
311b2o5$327bo$326bobo$326bobo$327bo$328b3o$330bo47$218b2o$145bo72bo$
145b3o68bobo$141bo6bo67b2o13b2o$140bobo4b2o82b2o$140bobo$138b3ob2o20bo
$137bo24b3o30b2o40b2o$131bo6b3ob2o17bo33b2o40b2o$131b3o6bob2o17b2o70b
2o$134bo98b2o$121bo11b2o$119b3o36b2o$118bo38bo2bo$118b2o38b2o78b2o$
103b2o133b2o$104bo$104bob2o$105bo2bo$106b2o$121b2o$121b2o23b2o$146bo
58b2o4b2ob2o2b2o$147b3o55b2o5bobo2bobo$149bo62bo2b2o$213bobo$129bo3b2o
77b2obo2bo12b2o$128bobo3bo80bobobo11bo$124b2obobo3bo78b4o2bo13b3o$124b
2obo4bo79bo3b2o16bo$128b5obo79bo$120b2obob2obo4b2o78b2ob2o$120bob2obo
2bob2o84b2o$113b2o12b2obob3o78b2o$113b2o19bo78bo10b2o$214bo9b2o7b2o$
213b2o18bo$231bobo$231b2o4$211b2o$211b2o5$227bo$226bobo$226bobo$227bo$
228b3o$230bo33$118b2o$118bo$116bobo$116b2o13b2o$131b2o3$95b2o40b2o$95b
2o40b2o$133b2o$133b2o4$138b2o$138b2o7$105b2o4b2ob2o2b2o$105b2o5bobo2bo
bo$112bo2b2o$113bobo$112b2obo2bo12b2o$115bobobo11bo$112b4o2bo13b3o$
112bo3b2o16bo$114bo$113b2ob2o$116b2o$113b2o$113bo10b2o$114bo9b2o7b2o$
113b2o18bo$131bobo$131b2o4$111b2o$111b2o5$127bo$126bobo$126bobo$127bo$
128b3o$130bo32$764b2o$764bobo$764bo3$177b2o$177bobo185bo$177bo186b2o$
364bobo6$572b2o$572bobo599bo$572bo600b2o$1173bobo12$985b2o$985bobo$
985bo23$1379bo$1378b2o$1378bobo!
Some more notes about the script:
- The script allows you to ban specific edgeshooters from being used. I don't imagine this feature will be useful very often but I can envisage situations in which you might want to ban Fx119 edgeshooters for repeat time reasons so I added it.
- The script doesn't bother to place the eaters required to suppress the additional glider outputs from the RNE-19T84 pseudo-edgeshooters so you will have to place them yourself
- The script allows you to choose whether you prefer all the gliders to be inserted from one side or from alternating sides of the salvo. I think this feature is nice since you (usually) get greater space efficiency from inserting the gliders from alernating sides. If the script is not able to insert a glider from the side of your preference it will attempt to insert it from the other side and then go back to following your preferences
I also updated my old manual edgeshooter placing script. It now produces consistent results regardless of where the inital gliders are placed and has a few new features such as being able to place edgeshooters that insert from both sides and the ability to select gliders with the mouse rather than just with the arrow keys. I think this script is a fair bit less useful than my other script but it might be helpful if you want to handpick all the edgeshooters that are used:
Code: Select all
#place-edgeshooters-v2.py
#Goldtiger997 February 2020
import golly as g
gap_size = int(g.getstring("Please enter the diagonal spacing between the edgeshooters","50"))
safe_space = int(g.getstring("How much additional spacing do you want between the gliders and the edgeshooters? Increase this parameter if the script places gliders too close to the edgeshooters","50"))
sel_desc = g.getselrect()
selection = g.getcells(g.getselrect())
glider_phases = [g.parse("3o$2bo$bo!"),g.parse("bo$b2o$obo!"),g.parse("b2o$obo$2bo!"),g.parse("2o$b2o$o!")]
glider_phases_lh1 = [g.parse("3A$2.A$.A!"),g.parse(".A$.2A$A.A!"),g.parse(".2A$A.A$2.A!"),g.parse("2A$.2A$A!")]
glider_phases_lh2 = [g.parse("3C$2.C$.C!"),g.parse(".C$.2C$C.C!"),g.parse(".2C$C.C$2.C!"),g.parse("2C$.2C$C!")]
glider_phases_lh3 = [g.parse("3D$2.D$.D!"),g.parse(".D$.2D$D.D!"),g.parse(".2D$D.D$2.D!"),g.parse("2D$.2D$D!")]
gliders = []
gliders_sorted = []
gliders_lanes = []
the_numbers = ["1","2","3","4","5"] #full list ["1","2","3","4","5","6","7","8","9","0"]
#edgeshooters
#format is [rle, output glider lane adjustment, input glider lane adjustment, input glider positioning adjustment,delay of edgeshooter,flip_adjust,flip_time_adjust]
edgeshooter1 = [g.parse("18.B$17.2B$16.3B$15.4B$14.4B$13.4B$12.4B$11.4B$10.4B$9.4B$8.4B$8.4B$7.5B$4.9B$4.9B$4.9B$4.10B$3.12B$2.13B8.2A$3.11B9.A$4.12B4.BA.A$4.15B.B2A13.2A$4.17B14.B2AB$4.17B15.2B$.B.17B17.2B3.B$2A19B15.4B.B2A$2AB.19B11.8B2A$.B4.20B2.2B2.6B2AB.B$6.32B2A$6.9B.24B$7.7B2.28B$7.7B2.28B$7.6B4.26B2A$7.7B10.4B.14B2A$7.6B12.4B2.11B.B$6.7B13.4B2.10B$7.6B14.14B$8.5B15.14B$8.6B14.13B$10.4B14.13B$9.B2A2B2.2A.2A2.2A3.8B.4B$10.2A5.A.A2.A.A3.8B$17.A2.2A.B4.8B$18.A.A2.2B3.10B$17.2A.A.BA2B.7B2.2A$20.A.A.A9B2.A$17.4A2.A.8B4.3A$17.A3.2A3.7B6.A$19.A.B6.6B$18.2AB2AB3.7B$21.2AB.8B$18.2A3.10B$18.A4.6B2A3B$19.A3.6B2A2B5.2A$18.2A3.10B5.A$22.11B2.BA.A$22.12B.B2A$21.15B$20.16B$17.2B.16B$16.2A18B$16.2AB.17B$17.B.4B.8B2.4B$24.7B4.4B$25.6B5.4B$27.4B6.4B$29.3BA5.4B$30.BA.A5.3B$31.ABA6.2B$32.A8.B$33.3A$35.A!"),18,0,27,1,19,-100]
edgeshooter2 = [g.parse("22.4B$21.4B$20.4B$19.4B$18.4B5.2A$17.6B3.A2.A$16.8B.B.A.A$16.10B2A2.2A$15.11B2.2A2.A$15.11B2A3.2A$15.10B2.A$15.9B2.A$10.14B3.3A$9.13B7.A$9.14B$9.14B$9.13B$10.11B$9.14B$9.2B2A11B$10.B2A11B$10.14B$10.4B.8B$11.2B.9B3.2A$14.8B3.A.A$14.8B3.A$14.9B.2A$13.11B$12.12B$12.12B$5.2A6.10B$6.A7.11B$6.A.AB.14B$7.2AB.13B2A$9.15B2A$8.15B.B$9.14B$7.2AB.11B$6.A.AB3.9B$6.A8.8B$5.2A9.7B$13.11B$12.12B$12.12B$12.11B$2A.2A2.2A3.8B.4B$.A.A2.A.A3.7B4.2A$.A2.2A.B4.7B4.A$2.A.A2.2B.B.6B6.3A$.2A.A.BA10B8.A$4.A.A.A9B$.4A2.A.8B$.A3.2A4.6B$3.A.B6.6B$2.2AB2AB3.7B$5.2AB.8B$2.2A3.10B$2.A4.6B2A3B$3.A3.6B2A2B5.2A$2.2A3.10B5.A$6.11B2.BA.A$6.12B.B2A$5.15B$4.16B$.2B.16B$2A18B$2AB.17B$.B.4B.8B2.4B$8.7B4.4B$9.6B5.4B$11.4B6.4B$13.3BA5.4B$14.BA.A5.4B$15.ABA$16.A$17.3A$19.A!"),22,12,48,39,23,-184]
edgeshooter3 = [g.parse("18.4B$17.4B$16.4B$15.4B$14.6B7.2A$13.7B7.A$13.9B2.BA.A$9.B2.11B.B2A$9.2B.9BA3B$9.3B.7BABA2B$9.11BABA2B$10.4B.B2.3BA3B$11.4B4.6B$12.4B4.6B$13.4B3.6B$14.4B2.5B$15.14B$16.14B$17.13B$10.2A5.13B$11.A5.11B.B2A$11.A.AB2.10B2.BA.A$12.2AB.9B7.A$14.11B7.2A$14.13B$14.9B.B2A.A$15.7B2.B2AB3A$14.8B4.B4.A$15.8B2.2A.3A$16.7B3.A.A$13.11B2.A.A$12.11B4.A$12.11B$12.11B$2A.2A2.2A3.8B2.B2A$.A.A2.A.A3.7B3.BA.A$.A2.2A.B4.7B6.A$2.A.A2.2B3.6B7.2A$.2A.A.BAB2.7B$4.A.A.A2.7B$.4A2.A4.5B$.A3.2A4.6B$3.A.B6.6B$2.2AB2AB3.7B$5.2AB.8B$2.2A3.10B$2.A4.6B2A3B$3.A3.6B2A2B5.2A$2.2A3.10B5.A$6.11B2.BA.A$6.12B.B2A$5.15B$4.16B$.2B.16B$2A18B$2AB.17B$.B.4B.8B2.4B$8.7B4.4B$9.6B5.4B$11.4B6.4B$13.3BA5.4B$14.BA.A5.4B$15.A.A6.4B$16.A8.4B$17.3A6.4B$19.A7.4B$28.4B!"),18,4,37,14,19,-140]
edgeshooter4 = [g.parse("17.4B$16.4B$15.4B$14.4B$13.4B$12.4B$11.4B$10.4B$9.7B$9.9B$8.11B$5.13B$4.14B$3.16B$3.17B$2.18B$2.19B$.20B19.A$20B20.3A$.21B21.A$.21B20.2A$3.19B20.B8.A$2.B.17B19.3B6.3A$4.18B16.6B4.A$4.20B11.10B3.2A$5.22B2.2B3.16B$5.34B2A7B$7.32B2A9B$8.42B$8.42B$8.44B$8.13B4.4B.13B.9B$8.6B4.3B5.3B5.B.19B$7.7B5.4B4.4B12.14B$8.6B7.2A6.2A11.15B$9.6B6.A7.A12.14B$9.6B7.3A5.3A9.13B$8.8B8.A7.A6.15B$9.6B17.A.AB2.15B$8.7B18.2AB.17B$6.11B18.19B$4.9B2A2B.B15.19B$4.9B2A3B2A15.20B2.2A$4.14B2A13.2AB.16B2A.A.A$5.14B13.A.AB2.13B.B2ABA$5.3B.2B2.B2.5B11.A6.11B4.B2.A$5.2A5.3B4.2A10.2A7.11B2.2A.2A$6.A5.B2AB3.A17.14B3.A.A$3.3A7.2A5.3A13.16B2.A.A$3.A18.A4.2A7.13B.B2A.2A$26.A2.A2.2A2.13B.BA.A$27.2A2.A.A2.8B.2B6.A$29.2A.B3.7B10.2A$29.A2.2B2.7B$26.2A.A.BA2B.6B$26.A.2A.A.A8B$30.A.A.8B$27.2A2.A2.7B$25.3A.2A4.6B$24.A4.B6.6B$25.3AB2AB3.7B$27.A.2AB.8B$31.10B$31.6B2A3B$31.6B2A2B5.2A$31.10B5.A$30.11B2.BA.A$30.12B.B2A$29.15B$28.16B$25.2B.16B$24.2A18B$24.2AB.17B$25.B.4B.8B2.4B$32.7B4.4B$33.6B5.4B$35.4B6.4B$37.3BA5.4B$38.BA.A5.4B$39.ABA6.4B$40.A8.3B$41.3A6.B$43.A!"),17,0,30,87,18,-112]
edgeshooter5 = [g.parse("23.4B$22.4B$21.4B$20.4B$19.4B$18.4B$17.4B$16.4B$3.2A10.4B$4.A9.4B$2.A10.4B$2.5A5.4B5.2A$7.A4.4B5.A$4.3AB2.7B.BA.A$3.A.2B3.7B.B2A$3.4A12B$.2A2.BA3B2A7B$A2.3AB.2B2A7B$2A.A.B3.10B$3.A8.8B$3.2A7.9B$13.3B2.4B$11.5B3.4B$11.2A7.4B$12.A8.3B$9.3A10.2B$9.A13.B!"),23,-14,2,-76,24,0]
edgeshooters = [edgeshooter1,edgeshooter2,edgeshooter3,edgeshooter4,edgeshooter5]
if g.getselrect() == []:
g.warn("Please select some northeast heading gliders")
g.exit()
g.shrink()
#crude glider detection
def find_glider(phase_num):
count = 0
size = ((sel_desc[2]-2)*(sel_desc[3]-2))
for i in range(0,sel_desc[2]-2):
for j in range(0,sel_desc[3]-2):
x = sel_desc[0]+i
y = sel_desc[1]+j
g.select([x,y,3,3])
old_patt = g.getcells(g.getselrect()) #for restoration
g.putcells(glider_phases[phase_num],x,y,1,0,0,1,"xor")
if len(g.getcells(g.getselrect())) == 0:
gliders.append([phase_num,x,y])
g.clear(0)
g.putcells(old_patt,0,0,1,0,0,1,"or")
count += 1
g.show(str(25*phase_num + count*25/size) + "% glider detection done")
for i in range(0,4):
find_glider(i)
if len(gliders) == 0:
g.warn("Your selection has no (detectable) gliders")
g.exit()
g.setrule("LifeHistory")
#now convert into format of [[lane,point on that lane]...]
for glid in gliders:
if glid[0] == 0:
gliders_lanes.append([glid[2]+glid[1],glid[1]*4])
elif glid[0] == 1:
gliders_lanes.append([glid[2]+glid[1] + 1,glid[1]*4 + 1])
elif glid[0] == 2:
gliders_lanes.append([glid[2]+glid[1] + 1,glid[1]*4 + 2])
elif glid[0] == 3:
gliders_lanes.append([glid[2]+glid[1],glid[1]*4 - 1])
gliders_lanes_sorted = sorted(gliders_lanes, key = lambda x: x[0])[::-1]
for e in gliders_lanes_sorted:
gliders_sorted.append(gliders[gliders_lanes.index(e)])
#g.note(str(gliders_lanes_sorted))
last_selected_glider = 0
completed_gliders = []
for blah_blah_blah in gliders:
completed_gliders.append(False)
last_selected_glider = -1
#highlight gliders in the white LifeHistory state
def select_glider(num):
global last_selected_glider
glid = gliders_sorted[num%len(gliders)]
g.putcells(glider_phases_lh2[glid[0]],glid[1],glid[2],1,0,0,1,"copy")
#revert previous selected glider to its previous state
if completed_gliders[last_selected_glider%len(gliders)] == False:
old_glid = gliders_sorted[last_selected_glider%len(gliders)]
g.putcells(glider_phases_lh1[old_glid[0]],old_glid[1],old_glid[2],1,0,0,1,"copy")
else:
old_glid = gliders_sorted[last_selected_glider%len(gliders)]
g.putcells(glider_phases_lh3[old_glid[0]],old_glid[1],old_glid[2],1,0,0,1,"copy")
last_selected_glider = num
select_glider(0)
g.putcells(selection,-(186 + safe_space) - gap_size*len(gliders),(186 + safe_space) + gap_size*len(gliders),1,0,0,1,"or")
g.update()
def find_glider_from_click(x,y):
answer = ""
for i in range(0,len(gliders)):
if gliders_sorted[i][1] - x >= -4 and gliders_sorted[i][1] - x <= 1 and gliders_sorted[i][2] - y >= -4 and gliders_sorted[i][2] - y <= 1:
answer = i
break
return answer
edgeshooter_gap = 150
edgeshooters_placed_count = 0
edgeshooter_storage = [] #to facilitate deletion
def place_edgeshooter(num,gap,count):
if flipped%2 == 0:
edge_x = -gap-edgeshooters[num][1] + edgeshooters[num][2] + sel_desc[0]
edge_y = gliders_lanes_sorted[last_selected_glider%len(gliders)][0]+gap - edgeshooters[num][2] - sel_desc[0]
g.putcells(edgeshooters[num][0],edge_x,edge_y,1,0,0,1,"or")
delay = edgeshooters[num][4] + gliders_lanes_sorted[last_selected_glider%len(gliders)][1] - 4*safe_space - 4*sel_desc[0]
x = edge_x - delay/4 + gap_size*(len(gliders) - count)
y = edge_y + edgeshooters[num][3] - delay/4 + gap_size*(len(gliders) - count)
g.putcells(g.evolve(g.parse("$b3o$bo$2bo!"),delay%4),x-1,y-1,1,0,0,1,"copy")
else:
edge_x = -gap-edgeshooters[num][1] + edgeshooters[num][2] + edgeshooters[num][5] + sel_desc[0]
edge_y = gliders_lanes_sorted[last_selected_glider%len(gliders)][0]+gap - edgeshooters[num][2] + edgeshooters[num][5] + 1 - sel_desc[0]
g.putcells(edgeshooters[num][0],edge_x,edge_y,0,-1,-1,0,"or")
delay = edgeshooters[num][4] + gliders_lanes_sorted[last_selected_glider%len(gliders)][1] + edgeshooters[num][6] - 4*safe_space - 4*sel_desc[0]
x = edge_x + delay/4 - gap_size*(len(gliders) + count) + 1 + 2*gap_size*count
y = edge_y + edgeshooters[num][3] + delay/4 - gap_size*(len(gliders) + count) + 2*gap_size*count
g.putcells(g.evolve(g.parse("$b3o$bo$2bo!"),delay%4),x-1,y-1,-1,0,0,-1,"copy")
#remove the comparison glider
g.putcells(glider_phases[gliders_sorted[last_selected_glider%len(gliders)][0]],gliders_sorted[last_selected_glider%len(gliders)][1] - (186 + safe_space) - gap_size*len(gliders),gliders_sorted[last_selected_glider%len(gliders)][2] + (186 + safe_space) + gap_size*len(gliders),1,0,0,1,"xor")
g.update()
edgeshooter_storage.append([edge_x,edge_y,x,y,num,last_selected_glider%len(gliders),flipped%2])
def remove_edgeshooter(e):
g.putcells(edgeshooters[e[4]][0],e[0],e[1],1-e[6],-e[6],-e[6],1-e[6],"xor")
g.select([e[2]-1-e[6]*3,e[3]-1-e[6]*3,4,4])
g.clear(0)
g.update()
completed_gliders[e[5]] = False
glid = gliders_sorted[e[5]]
g.putcells(glider_phases_lh1[glid[0]],glid[1],glid[2],1,0,0,1,"copy")
select_glider(last_selected_glider%len(gliders))
g.putcells(glider_phases[gliders_sorted[e[5]][0]],gliders_sorted[e[5]][1] - (186 + safe_space) - gap_size*len(gliders),gliders_sorted[e[5]][2] + (186 + safe_space) + gap_size*len(gliders),1,0,0,1,"or")
g.update()
edgeshooter_storage.pop()
flipped = 0
while True:
event = g.getevent()
if event.startswith("key h"):
g.note("Commmands:\n\n- press the up and down arrows to toggle between the gliders\n- alternatively, click on a glider to select it\n- press the number keys to place one of the five supported edgeshooters\n- press d to delete the most recently placed edgeshooter\n- press t to test the current pattern\n- press r to return from the testing to generation 0\n- press f to fit the entire pattern into the viewport\n- press x to copy the current pattern to the clipboard\n- press k to toggle between inserting the gliders from the NE and the SW\n- press [ to zoom out\n- press ] to zoom in\n - press v view the gliders")
if event.startswith("key f"):
g.fit()
g.update()
if event.startswith("key v"):
g.select(sel_desc)
g.fitsel()
g.update()
if event.startswith("key ["):
g.setmag(g.getmag() - 1)
g.update()
if event.startswith("key ]"):
g.setmag(g.getmag() + 1)
g.update()
if event.startswith("key x"):
g.select(g.getrect())
g.copy()
g.select([])
if g.getgen() == "0":
if flipped%2 == 0:
g.show("Press <h> for help. Press <esc> to quit the script with the current edgeshooters. Currently inserting from the SE")
else:
g.show("Press <h> for help. Press <esc> to quit the script with the current edgeshooters. Currently inserting from the NW")
if event.startswith("click"):
ans = find_glider_from_click(int(event.split()[1]),int(event.split()[2]))
if ans != "":
select_glider(ans)
g.update()
elif event.startswith("key up"):
select_glider(last_selected_glider+1)
g.update()
elif event.startswith("key down"):
select_glider(last_selected_glider-1)
g.update()
elif event.startswith("key k"):
flipped += 1
elif event.startswith("key t"):
g.run(744 + 4*safe_space + 4*gap_size*len(gliders))
g.update()
elif event.startswith("key d"):
if edgeshooter_storage != []:
remove_edgeshooter(edgeshooter_storage[-1])
edgeshooters_placed_count -= 1
edgeshooter_gap -= gap_size
elif event.startswith("key ") and event[4] in the_numbers:
if completed_gliders[last_selected_glider%len(gliders)]:
g.note("this glider has already had an edgeshooter constructed")
else:
place_edgeshooter(the_numbers.index(event[4]),edgeshooter_gap,edgeshooters_placed_count)
edgeshooter_gap += gap_size
edgeshooters_placed_count += 1
completed_gliders[last_selected_glider%len(gliders)] = True
else:
g.show("Advanced pattern to generation " + str(744 + 4*safe_space + 4*gap_size*len(gliders)) + ". Press <r> to return to generation 0")
if event.startswith("key r"):
g.reset()
g.update()