Files
  • main.py
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import sys
from os import path

N_HOODS = 'cekainyqjrtwz'
NAPKINS = {
  k: dict(zip(N_HOODS, v)) for k, v in {
    '0': '',
    '1': ['00000001', '10000000'],
    '2': ['01000001', '10000010', '00100001', '10000001', '10001000', '00010001'],
    '3': ['01000101', '10100010', '00101001', '10000011', '11000001', '01100001', '01001001', '10010001', '10100001', '10001001'],
    '4': ['01010101', '10101010', '01001011', '11100001', '01100011', '11000101', '01100101', '10010011', '10101001', '10100011', '11001001', '10110001', '10011001'],
    '5': ['10111010', '01011101', '11010110', '01111100', '00111110', '10011110', '10110110', '01101110', '01011110', '01110110'],
    '6': ['10111110', '01111101', '11011110', '01111110', '01110111', '11101110'],
    '7': ['11111110', '01111111'],
    '8': ''
    }.items()
  }


def order_segment(sz, segment):
    if not segment or segment[0] == '-':
        return [t for t in N_HOODS[:sz] if t not in segment]
    return [t for t in N_HOODS if t in segment]


def combine_rstring(segment):
    cop = {}
    for i, v in enumerate(segment, 1):
        if v.isdigit():
            after = next((idx for idx, j in enumerate(segment[i:], i) if j.isdigit()), len(segment))
            cop[v] = order_segment(len(NAPKINS[v]), segment[i:after])
    return cop


def replace_bind(transition, pre, sub='', count=0):
    cop = []
    for i in map(int, transition):
        if not i:
            cop.append(0)
            continue
        cop.append('{}{}_{}'.format(pre, sub, count))
        count += 1
    return cop


def print_table(rname, n_states, n_live, d_vars, transitions):
    print('@RULE {}\[email protected]\n'.format(rname))
    print('n_states:{}\nneighborhood:Moore\nsymmetries:rotate4reflect\n'.format(n_states))
    # Variables
    live = range(1, n_states)
    for sub, (state, count) in d_vars.items():
        range_ = {i for i in live if i != state}
        if not range_:
            continue
        print('var not_{}_0 = {}'.format(sub, range_))
        for n in range(1, count):
            print('var not_{0}_{1} = not_{0}_0'.format(sub, n))
    print('var any_0 = {}'.format(set(range(n_states))))
    for n in range(9):
        print('var any_{} = any_0'.format(n))
    print('var live_0 = {}'.format(set(live)))
    for n in range(1, n_live):
        print('var live_{} = live_0'.format(n))
    print()
    # Transitions
    for tr in transitions:
        print(','.join(map(str, tr)))


transitions = []
rulestring = input('B/S rulestring: ')
PERM = 'y' == input('Permanent deficiency? (y/n): ').lower()[0]
rulename = rulestring.translate(str.maketrans('/bs', '_BS')) + ('_deficient', '_pdeficient')[PERM]
rulename = input("Rulename (leave blank for {}): ".format(rulename)) or rulename

try:
    # Get rid of B and S from the start of each segment
    (_, *birth), (_, *survival) = map(str.strip, rulestring.split('/'))
except ValueError:
    print()
    raise ValueError('Rulestring is not in B/S form')
birth, survival = combine_rstring(birth), combine_rstring(survival)
n_live, sum_len = 0, 2
for counter, (num, subs) in enumerate(birth.items()):
    if num == '0':
        transitions.append([*[0]*9, 1])
    elif num == '8':
        transitions.append([0, *('live_{}'.format(i) for i in range(8)), 1])
        n_live = 8
    else:
        transitions.extend([0, *replace_bind(NAPKINS[num][sub], 'not_', num+sub), idx] for idx, sub in enumerate(subs, sum_len))
        sum_len = 1 + transitions[-1][-1]
d_vars = {k: (tr[-1], sum(1 for i in tr if isinstance(i, str))) for k, tr in zip((n+j for n, li in birth.items() for j in N_HOODS[:len(NAPKINS[n])] if not li or j in li), transitions)}
transitions.append('')

END = 'live_0' if PERM else 1  # Bind if rule is to be 'permanently deficient'
for num, subs in survival.items():
    if num == '0':
        transitions.append(['live_0', *[0]*8, END])
    elif num == '8':
        transitions.append([*('live_{}'.format(i) for i in range(9)), END])
        n_live = 9
    else:
        transitions.extend(['live_0', *replace_bind(NAPKINS[num][sub], 'live', count=1), END] for sub in subs)

n_live = n_live if not survival else max(n_live, *(sum(1 for i in tr if isinstance(i, str)) for tr in transitions[1+transitions.index(''):]))
n_states = 1 + max(t[-1] for t in transitions if t and isinstance(t[-1], int))
transitions.append([*('any_{}'.format(i) for i in range(9)), 0])

print()
print_table(rulename, n_states, n_live, d_vars, transitions)