The good news about the stamp collections is that they appear to consist of distinct still lifes except for a single error. Namely in the file p1-14-2.rle it looks like 14.266 (ie. 7th row 6th column) should be an appropriately long snake. It's fairly clear that this is a manual error caused by having to special-case still lifes of large height while keeping within the 15x10 grid.
Anyway here is some code. The first script asks for a Niemiec number or an apgcode and then displays the still life and both of its encodings. It only works up to 17 bits and requires the attached file "translate17.txt.gz" to be in the same directory:
Code: Select all
import golly as g
import gzip
chars = "0123456789abcdefghijklmnopqrstuvwxyz"
def decodeCanon(apgcode):
blank = False
x = y = 0
clist = []
for c in apgcode[apgcode.find("_")+1:]:
if blank:
x += chars.index(c)
blank = False
else:
if (c == 'y'):
x += 4
blank = True
elif (c == 'x'):
x += 3
elif (c == 'w'):
x += 2
elif (c == 'z'):
x = 0
y += 5
else:
v = chars.index(c)
for i in range(5):
if v & (1 << i):
clist += [x, y+i]
x += 1
return clist
code = g.getstring("Enter code:")
for s in gzip.open("translate17.txt.gz"):
niemiec, apg = s.split()
if code == apg or code == niemiec:
g.new('')
g.putcells(decodeCanon(apg))
g.show(s)
g.exit()
g.show("Didn't find code")
EDIT 22/11/16: Fixed a bug in this script when the selected SL has close neighbours.
Code: Select all
import golly as g
import gzip
# Obtains a canonical representation of any oscillator/spaceship that (in
# some phase) fits within a 40-by-40 bounding box. This representation is
# alphanumeric and lowercase, and so much more compact than RLE. Compare:
#
# Common name: pentadecathlon
# Canonical representation: 4r4z4r4
# Equivalent RLE: 2bo4bo$2ob4ob2o$2bo4bo!
#
# It is a generalisation of a notation created by Allan Weschler in 1992.
def canonise():
representation = "#"
if g.getselrect():
g.shrink()
rect = g.getselrect()
else:
rect = g.getrect()
if len(rect) == 0:
return "0"
if ((rect[2] <= 40) & (rect[3] <= 40)):
# Fits within a 40-by-40 bounding box, so eligible to be canonised.
# Choose the orientation which results in the smallest description:
representation = compare_representations(representation, canonise_orientation(rect[2], rect[3], rect[0], rect[1], 1, 0, 0, 1))
representation = compare_representations(representation, canonise_orientation(rect[2], rect[3], rect[0]+rect[2]-1, rect[1], -1, 0, 0, 1))
representation = compare_representations(representation, canonise_orientation(rect[2], rect[3], rect[0], rect[1]+rect[3]-1, 1, 0, 0, -1))
representation = compare_representations(representation, canonise_orientation(rect[2], rect[3], rect[0]+rect[2]-1, rect[1]+rect[3]-1, -1, 0, 0, -1))
representation = compare_representations(representation, canonise_orientation(rect[3], rect[2], rect[0], rect[1], 0, 1, 1, 0))
representation = compare_representations(representation, canonise_orientation(rect[3], rect[2], rect[0]+rect[2]-1, rect[1], 0, -1, 1, 0))
representation = compare_representations(representation, canonise_orientation(rect[3], rect[2], rect[0], rect[1]+rect[3]-1, 0, 1, -1, 0))
representation = compare_representations(representation, canonise_orientation(rect[3], rect[2], rect[0]+rect[2]-1, rect[1]+rect[3]-1, 0, -1, -1, 0))
return "xs%d_%s" % (len(g.getcells(rect)) // 2, representation)
# A subroutine used by canonise:
def canonise_orientation(length, breadth, ox, oy, a, b, c, d):
representation = ""
chars = "0123456789abcdefghijklmnopqrstuvwxyz"
for v in xrange(0, breadth, 5):
zeroes = 0
if (v != 0):
representation += "z"
for u in xrange(length):
baudot = 0
for w in xrange(v, v+5):
x = ox + a*u + b*w
y = oy + c*u + d*w
baudot = (baudot >> 1)
if w < breadth: baudot += 16*g.getcell(x, y)
if (baudot == 0):
zeroes += 1
else:
if (zeroes > 0):
if (zeroes == 1):
representation += "0"
elif (zeroes == 2):
representation += "w"
elif (zeroes == 3):
representation += "x"
else:
representation += "y"
representation += chars[zeroes - 4]
zeroes = 0
representation += chars[baudot]
return representation
# Compares strings first by length, then by lexicographical ordering.
# A hash character is worse than anything else.
def compare_representations(a, b):
if (a == "#"):
return b
elif (b == "#"):
return a
elif (len(a) < len(b)):
return a
elif (len(b) < len(a)):
return b
elif (a < b):
return a
else:
return b
apgcode = canonise()
for s in gzip.open("translate17.txt.gz"):
niemiec, apg = s.split()
if apgcode == apg:
g.show(s)
g.exit()
g.show("?? " + apgcode)
EDIT 22/11/16: The attachment translate17.txt.gz has been updated due to a bug when canonicalising closely separated still lifes.