EDIT0: Here's the link for the glider pair adjustment toolkit.
EDIT1: Updated 4 June 2014, after a complete scan of Hunting of the New Herschel Conduits thread, with some composite conduits included -- mostly H-to-X-to-G for non-Herschel X. Added and fixed everything from simeks' review (thanks again!)
EDIT2: Updated collection from chris_c, 13 October 2015 -- 50 new H-to-Gs, mostly combinations of elementary conduits, plus simeks' new SE30T14.
EDIT3: Updated collection based on simeks' notes.
EDIT4: Annual October update for 2016 -- added everything I found in this thread and the Hunting of the New Herschel Conduits thread.
-----------------------------------------------
Please post links or patterns for Herschel-to-glider or Herschel-to-2-parallel-glider converters that aren't in the respective collections yet. The pattern below is the template for the H-to-G stamp collection, to be updated from time to time here in this first post. I'll fill in the forty or fifty known ones sometime this week, and then will be looking for pointers to other H-to-Gs that I've missed.
See the next post for a similar stamp collection for H-to-G(n).
Canonical orientations for gliders:
x = 27, y = 30, rule = LifeHistory
D3.D.D3.D5.D3.D.5D$2D2.D.D3.D5.2D2.D.D$D.D.D.D3.D5.D.D.D.D$D2.2D.D.D.
D5.D2.2D.3D$D3.D.D.D.D5.D3.D.D$D3.D.2D.2D5.D3.D.D$D3.D.D3.D5.D3.D.5D
4$4.3C13.3C$4.C17.C$5.C15.C5$5.C15.C$4.C17.C$4.3C13.3C4$.3D2.D3.D6.3D
2.5D$D3.D.D3.D5.D3.D.D$D5.D3.D5.D5.D$.3D2.D.D.D6.3D2.3D$4.D.D.D.D9.D.
D$D3.D.2D.2D5.D3.D.D$.3D2.D3.D6.3D2.5D!
#C [[ VIEWONLY THUMBNAIL ]]
If a canonical-phase glider is centered on the cell (N, 0) then it's on Lane N -- that is, if you run a lane-N glider forwards or backwards in time, there should be a pont where the canonical orientation of the glider is centered around (N,0). This is slightly different from the old NW and SE lane numbers from the 2006 collection, but the same for the old NE and SW lanes.
Script to identify H-to-Gs:
H-to-Gstats16November2015.py -- edited to remove dependency on make_text in glife module, for more reliability when running from clipboard:
import golly as g
from time import sleep
import itertools
from string import *
# Mono-spaced ASCII font
__mfont = dict()
__mfont[' '] = g.parse("")
__mfont['!'] = g.parse("2bo$2bo$2bo$2bo$2bo2$2bo!")
__mfont['"'] = g.parse("bobo$bobo$bobo!")
__mfont['#'] = g.parse("bobo$bobo$5o$bobo$5o$bobo$bobo!")
__mfont['$'] = g.parse("b3o$obobo$obo$b3o$2bobo$obobo$b3o!")
__mfont['%'] = g.parse("2o2bo$2o2bo$3bo$2bo$bo$o2b2o$o2b2o!")
__mfont['&'] = g.parse("b2o$o2bo$o2bo$b2o$o2bo$o2bo$b2obo!")
__mfont['\''] = g.parse("2bo$2bo$2bo!")
__mfont['('] = g.parse("3bo$2bo$2bo$2bo$2bo$2bo$3bo!")
__mfont[')'] = g.parse("bo$2bo$2bo$2bo$2bo$2bo$bo!")
__mfont['*'] = g.parse("$obobo$b3o$5o$b3o$obobo!")
__mfont['+'] = g.parse("$2bo$2bo$5o$2bo$2bo!")
__mfont[','] = g.parse("6$2bo$2bo$bo!")
__mfont['-'] = g.parse("3$5o!")
__mfont['.'] = g.parse("6$2bo!")
__mfont['/'] = g.parse("3bo$3bo$2bo$2bo$2bo$bo$bo!")
__mfont['0'] = g.parse("b3o$o3bo$o2b2o$obobo$2o2bo$o3bo$b3o!")
__mfont['1'] = g.parse("2bo$b2o$2bo$2bo$2bo$2bo$b3o!")
__mfont['2'] = g.parse("b3o$o3bo$4bo$3bo$2bo$bo$5o!")
__mfont['3'] = g.parse("b3o$o3bo$4bo$2b2o$4bo$o3bo$b3o!")
__mfont['4'] = g.parse("3bo$2b2o$bobo$o2bo$5o$3bo$3bo!")
__mfont['5'] = g.parse("5o$o$o$b3o$4bo$o3bo$b3o!")
__mfont['6'] = g.parse("b3o$o$o$4o$o3bo$o3bo$b3o!")
__mfont['7'] = g.parse("5o$4bo$3bo$2bo$bo$o$o!")
__mfont['8'] = g.parse("b3o$o3bo$o3bo$b3o$o3bo$o3bo$b3o!")
__mfont['9'] = g.parse("b3o$o3bo$o3bo$b4o$4bo$4bo$b3o!")
__mfont[':'] = g.parse("2$2bo4$2bo!")
__mfont[';'] = g.parse("2$2bo4$2bo$2bo$bo!")
__mfont['<'] = g.parse("$3bo$2bo$bo$2bo$3bo!")
__mfont['='] = g.parse("2$5o2$5o!")
__mfont['>'] = g.parse("$bo$2bo$3bo$2bo$bo!")
__mfont['?'] = g.parse("b3o$o3bo$4bo$2b2o$2bo2$2bo!")
__mfont['@'] = g.parse("b3o$o3bo$ob3o$obobo$ob2o$o$b3o!")
__mfont['A'] = g.parse("b3o$o3bo$o3bo$5o$o3bo$o3bo$o3bo!")
__mfont['B'] = g.parse("4o$o3bo$o3bo$4o$o3bo$o3bo$4o!")
__mfont['C'] = g.parse("b3o$o3bo$o$o$o$o3bo$b3o!")
__mfont['D'] = g.parse("4o$o3bo$o3bo$o3bo$o3bo$o3bo$4o!")
__mfont['E'] = g.parse("5o$o$o$3o$o$o$5o!")
__mfont['F'] = g.parse("5o$o$o$3o$o$o$o!")
__mfont['G'] = g.parse("b3o$o3bo$o$o2b2o$o3bo$o3bo$b3o!")
__mfont['H'] = g.parse("o3bo$o3bo$o3bo$5o$o3bo$o3bo$o3bo!")
__mfont['I'] = g.parse("b3o$2bo$2bo$2bo$2bo$2bo$b3o!")
__mfont['J'] = g.parse("2b3o$3bo$3bo$3bo$3bo$o2bo$b2o!")
__mfont['K'] = g.parse("o3bo$o2bo$obo$2o$obo$o2bo$o3bo!")
__mfont['L'] = g.parse("o$o$o$o$o$o$5o!")
__mfont['M'] = g.parse("o3bo$2ob2o$obobo$obobo$o3bo$o3bo$o3bo!")
__mfont['N'] = g.parse("o3bo$2o2bo$obobo$o2b2o$o3bo$o3bo$o3bo!")
__mfont['O'] = g.parse("b3o$o3bo$o3bo$o3bo$o3bo$o3bo$b3o!")
__mfont['P'] = g.parse("4o$o3bo$o3bo$4o$o$o$o!")
__mfont['Q'] = g.parse("b3o$o3bo$o3bo$o3bo$obobo$o2bo$b2obo!")
__mfont['R'] = g.parse("4o$o3bo$o3bo$4o$o2bo$o3bo$o3bo!")
__mfont['S'] = g.parse("b3o$o3bo$o$b3o$4bo$o3bo$b3o!")
__mfont['T'] = g.parse("5o$2bo$2bo$2bo$2bo$2bo$2bo!")
__mfont['U'] = g.parse("o3bo$o3bo$o3bo$o3bo$o3bo$o3bo$b3o!")
__mfont['V'] = g.parse("o3bo$o3bo$o3bo$o3bo$o3bo$bobo$2bo!")
__mfont['W'] = g.parse("o3bo$o3bo$o3bo$obobo$obobo$2ob2o$o3bo!")
__mfont['X'] = g.parse("o3bo$o3bo$bobo$2bo$bobo$o3bo$o3bo!")
__mfont['Y'] = g.parse("o3bo$o3bo$bobo$2bo$2bo$2bo$2bo!")
__mfont['Z'] = g.parse("5o$4bo$3bo$2bo$bo$o$5o!")
__mfont['['] = g.parse("2b2o$2bo$2bo$2bo$2bo$2bo$2b2o!")
__mfont['\\'] = g.parse("bo$bo$2bo$2bo$2bo$3bo$3bo!")
__mfont[']'] = g.parse("b2o$2bo$2bo$2bo$2bo$2bo$b2o!")
__mfont['^'] = g.parse("2bo$bobo$o3bo!")
__mfont['_'] = g.parse("6$5o!")
__mfont['`'] = g.parse("o$bo!")
__mfont['a'] = g.parse("2$b4o$o3bo$o3bo$o3bo$b4o!")
__mfont['b'] = g.parse("o$o$4o$o3bo$o3bo$o3bo$4o!")
__mfont['c'] = g.parse("2$b4o$o$o$o$b4o!")
__mfont['d'] = g.parse("4bo$4bo$b4o$o3bo$o3bo$o3bo$b4o!")
__mfont['e'] = g.parse("2$b3o$o3bo$5o$o$b4o!")
__mfont['f'] = g.parse("2b2o$bo2bo$bo$3o$bo$bo$bo!")
__mfont['g'] = g.parse("2$b3o$o3bo$o3bo$o3bo$b4o$4bo$b3o!")
__mfont['h'] = g.parse("o$o$ob2o$2o2bo$o3bo$o3bo$o3bo!")
__mfont['i'] = g.parse("$2bo2$2bo$2bo$2bo$2b2o!")
__mfont['j'] = g.parse("$3bo2$3bo$3bo$3bo$3bo$o2bo$b2o!")
__mfont['k'] = g.parse("o$o$o2bo$obo$3o$o2bo$o3bo!")
__mfont['l'] = g.parse("b2o$2bo$2bo$2bo$2bo$2bo$2b2o!")
__mfont['m'] = g.parse("2$bobo$obobo$obobo$o3bo$o3bo!")
__mfont['n'] = g.parse("2$4o$o3bo$o3bo$o3bo$o3bo!")
__mfont['o'] = g.parse("2$b3o$o3bo$o3bo$o3bo$b3o!")
__mfont['p'] = g.parse("2$4o$o3bo$o3bo$o3bo$4o$o$o!")
__mfont['q'] = g.parse("2$b4o$o3bo$o3bo$o3bo$b4o$4bo$4bo!")
__mfont['r'] = g.parse("2$ob2o$2o2bo$o$o$o!")
__mfont['s'] = g.parse("2$b4o$o$b3o$4bo$4o!")
__mfont['t'] = g.parse("$2bo$5o$2bo$2bo$2bo$3b2o!")
__mfont['u'] = g.parse("2$o3bo$o3bo$o3bo$o3bo$b4o!")
__mfont['v'] = g.parse("2$o3bo$o3bo$o3bo$bobo$2bo!")
__mfont['w'] = g.parse("2$o3bo$o3bo$obobo$2ob2o$o3bo!")
__mfont['x'] = g.parse("2$o3bo$bobo$2bo$bobo$o3bo!")
__mfont['y'] = g.parse("2$o3bo$o3bo$o3bo$o3bo$b4o$4bo$b3o!")
__mfont['z'] = g.parse("2$5o$3bo$2bo$bo$5o!")
__mfont['{'] = g.parse("3bo$2bo$2bo$bo$2bo$2bo$3bo!")
__mfont['|'] = g.parse("2bo$2bo$2bo$2bo$2bo$2bo$2bo!")
__mfont['}'] = g.parse("bo$2bo$2bo$3bo$2bo$2bo$bo!")
__mfont['~'] = g.parse("2$bo$obobo$3bo!")
orientations=[[1,0,0,1],[0,-1,1,0],[-1,0,0,-1],[0,1,-1,0],[1,0,0,-1],[0,1,1,0],[0,-1,-1,0],[-1,0,0,1]]
herschel=([[-1,-2],[-1,-1],[-1,0],[1,-1],[1,0],[1,1]],0) # plus [0,0] makes a Herschel
# arrange for pre-Herschels to be recognizable also
hminus3=([[-5,-1],[-5,1],[-5,2],[-4,-2],[-4,-1],[-4,0],[-4,1],[-4,2],[-3,-2],[-3,-1],[-3,0],[-3,1],[-1,-1],[-1,0],[-1,1],[0,-1],[0,1],[1,0]],-3)
hminus4=([[-5,1],[-4,-2],[-4,-1],[-4,0],[-4,1],[-4,2],[-3,-3],[-1,-2],[-1,2],[0,-1],[0,1],[0,1]],-4)
hminus5=([[-4,0],[-4,1],[-4,2],[-3,-3],[-3,-2],[-3,-1],[-3,1],[-2,-2],[-2,-1],[-2,1],[-2,2],[-1,-2],[-1,-1],[-1,1],[-1,2],[-1,2]],-5)
hminus6=([[-5,1],[-4,-3],[-4,1],[-3,-2],[-3,1],[-2,-2],[-2,-1],[-2,1],[-2,2],[-1,-1],[-1,1],[-1,1]],-6)
# the duplicate cell at end of hminus6 is a cheap kludge
# to allow a multistate version of the cell list to have an odd number of items...
# quick recognition patterns and offsets for all phases -- add [0,0] to make a complete glider
gliders=[([[1,0],[2,0],[0,1],[1,2]],(-1,-1),"NW",0),
([[-1,1],[0,1],[-1,2],[1,2]],(0,-2),"NW",1),
([[1,0],[0,1],[2,1],[0,2]],(-1,-2),"NW",2),
([[1,0],[-1,1],[0,1],[1,2]],(-1,-2),"NW",3),
([[1,0],[2,0],[2,1],[1,2]],(-1,-1),"NE",0),
([[0,1],[1,1],[-1,2],[1,2]],(0,-2),"NE",1),
([[1,0],[-1,1],[1,1],[1,2]],(0,-2),"NE",2),
([[1,0],[1,1],[2,1],[0,2]],(0,-2),"NE",3),
([[1,1],[-1,2],[0,2],[1,2]],(0,-1),"SE",0),
([[2,0],[1,1],[2,1],[1,2]],(-1,0),"SE",1),
([[-2,1],[0,1],[-1,2],[0,2]],(1,0),"SE",2),
([[1,1],[2,1],[0,2],[1,2]],(0,0),"SE",3),
([[-1,1],[-1,2],[0,2],[1,2]],(0,-1),"SW",0),
([[2,0],[0,1],[1,1],[1,2]],(-1,0),"SW",1),
([[0,1],[2,1],[0,2],[1,2]],(-1,0),"SW",2),
([[-2,1],[-1,1],[-1,2],[0,2]],(0,0),"SW",3)]
RUNTIME = 1024
def make_text(string, font='Mono'):
p,x = [], 0
for c in string:
if not __mfont.has_key (c): c = "_"
p += g.transform(__mfont[c],x,0)
x += 6
return p
def groupcells(c):
return [c[pos:pos+2] for pos in range(0, len(c)-1, 2)]
def findHerschels(c, hv):
h=hv[0]
count,foundmatch,final=0,0,[]
while count<8:
ora,orb,orc,ord=orientations[count]
count+=1
cnew=groupcells(g.transform(c,0,0,ora,orb,orc,ord))
for cell in cnew:
sleep(0)
ptr,match=0,1
while ptr<len(h):
if [cell[0]+h[ptr][0],cell[1]+h[ptr][1]] not in cnew:
match=0
break
ptr+=1
if match==1:
final=g.transform(c,0,0,ora,orb,orc,ord)
final=g.transform(final,-cell[0],-cell[1])
foundmatch+=1
# break ## faster, but doesn't check for multiple Herschels
# if foundmatch==1: break
return foundmatch, final, hv
# input time run so far
# return list of spacetime locations of canonical gliders in current universe:
# [["NW",X0,Y0,T0],["NW",X1,Y1,T1],[["SE",X2,Y2,T2],["NE",X3,Y3,T3]]
def findgliders(t):
outlist=[]
clist=groupcells(g.getcells(g.getrect()))
while clist!=[]:
cx,cy = clist[0][0],clist[0][1]
match=1
for glider in gliders:
match = 1
for item in glider[0]:
if g.getcell(item[0]+cx,item[1]+cy)==0:
match=0
break
if match==1:
g.setcell(cx,cy,0)
for item in glider[0]:
g.setcell(item[0]+cx,item[1]+cy, 0)
outlist+=[[cx-glider[1][0],cy-glider[1][1],glider[2],glider[3]]]
# make new list of remaining ON cells and continue
clist=groupcells(g.getcells(g.getrect()))
break
# if we try all gliders and none of them match, report the problem
if match==0: g.exit("Top remaining cell doesn't look like a glider.")
# g.note(str(clist)+"\n"+str(outlist))
return outlist
cells,altcells=g.getcells(g.getselrect()),[]
if cells==[]:
cells=g.getcells(g.getrect())
if cells==[]:
g.exit("Please open or select H-to-nG converter pattern to retrieve glider statistics.")
altcells2, altflatcells2 = [], []
if len(cells)%2==1:
# convert to two-state list
# cells = ON cells only (will find Herschels with some cells marked)
# altcells = marked ON and marked OFF cells
# altcells2 = any ON and marked OFF cells
newcells=[cells[i:i+2] for i in range(0,len(cells)-1,3) if cells[i+2] in [1,3,5]]
flatcells=list(itertools.chain.from_iterable(newcells)) # sum(newcells,[]) is shorter but slower
# altcells=[cells[i:i+2] for i in range(0,len(cells)-1,3) if cells[i+2] in [3,4,5]]
# altflatcells=list(itertools.chain.from_iterable(altcells))
altcells2=[cells[i:i+2] for i in range(0,len(cells)-1,3) if cells[i+2] in [1,3,4,5]]
altflatcells2=list(itertools.chain.from_iterable(altcells2))
cells=newcells
else:
flatcells=cells
foundmatch, final, hvariant = findHerschels(flatcells, herschel)
if foundmatch==0:
foundmatch, final, hvariant = findHerschels(flatcells, hminus3)
if foundmatch==0:
foundmatch, final, hvariant = findHerschels(flatcells, hminus4)
if foundmatch==0:
foundmatch, final, hvariant = findHerschels(flatcells, hminus5)
if foundmatch==0:
foundmatch, final, hvariant = findHerschels(flatcells, hminus6)
if foundmatch==0:
if altcells2!=[]:
foundmatch, final, hvariant = findHerschels(altflatcells2, herschel)
if foundmatch==0:
foundmatch, final, hvariant = findHerschels(altflatcells2, hminus3)
if foundmatch==0:
foundmatch, final, hvariant = findHerschels(altflatcells2, hminus4)
if foundmatch==0:
foundmatch, final, hvariant = findHerschels(altflatcells2, hminus5)
if foundmatch==0:
foundmatch, final, hvariant = findHerschels(altflatcells2, hminus6)
if foundmatch==0: g.exit("No match found.")
if foundmatch>1: g.exit("Found multiple Herschels ("+str(foundmatch)+")" )
hcells=[[0,0]]+hvariant[0]
# hcellsflat=list(itertools.chain.from_iterable(hcells))
g.addlayer()
g.new("LifeHistory version")
g.setrule("LifeHistory")
g.putcells(final)
rfinal=g.getrect()
g.run(RUNTIME)
# g.putcells(list(itertools.chain.from_iterable([c+[3] for c in groupcells(hcellsflat)])))
g.putcells(list(itertools.chain.from_iterable([c+[3] for c in hcells])))
finalLH=g.getcells([rfinal[0]-8,rfinal[1]-8,rfinal[2]+16,rfinal[3]+16])
g.new("start@H"+str(hvariant[1]))
# g.setalgo("QuickLife")
g.setrule("B3/S23")
g.putcells(final)
g.run(RUNTIME)
for c in hcells:
if g.getcell(c[0],c[1])!=0: g.exit("Herschel site is contaminated.")
for c in hcells: g.setcell(c[0],c[1],1)
for c in groupcells(final):
if g.getcell(c[0],c[1])==0: g.exit("Conduit has been damaged.")
g.setcell(c[0],c[1],0)
glist = findgliders(RUNTIME)
count=0
g.setrule("LifeHistory")
for item in glist:
if item[2]=="NW":
lane = item[0]-item[1]
out="NW"+str(lane)+"T"+str(RUNTIME-item[3]+4*item[1]+hvariant[1]+4*lane) # tested
elif item[2]=="NE":
lane = item[0]+item[1]
out="NE"+str(lane)+"T"+str(RUNTIME-item[3]+4*item[1]+hvariant[1]-4*lane) # tested
elif item[2]=="SE":
lane = item[0]-item[1]
out="SE"+str(lane)+"T"+str(RUNTIME-item[3]-4*item[1]+hvariant[1]-4*lane) # tested
elif item[2]=="SW":
lane = item[0]+item[1]
out="SW"+str(lane)+"T"+str(RUNTIME-item[3]-4*item[1]+hvariant[1]+4*lane) # tested
else:
g.note("A new diagonal direction has been discovered...!")
t = make_text(out, "mono")
tstate4=[c+[4] for c in groupcells(t)]
ts4flat = list(itertools.chain.from_iterable(tstate4))
if len(ts4flat)%2==0: ts4flat+=[0]
g.putcells(ts4flat, 0, count*10)
count+=1
g.putcells(finalLH,0,count*10+50)
g.setgen("0")
g.fit()
EDIT: Golly will fail to load the make_text module on a first run, unless the above script is saved in Golly's Scripts/Python directory (I think). Otherwise Python doesn't know where to find the glife module. Because Golly keeps modules loaded after their first use, you can dodge the problem by running another script such as pop-plot.py that loads make_text, and then the above script works fine after that (!).
Please report any remaining bugs. Versions of this script that recognize R, B, C, D, P, and Q inputs have been written. Will post an updated version of the above when they've all been successfully combined into one script...!