Skip to content

Instantly share code, notes, and snippets.

@vyznev
Last active February 3, 2018 02:41
Show Gist options
  • Save vyznev/92a53d9079b5cdff6308372ccc5aa37a to your computer and use it in GitHub Desktop.
Save vyznev/92a53d9079b5cdff6308372ccc5aa37a to your computer and use it in GitHub Desktop.
Convert isotropic CA rule strings from the 4-cell von Neumann neighborhood to the 8-cell Moore neighborhood
#!/usr/bin/python
neumann2moore = {
"0": {0: "", 1: "c", 2: "cn", 3: "c", 4: "c"},
"1": {1: "e", 2: "ka", 3: "inyq", 4: "ny", 5: "e"},
"2e": {2: "e", 3: "kaj", 4: "kaqw", 5: "kaj", 6: "e"},
"2i": {2: "i", 3: "r", 4: "itz", 5: "r", 6: "i"},
"3": {3: "e", 4: "jr", 5: "inyq", 6: "ka", 7: "e"},
"4": {4: "e", 5: "c", 6: "cn", 7: "c", 8: ""}
}
# the allowed suffix letters for neighbor count n are moore_letters[:letter_counts[n]]
moore_letters = "cekainyqjrtwz"
letter_counts = [0,2,6,10,13,10,6,2,0]
def convert_env(envstr4):
env8 = {}
for match in re.finditer(r'([0-4])(-?)([ei]*)', envstr4):
count = match.group(1)
if count == "2":
negate = bool(match.group(2))
letters = set(match.group(3))
if negate or not letters: letters = set("ei") - letters
else:
letters = [""]
for letter in letters:
for count8, letters8 in neumann2moore[count + letter].items():
if count8 not in env8: env8[count8] = set()
env8[count8] |= set(letters8)
# generate canonical output string
envstr8 = ""
for count, letters in sorted(env8.items()):
complement = set(moore_letters[:letter_counts[count]]) - letters
if len(complement) == 0:
envstr8 += str(count)
elif len(complement) < len(letters):
envstr8 += str(count) + "-" + "".join(sorted(complement))
else:
envstr8 += str(count) + "".join(sorted(letters))
return envstr8
import argparse
parser = argparse.ArgumentParser(description='Convert isotropic CA rule from 4-cell von Neumann to 8-cell Moore neighborhood.')
parser.add_argument('rule', nargs='+', help='input rule (e.g. B024/S1)')
args = parser.parse_args()
import re
import sys
ok = True
for rule in args.rule:
bs = re.match(r'^\s*b((?:[0134]|2-?[ei]*)*)/s((?:[0134]|2-?[ei]*)*)[vn]?\s*$', rule.lower())
if bs:
bs = tuple(convert_env(bs.group(i)) for i in (1,2))
print("B%s/S%s" % bs)
else:
sys.stderr.write("Cannot parse von Neumann rule \"%s\".\n" % rule)
ok = False
if not ok: sys.exit(1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment