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
import itertools

SYMBOLS = {
  '+': 'A',
  '-': 'B',
  ']': 'C',
  '[': 'D',
  '>': 'F',
  '<': 'E',
  '.': 'G',
  ',': 'H',
  }


def _encode(seqs):
    """
    Encode given string into Golly-compatible RLE.
    """
    ret = '$'.join(
      ''.join(
        '{}{}'.format(len(s), s[0]) if len(s) > 1 else ''.join(s)
        for s in (
          list(g)
          for _, g in itertools.groupby(s)
          )
        )
      for s in seqs
      )
    return _encode([ret]) if '$$' in ret else ret.rstrip('$23456789') + '!'


def _offset(n):
    while n >= 0:
        n -= 1
        yield n


def convert(prgm, data=None, inp=None):
    inp, data = inp[::-1] or [], data or []
    prgm = list(map(SYMBOLS.get, filter(SYMBOLS.__contains__, prgm)))
    inp = [j for i in inp for j in (['rS']*i or ['rT']) + ['rU']][:-1] + ['rM']  # rS: 91, rT: 92, rU: 93, rM: 85
    pad = ['.'] * (1 + len(inp))  # + 1 because the input tape ends one cell east of (one cell before) data-tape cell 0
    offset = _offset(max(data) if data else 0)
    data = [
      [*pad, *['.']*off, *i]
      for off, i in
      zip(offset, list(itertools.zip_longest(*map(['qR'].__mul__, data), fillvalue='.'))[::-1])  # qR: 66
      ]
    # header = 'x = {}, y = {}, rule = bf'.format(..., len(data) + 5)
    # ...but we actually don't need to bother calculating dimensions for Golly!
    header = 'x = 0, y = 0, rule = bf'
    rle = [
      *data,
      pad + ['qJ'],                 # Data pointer
      pad + ['.', '.', 'pR'],       # Shadow cell
      inp,
      pad + ['.', '.', 'I'],        # Program-tape pointer
      pad + ['.', '.', '.'] + prgm  # Program tape
      ]
    return '{}\n{}'.format(header, _encode(rle))


if __name__ == '__main__':
    numeric = False
    prgm, inp, data = input('Program tape: '), input('Input tape: '), input('Initial data-tape configuration: ')
    if (inp or data) and all(seq.replace(',', '').isdigit() or not seq for seq in (inp, data)):
        numeric = input(
          '\nWere those just sequences of Unicode/ASCII characters (c), or were they numeric values delimited by commas (n)?\nRespond c/n: '
        ).lower().startswith('n')
    if numeric:
        inp, data = map(list, (map(int, seq.split(',')) if seq else [] for seq in (inp, data)))
    else:
        inp, data = map(list, (map(ord, seq) for seq in (inp, data)))
    print('', convert(prgm, data, inp), sep='\n')