snippetpythonMinor
Parse Run Length Encoded file for cellular automaton data
Viewed 0 times
filelengthcellularencodedparsefordataautomatonrun
Problem
I wanted to be able to parse Run Length Encoded
Here is my
The console output of the file is as follows. I left out the output from
```
name: Gosper glider gun
comments:
['This was the first gun discovered.',
'As its name suggests, it was discovered by Bill Gosper.']
author: Bill Gosper Nov. 1970
size_x: 36
size_y: 9
rule_birth: [3]
rule_survival: [2, 3]
pattern_raw: 24bo$22bobo$12b2o6b2o12b2o$11bo3bo4b2o12b2o$2o8bo5bo3b2o$2o8bo3bob2o4bobo$10bo5bo7bo$11bo3bo$12b2o!
human_friendly_pattern:
........................o...........
......................o.o...........
............oo......
(*.rle) files into something usable for a cellular automaton simulator (e.g. Conway's Game of Life and such). Here is my
main method which has the code I used for manual testing. The example file is taken from the above linked wiki.def main():
sample_rle = \
"""#N Gosper glider gun
#C This was the first gun discovered.
#C As its name suggests, it was discovered by Bill Gosper.
#O Bill Gosper Nov. 1970
x = 36, y = 9, rule = B3/S23
24bo$22bobo$12b2o6b2o12b2o$11bo3bo4b2o12b2o$2o8bo5bo3b2o$2o8bo3bob2o4b
obo$10bo5bo7bo$11bo3bo$12b2o! """
rle_parser = RunLengthEncodedParser(sample_rle)
print("name:", rle_parser.get_name())
print("comments:")
pprint.pprint(rle_parser.get_comments())
print("author:", rle_parser.get_author())
print("size_x:", rle_parser.get_size_x())
print("size_y:", rle_parser.get_size_y())
print("rule_birth:", rle_parser.get_rule_birth())
print("rule_survival:", rle_parser.get_rule_survival())
print("pattern_raw:", rle_parser.get_pattern_raw())
#print("pattern_2d_array:")
#print(rle_parser.get_pattern_2d_array())
print("human_friendly_pattern:")
print(rle_parser.get_human_friendly_pattern())The console output of the file is as follows. I left out the output from
print(rle_parser.get_pattern_2d_array()) as it is just a 2D list of b (dead) and o (alive) cells. For the sake of human readability, I replaced b dead cells with dots in the return from get_human_friendly_pattern.```
name: Gosper glider gun
comments:
['This was the first gun discovered.',
'As its name suggests, it was discovered by Bill Gosper.']
author: Bill Gosper Nov. 1970
size_x: 36
size_y: 9
rule_birth: [3]
rule_survival: [2, 3]
pattern_raw: 24bo$22bobo$12b2o6b2o12b2o$11bo3bo4b2o12b2o$2o8bo5bo3b2o$2o8bo3bob2o4bobo$10bo5bo7bo$11bo3bo$12b2o!
human_friendly_pattern:
........................o...........
......................o.o...........
............oo......
Solution
Apart from @Graipher's great answer (my answer is based on his), I'd use the following when it comes to multi-line styling:
For me, the trade-off of using
I also added the
from pprint import pformat
class RunLengthEncodedParser:
"""
Parser for Run Length Encode (RLE) strings / files.
More information: http://www.conwaylife.com/w/index.php?title=Run_Length_Encoded
"""
def __init__(self, rle_string):
self.rle_string = rle_string
self.name = ""
self._comments = [] # Note underscore
self.author = ""
self.size_x = 0
self.size_y = 0
self.rule_birth = []
self.rule_survival = []
self.pattern_raw = ""
# Fill in instance attributes by parsing the raw strings
self.populate_attributes(self.rle_string.strip().splitlines())
self.pattern_2d_array = self.populate_pattern(self.pattern_raw, self.size_x, self.size_y)
def populate_attributes(self, lines):
...
def populate_pattern(self, pattern_raw, size_x, size_y, default_cell='b'):
...
def isdigit(self, c):
"""Returns True is the character is a digit"""
return '0' <= c <= '9'
def __str__(self):
return self.rle_string
def __format__(self, fmt):
return 'name: {self.name}\n' \
'comments: {self.comments}\n' \
'author: {self.author}\n' \
'size_x: {self.size_x}\n' \
'size_y: {self.size_y}\n' \
'rule_birth: {self.rule_birth}\n' \
'rule_survival: {self.rule_survivor}\n' \
'pattern_raw: {self.pattern_raw}\n' \
'human_friendly_pattern: {self.human_friendly_pattern}\n'.format(self=self)
@property
def human_friendly_pattern(self):
pattern_str = ""
for row in self.pattern_2d_array:
row_str = ""
for c in row:
if c == 'b':
row_str += '.'
else:
row_str += c
pattern_str += row_str + '\n'
return pattern_str
@property
def comments(self):
return pformat(self._comments)
def main():
sample_rle = '#N Gosper glider gun\n' \
'#C This was the first gun discovered.\n' \
'#C This was the first gun discovered.\n' \
'#C As its name suggests, it was discovered by Bill Gosper.\n' \
'#O Bill Gosper Nov. 1970\n' \
'x = 36, y = 9, rule = B3/S23\n' \
'24bo$22bobo$12b2o6b2o12b2o$11bo3bo4b2o12b2o$2o8bo5bo3b2o$2o8bo3bob2o4b\n' \
'obo$10bo5bo7bo$11bo3bo$12b2o!\n'
rle_parser = RunLengthEncodedParser(sample_rle)
print(format(rle_parser))
if __name__ == '__main__':
main()For me, the trade-off of using
\n and \ to gain the correct indentation makes sense + makes those snippets look clear.I also added the
from pprint import pformat at the top of the code.Code Snippets
from pprint import pformat
class RunLengthEncodedParser:
"""
Parser for Run Length Encode (RLE) strings / files.
More information: http://www.conwaylife.com/w/index.php?title=Run_Length_Encoded
"""
def __init__(self, rle_string):
self.rle_string = rle_string
self.name = ""
self._comments = [] # Note underscore
self.author = ""
self.size_x = 0
self.size_y = 0
self.rule_birth = []
self.rule_survival = []
self.pattern_raw = ""
# Fill in instance attributes by parsing the raw strings
self.populate_attributes(self.rle_string.strip().splitlines())
self.pattern_2d_array = self.populate_pattern(self.pattern_raw, self.size_x, self.size_y)
def populate_attributes(self, lines):
...
def populate_pattern(self, pattern_raw, size_x, size_y, default_cell='b'):
...
def isdigit(self, c):
"""Returns True is the character is a digit"""
return '0' <= c <= '9'
def __str__(self):
return self.rle_string
def __format__(self, fmt):
return 'name: {self.name}\n' \
'comments: {self.comments}\n' \
'author: {self.author}\n' \
'size_x: {self.size_x}\n' \
'size_y: {self.size_y}\n' \
'rule_birth: {self.rule_birth}\n' \
'rule_survival: {self.rule_survivor}\n' \
'pattern_raw: {self.pattern_raw}\n' \
'human_friendly_pattern: {self.human_friendly_pattern}\n'.format(self=self)
@property
def human_friendly_pattern(self):
pattern_str = ""
for row in self.pattern_2d_array:
row_str = ""
for c in row:
if c == 'b':
row_str += '.'
else:
row_str += c
pattern_str += row_str + '\n'
return pattern_str
@property
def comments(self):
return pformat(self._comments)
def main():
sample_rle = '#N Gosper glider gun\n' \
'#C This was the first gun discovered.\n' \
'#C This was the first gun discovered.\n' \
'#C As its name suggests, it was discovered by Bill Gosper.\n' \
'#O Bill Gosper Nov. 1970\n' \
'x = 36, y = 9, rule = B3/S23\n' \
'24bo$22bobo$12b2o6b2o12b2o$11bo3bo4b2o12b2o$2o8bo5bo3b2o$2o8bo3bob2o4b\n' \
'obo$10bo5bo7bo$11bo3bo$12b2o!\n'
rle_parser = RunLengthEncodedParser(sample_rle)
print(format(rle_parser))
if __name__ == '__main__':
main()Context
StackExchange Code Review Q#149068, answer score: 5
Revisions (0)
No revisions yet.