Skip to content

Instantly share code, notes, and snippets.

@vyznev
Last active February 4, 2019 01:04
Show Gist options
  • Save vyznev/7f1a08b5804a073314a0d8fd72f9d944 to your computer and use it in GitHub Desktop.
Save vyznev/7f1a08b5804a073314a0d8fd72f9d944 to your computer and use it in GitHub Desktop.
Golly script for loading apgcodes as patterns
#! /usr/bin/python
# apgdecode.py v0.2
# A script for loading apgcodes (http://conwaylife.com/wiki/Apgcode) as Golly (http://golly.sourceforge.net/) patterns.
# Supports extended and multistate apgcodes. (Multistate handling may still have bugs. Let me know if you find any.)
# Copyright 2019 Ilmari Karonen. Released under the WTFPL (http://www.wtfpl.net/).
import golly as g
import re
apgcode = g.getstring("Enter apgcode:", "xq4_153").strip()
if not re.match(r'^x[spq][1-9][0-9]*(_([0-9a-xz]|y[0-9a-z])*)+$', apgcode):
g.exit("Invalid or unsupported apgcode \"%s\". (The only supported prefixes are xs, xp and xq.)" % apgcode)
def wechsler_decode(c, end='z'):
if '0' <= c <= '9':
return ord(c) - ord('0')
elif 'a' <= c <= end:
return ord(c) - ord('a') + 10
else:
g.exit("Invalid symbol \"%s\" in apgcode!" % c)
cells = {}
bitplane = 0
for layer in apgcode.split('_')[1:]:
row = 0
col = 0
for c in (m.group(0) for m in re.finditer(r'y?.', layer)):
if c == 'z':
row += 5
col = 0
elif len(c) == 2 and 'y0' <= c <= 'yz':
col += wechsler_decode(c[1], 'z') + 4
elif 'w' <= c <= 'x':
col += ord(c) - ord('w') + 2
else:
bits = wechsler_decode(c, end='v')
for i in range(5):
if (bits >> i) & 1:
pos = (col, row + i)
if pos not in cells: cells[pos] = 0
cells[pos] |= (1 << bitplane)
col += 1
bitplane += 1
# undo weird state encoding for Generations rules (http://www.conwaylife.com/forums/viewtopic.php?t=&p=49793#p49793)
if g.getalgo() == 'Generations':
maxstate = g.numstates() - 1
for pos in cells:
state = cells[pos]
if state > 1:
if state % 4 != 2:
g.exit("Unexpected state %d at (%d,%d); all states > 1 should be of the form 4n+2." % (state, pos[0], pos[1]))
cells[pos] = maxstate - (state - 2) // 4
def dict_to_cell_list(cells):
for x,y in cells:
yield x
yield y
yield cells[(x,y)]
if len(cells) % 2 == 0:
yield 0
cell_list = list(dict_to_cell_list(cells))
g.show(str(cells))
# TODO: find a less destructive way to load the pattern?
g.new(apgcode)
g.putcells(cell_list)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment