Proposal: Recursive RLE

For general discussion about Conway's Game of Life.
Post Reply
igblan
Posts: 28
Joined: September 13th, 2009, 9:42 am

Proposal: Recursive RLE

Post by igblan » September 13th, 2009, 11:07 am

I have been experimenting (in Python) with an extension to RLE which allows the definition and reuse of subpatterns, including the transformation and evolution of subpatterns, and nested subpatterns.

For the formalists, here is the BNF:

Code: Select all

rle = pattern '!'
pattern = [ unit ]...
unit = run | subpattern
run = [ integer ] ( state | '$' )
state = 'b' | 'o'
subpattern = '@' ( definition | name ) [ evolution ] transformation
definition = name '=' pattern
evolution = '+' integer
transformation = '.' | '<' | '^' | '>' | '-' | '\' | '|' | '/'
integer = ( digit )...
id = ( letter | digit )...
letter = 'A' | ... | 'Z' | 'a' | ... | 'z' | '_'
digit = '0' | ... | '9'
(The above is for Life patterns; the idea can be extended to other rules, including rules with more than two states, by extending state in the usual way.)

A subpattern is delimited by @ on the left and a transformation on the right.

The transformations are the four rotations (including the identity rotation) and the four reflections, as follows:

Code: Select all

. - Identity
< - Rotate 90 degrees clockwise
^ - Rotate 180 degrees
> - Rotate 90 degrees anticlockwise
- - Reflect in a horizontal line
\ - Relfect in a leading-diagonal line
| - Relfect in a vertical line
/ - Reflect in a skew-diagonal line
The visual scheme here is that . should be thought of as a v, and <, ^ and > are rotations of it, and each of the four reflections is indicated by its line of symmetry.

Subpatterns are defined in a "local raster", ie such that a $ in a subpattern aligns with the top-left corner of the subpattern. Transformations are performed "in place", ie roughly relative to the "centre" of the subpattern. (I'll write this up in more detail if anyone shows interest.)

An evolution, if present, is performed after the transformation for the purposes of transforming "in place".

Both subpattern definitions and subpattern references are included at the current place in the enclosing pattern, with the given evolution and transformation. A subpattern definition or reference does not increment the raster pointer in the enclosing pattern.

A subpattern name may be any mixture of letters, digits and _, including a simple integer (although 01 and 1 would be different names).

It seems to me that the main advantages of extending RLE in this way, rather than extending file formats to included additional "command" lines, are that (1) the parser for the above is relatively trivial, (2) the format is in the spirit of RLE: not very human-readable, but very compact, and (3) very large patterns like the Caterpillar could be jammed into relatively small files.

What isn't trivial is a general-purpose pattern-to-RLE converter. It is expected that patterns generated with software assistance, like the MRM or the Caterpillar, could generate fairly efficient RLE strings.

I'll try to include some examples in a future post.

Cheers, Paul (Chapman)

User avatar
PM 2Ring
Posts: 152
Joined: March 26th, 2009, 11:18 am

Re: Proposal: Recursive RLE

Post by PM 2Ring » September 13th, 2009, 12:16 pm

Interesting! I'd love to see some examples. And your Python code. :)
What isn't trivial is a general-purpose pattern-to-RLE converter. It is expected that patterns generated with software assistance, like the MRM or the Caterpillar, could generate fairly efficient RLE strings.
Yes, the general converter is hard. I've been thinking about efficient ways to search a pattern for useful sub-patterns. I have a few ideas, but haven't bothered testing them yet.

An altenative approach for patterns generated with software assistance is to simply output Python code in a compressed form that can unpack itself. I used that approach in my latest bitmap printer.

Here's a sample output script:

Code: Select all

#Golly Python script
import zlib,base64,golly
from glife import *
exec compile(zlib.decompress(base64.decodestring('''
eJytVktv2zgQvutXEIUKU4mciKTkR4BcCuytu5fuoYVhLKxYcejKpiErSPzvd2ZISZRfzS5qJDI5
883wmwdHznW9Z49skAghkqufTh2L3vYDYJSgf/uw+mYtWm0LtghhH6JZJp1t8mFw4sKKW5iH8JEN
TQI7Ph5FZ9pF0SYsvp62fqZ+Ae7X4AL4fKE8sBfKhSqdgo+WV8EuByI50zSXaZyhcwUsTlxf93yF
BrlqOy+56vnkjGuef/35P+AzoV8B/yfP7QHUz82lEX0vHo32cjVXtrlf5z13V+x3g73y0fIYPAiY
+wTL4pmVeltsFj+LipfG7DbRA6m//gmDbreo66La8sFgoNJcmhCeJpQZLLPc4DLNlcFtKGRuJiBz
y9yMciMRYYTAbUa6wO1BMwZLKQivEDCFpduTPX1N0YNCoZTwHIUpmoWBRDYyyY2yJMDrlM4I05EV
WiA9szCd0iZFlSSOKboLUrdTGMII/lWeuZ1IaCvNOExtvGiVUVx4iDIp+YSYAxBBhiKXt7/NDlIH
+bvt8icpBLCkpJlBzJSM2bgx+bLYF/10Y5JC4EAPZYRs0qBsbhL8wsSFU8omZYdWgs6aEOXAUFHA
mcJjUwqp+6P8YqwZsRqRjUKJtBkwVNQAYzXtUchDjK3hyGMj0VaSMRS3QYZqakWBInFOLKgWkpKJ
R8MXeJTIFatpmiaTocJ0KwtTSDAYh8p6CpXM06YPx/YQSU5spI2QOs6JxMgVOkDO41aE1FGSNl0t
m631Yp9Ql5iJNGZy2qvcLZabZ1nMUqjqc6l3ESN9VdSv1db2BJ9AQ9ANi9lQCja0mwik1k1At3Gz
0Fu+Wx5i9mR2utjHrNZ1WbS3cv8es93yHboFjhOZky5BCs8DiIeIYTcIQuSBEPkGNLOZ3tZ8HbFn
U7E101um57TWuM7ht83dflfqmg/iQTQnu5Upy8PdtnjjloUn3Bd19VoW/NMXdf9Nqk+RO+il0KuX
OobVm17WL3BuWWx5volit5glc4vd6CVoeWMCiRARu79nkrSYnTert46GbELqtFVjUJiLGwu25JKY
rYR/mewUCrF+wKEVGyc27uKuSr0sKvx5N7M+8J/DCkpaPT29ge0q6e3bMQpySXIqPdmd2Sdo59x0
W5fnFZ5r1wbqZrCSCiosFcnair1Xi+2q4DY5mLCHlsVy2aZj3VFbYXfOXHCQem7ewW65pDOGsEBC
TiucduIjxhZludEZlPrgjHc552nmbNNj52rO1dgph8p32gYsR94VSZsb8lsTkFKIwya82z7HzGkn
PsKS/lACRnMuRngtPZ/jOZc4MqTzsFtUuqZob7gXxg22VoLTgEPnicg2JU6E/FWXS5gvXqQrtPN6
PGo1x3lyl8ezxc96jRdrjVEWZb2AQ7tLBnfwc7PtGWmgsplpPZ+t13P2+Ogima3nD+zoExwLLGFI
1WoFeA/AYfaVi+1PoECY6G73WvOvOM5gBNYQxN4G18xbAj+e/GghNcFBCYnfwrw6tJ2jvYzA1PGy
oTXgcRANGddUiE5lnOr2RGX54UkGms2OX/BEy0PXj5TbR+YGsjatpi1pjzZOi38uko7b2XpMX/cp
I1d5hSr+LukRxtjk5DJtbIoL1IsF9N+3P3rjFmdqaN+jNHM74F8IdCbY7iKJXdAO9ANfa9POALPC
nSkaFD/gYnkOYO8sv5++SVy0UFj7JgVBr8vpFdl0FjkQYAgLfAWB1uZwUZYnF+24OmcKg2a3Ltj9
TMOV4oLe9JDTzwxmAS++QwlcBaLmKOr+qCHVvmh3Zs/3dcWHdro1YRDRWy/uYRc3JAotvh7u72Xk
v7ef4QV/9B5/eq32puIqCv4FVOElCQ==
''')),'<string>','exec')
main(16, 1, 'ConwaysLifeForum-printer')
It would be trivial to add an option to make such scripts display themselves in uncompressed form.

User avatar
Andrew
Moderator
Posts: 919
Joined: June 2nd, 2009, 2:08 am
Location: Melbourne, Australia
Contact:

Re: Proposal: Recursive RLE

Post by Andrew » September 13th, 2009, 7:26 pm

Hi Paul, and welcome to the forums!
igblan wrote:I have been experimenting (in Python) with an extension to RLE which allows the definition and reuse of subpatterns, including the transformation and evolution of subpatterns, and nested subpatterns. ...
An interesting extension, with what looks like a very nice, clean syntax. But I must admit my first reaction is, why bother? Why not just write (or auto-generate) a Python script? One of the main reasons for adding Python support to Golly was to allow exactly the sort of things you mention above. I am of course guilty of seeing Golly's scripting capabilities as the answer to all of Life's problems. :wink:
It seems to me that the main advantages of extending RLE in this way, rather than extending file formats to included additional "command" lines, are that ... (3) very large patterns like the Caterpillar could be jammed into relatively small files.
Ditto for a Python script. I'd love to see a Python script that creates the Caterpillar. I'm guessing the size of such a script might come in around 100K. It would probably be rather slow (certainly slower than if Golly could read a file in your extended RLE syntax), but that might not be such a drawback -- it would be fun to watch the script construct the Caterpillar piece by piece.

Anyway, don't let me put you off. Keep experimenting!
Use Glu to explore CA rules on non-periodic tilings: DominoLife and HatLife

User avatar
Andrew
Moderator
Posts: 919
Joined: June 2nd, 2009, 2:08 am
Location: Melbourne, Australia
Contact:

Re: Proposal: Recursive RLE

Post by Andrew » September 13th, 2009, 7:44 pm

PM 2Ring wrote:It would be trivial to add an option to make such scripts display themselves in uncompressed form.
Please do that -- it would allow people to fix problems. Your script causes an error in Golly 2.1 (and probably other versions). I suspect it's because it has a setcursor(int) call near the end -- at some point I changed the syntax to setcursor(string). You can write code that works in all versions by doing things like this:

Code: Select all

import golly
try:
   golly.setcursor("Move")
except:
   # old version
   golly.setcursor(3)
Untested, but I think it should work.
Use Glu to explore CA rules on non-periodic tilings: DominoLife and HatLife

User avatar
PM 2Ring
Posts: 152
Joined: March 26th, 2009, 11:18 am

Re: Proposal: Recursive RLE

Post by PM 2Ring » September 14th, 2009, 7:37 am

Sorry about this slight thread hijack, igblan. I hope you don't mind.

I guess one big advantage your scheme has over a Python script is that it's not dependant on a particular Life program, and a standalone translator could convert it to the original RLE format, or other formats, if required. And Python scripts have the disadvantage that the application programmer may decide to change the interface on you, breaking all your old scripts. :)
Andrew wrote:
PM 2Ring wrote:It would be trivial to add an option to make such scripts display themselves in uncompressed form.
Please do that -- it would allow people to fix problems. Your script causes an error in Golly 2.1 (and probably other versions). I suspect it's because it has a setcursor(int) call near the end -- at some point I changed the syntax to setcursor(string). You can write code that works in all versions by doing things like this:

Code: Select all

import golly
try:
   golly.setcursor("Move")
except:
   # old version
   golly.setcursor(3)
Untested, but I think it should work.
Oh. Thanks, Andrew. Good guess, BTW. I won't add that code to the current version - I hate releasing software I can't test. So in the meantime, I've just commented the setcursor() call out. But next time you do something like this, please consider the option of allowing old-style parameters where practical.

Here's the new version of the above compressed script. If you run it from within Golly it executes itself, but if you run it from the shell it prints itself in a form that can be fed to Golly. I'll post the new generating script in the Golly Scripts thread, and I'll also post the "straight" version of the script, so that people can read the comments if they so desire.

Code: Select all

#Golly Python script
import zlib,base64
s=zlib.decompress(base64.decodestring('''
eJytVttu2zgQfddXEK0KU4nciKR8C5CXLnb7kl0s0D60MIyFFcsOXdkUJAWJ/35nhtTNdtzsokar
kDNnhmcuHOn9Z5NlB/b3oXo0e1Y+FDqvPL3LTVGxDaq8dWF2bJPpdcqc/MpLdFWyOzaIhBDRxV+r
DkVv+wYwStC/fVh9vRaNtgFbhLAPUS+j1jZ6MzhyYYUNrIPoImuaBHZ8OhSdaRtFk7Dwctr6mfoJ
uF+DV8DnC9UBd0J5pUqn4KPlRbDLgYjONM3rNM7QuQAWJ64ve75Ag1w1nRdd9HxyxiXPP//9H/CZ
0C+A/5Pn5gDq5/rSiL6XDo3mctVXtr5f5z23V+xXgzvlo+UxeOAx9/NW6Zplep/ulj/SgmfG5Lvg
ltT3f8Kgy5dVlRZ7PhgMVJxI48PT+HIEy1FicBknyuDWFzIxU5C5ZWLGiZGIMELgdkQ6z+1BMwFL
KQivEDCDpduTPf2ZoQeFQinhOfZjNPM9iWxklBhlSYDXGZ3hx2MrtEB6jvx4RpsYVZI4xujOi91O
YQhj+K+SkduJiLbSTPzYxotWI4oLD1EmJp8QswciyFDg8vbV5JA6yN91mz9JIYAlJc0MQqZkyCa1
yadlmfbTjUnygQM9lBGyToOyuYnwDybOn1E2KTu0EnTWlCh7hooCzhQeG1NI7T/KL8Y6IlZjslEo
kTYDhorqYaymOQp5iIk1HHfYSLSVZAzFrZG+mlmRp0icEAuqhaRk4tHwBzxK5IrVNHWTSV9hupWF
KSToTXxlPflKJnHdhxN7iCQnNtJaSB3nRGLsCu0h50kjQuooieuulvXWerFPqEvIRBwyOetV7hrL
zUejkMVQ1XWm84CRvkirp2Jve4JPoSHohoVsKAUb2k0AUuvGo9u4W+o9z1eHkD2YXKdlyCpdZWlz
K8uXkOWrF+gWOE6MnHQFUngeQDxEDLtCECIPhEh2oJnP9b7i24CtTcG2TO+ZXtBa4xq/bT6WeaYr
PggHwYLs6FPo4z595pZFR1imVfGUpfzdJ3XzRap3gTvoMdWbxyqE1bNeVY9wbpbuebILQreYRwuL
3ekVaHltAokQAbu5YZK0mJ1nq7eOhmxK6rhRY1CYiysLtuSikG1E9zLZKeRj/YBDIzZObNzFhU+9
VVrg593c+sD/HFZQ0uLh4RlsN1Fv34xRkEuSU+nJ7sw+Qjvnpt26PG/wXLs2UDeDlVRQYalI1lTs
pVjuNym3ycGE3TYsVqsmHduW2ga7c+6Cg9Rz8wJ2qxWdMYQFEnJa4bTTLmJiUZYbnUGp9854lwse
j5xtfOxcLbiaOOVQdZ02Actx54rE9Q35pQmIKcRhHd51n+PIaaddhCX9pgSMF1yM8Vp2fE4WXOLI
kM5Dvix0RdFe8U4YV9haEU4DDp0nAtuUOBGSJ52tYL50It2gXafHg0ZznCd3eTq2+Ntu8WJtMco0
q5ZwaHvJ4A5+qLc9Iw1UdnOtF/PtdsHu7lwk8+3ilh39vGOBJQyp2mwA3wFwmH3Zcv8DKBAm+Jg/
VfwexxmMwAqCKG1w9bwl8N3JRwupCQ5KSPwe5tWh6RzdyQhMnU42tAY8DqIh45oK0aqMU12fqCw/
PMlAs9nxC55oeWj7kXJ7x9xA1qbRNCXt0cZp8c+rpMNmth7T133KyFVeoIrfJT3CGJucvk4bm+IV
6ukS+u/L771xizPVt+9Rmrkt8C8EOhNsdxGFLmgH+o6vtVlrgFnhzhQN0u9wsToOYO8sv52+SVy0
UFj7JgVBr8vpFVl3FjkQYAgLfAWB1uZwmWUnF+24OmcKg2bXLthyruFKcUFvesjpBwazgKffoASu
AkF9FHV/UJNqXrS5KXlZFXxop1sdBhG97sQ9bOOGRKHF/eHmRgbd9/YaXvB2/77x//BUlKbgKvDo
84NmWMgGv5n98/JQ3ut1+ocpnnZfh3kBnxBpMQj+BbBCRfM=
'''))
try:import golly
except ImportError:print s
else:    
 from glife import *
 exec compile(s,'<string>','exec')
 main(16, 1, 'ConwaysLifeForum-printer2')
I'm so glad you're here to answer our Golly questions, but your good advice tends to get scattered around the place. Maybe we should have a dedicated Golly Q&A thread?

igblan
Posts: 28
Joined: September 13th, 2009, 9:42 am

Re: Proposal: Recursive RLE

Post by igblan » September 14th, 2009, 10:31 am

Hi Paul, and welcome to the forums!
Thanks!
Your script causes an error in Golly 2.1 (and probably other versions).
Aye, there's the rub! RLE has lasted decades thanks to its independence from programming languages and Life implementations. And it is very easy to implement.

Here is my current Python (2.6) module for reading recursive RLE (and writing old-style RLE). The aforementioned "in place" transformation is effectively performed by the adjustment in the last line of _Reader()._xform(); note that it works relative to the origin of the subpattern's raster rather than the top-left corner of the its bounding rectangle, although these are the same if there are no blank rows or columns to the left of or above the subpattern, which I would describe as good style.

I have chosen here a native Python representation of Life patterns compatible with Golly, ie a flat list of co-ordinates [x0, y0, x1, y1, ...]. However, this module is independent of Golly. It would be a simple job to rewrite the module to work directly with Golly.

Code: Select all

import re

class _Writer(object):

    def _addrun(self, n, c):
         self.rle += (str(n) if n != 1 else "") + c
         
    def _addlives(self):
        if self._lives > 0:
            self._addrun(self._lives, "o")
            self._lives = 0
        
    def __init__(self, cells):

        self.rle = ""
        self._lives = 0
        
        points = [(cells[i + 1], cells[i]) for i in xrange(0, len(cells), 2)]
        points.sort()

        xc = yc = 0
        
        for y, x in points:
            if y > yc:
                self._addlives()
                self._addrun(y - yc, "$")
                xc, yc = 0, y
            if x > xc:
                self._addlives()
                self._addrun(x - xc, "b")
                xc = x
            self._lives += 1
            xc += 1
            
        self._addlives()
        self.rle += "!"


class _Reader(object):

    _REP = re.compile(r"""
        ( \d*[bo\$]  # old-style run
        | \@\w+      # name
        | \+\d+      # evolve
        | . )        # delimeter
        """, re.VERBOSE)
    
    _ID_CHAR = "."
    _XFORM_CHARS = _ID_CHAR + r"<^>/-\|"
    _TERMINATOR_CHARS = _XFORM_CHARS + "+"

    _MATRICES = {
        _ID_CHAR: ( 1,  0,  0,  1),
             ">": ( 0,  1, -1,  0),
             "^": (-1,  0,  0, -1),
             "<": ( 0, -1,  1,  0),
             "|": (-1,  0,  0,  1),
             "-": ( 1,  0,  0, -1),
             "/": ( 0, -1, -1,  0),
            "\\": ( 0,  1,  1,  0)
        }

    def __init__(self, str, evolve):
        self._evolve = evolve
        self._cache = {}
        str = re.sub(r"\s+", "", str)
        self._iterator = self._REP.finditer(str)
        token, self.cells = self._parse(self._next(), "!")

    def _next(self):
        try: return self._iterator.next().group()
        except StopIteration: return None

    def _parse(self, token, terminators):
        cells = []
        x = y = 0
        while token != None:
            if token.startswith("@"):
                subpattern = self._subpattern(token[1:])
                cells.extend(self._xlate(subpattern, x, y))
            elif token[-1:] in "bo$":
                n = int(token[:-1]) if len(token) > 1 else 1
                if token[-1:] == "$":
                    y += n
                    x = 0
                else:
                    if token[-1:] == "o":
                        for i in xrange(n):
                            cells.extend([x + i, y])
                    x += n
            else:
                if token not in terminators:
                    raise SyntaxError, "Syntax error in rle"
                return token, cells
            token = self._next()
        raise SyntaxError, "Syntax error in rle"
            
    def _subpattern(self, name):
        basekey = name + "+0" + self._ID_CHAR
        token = self._next()
        if token == "=":
            token, self._cache[basekey] = self._parse(self._next(),
                                                      self._TERMINATOR_CHARS)
        if token.startswith("+") and len(token) > 1:
            n = int(token[1:])
            token = self._next()
        else:
            n = 0
        if token not in self._XFORM_CHARS:
            raise SyntaxError, "Syntax error in rle"
        key = name + "+" + str(n) + token
        try:
            return self._cache[key]
        except KeyError:
            pass
        zerokey = name + "+0" + token
        try:
            result = self._cache[zerokey]
        except KeyError:
            result = self._cache[zerokey] = self._xform(self._cache[basekey],
                                                        token)
        result = self._cache[key] = self._gen(result, n)
        return result
    
    def _xlate(self, cells, xt, yt):
        if xt == yt == 0:
            return cells
        result = list(cells)
        for i in xrange(0, len(result), 2):
            x, y = result[i:i+2]
            result[i:i+2] = x + xt, y + yt
        return result
    
    def _xform(self, cells, char):
        if char == self._ID_CHAR:
            return cells
        matrix = self._MATRICES[char]
        result = list(cells)
        xm = ym = 0
        for i in xrange(0, len(result), 2):
            x, y = result[i:i+2]
            xn, yn = (matrix[0] * x + matrix[1] * y,
                      matrix[2] * x + matrix[3] * y)
            xm, ym = min(xm, xn), min(ym, yn)
            result[i:i+2] = xn, yn
        return self._xlate(result, max(0, -xm), max(0, -ym))
    
    def _gen(self, cells, n):
        if n == 0:
            return cells
        if self._evolve is None:
            raise SyntaxError, "'+' used without supplied evolve function"
        return self._evolve(cells, n)
    
    
def rle(cells):
    return _Writer(cells).rle

def cells(str, evolve=None):
    return _Reader(str, evolve).cells

__all__ = ["rle", "cells"]

if __name__ == "__main__":
    from rlife import Pattern
    def evolve(cells, n):
        return Pattern(cells).evolved(n).cells
    print cells("@G=3o$o$bo.10b@G+1^!", evolve)
I only started learning Python a week ago, so forgive - but also if you wish decry! - any bad style. I also tend to comment things only when they're "finished".

Note that evolve() is supplied as an argument to cells() in order for the module to be indepndent of any Life implementation available to the caller. In the test code at the end, rlife is a module which wraps RLife7.dll, a Life engine which I wrote years ago in C for use with my Glue Smalltalk program. It was a doddle to get it running without recompliation under Python (using the ctypes library).

I'm not sure scripts written in Python (or any other language) would always be the best way in which to express a complex construction. At the very least, some "scripts" might actually be organized by the originator as a collection of modules. I hope to start working with Herschel conduits in Python soon, and I would want to put their pattern definitions in a separate, reusable module - or even in a database. I am writing another module for defining a class of general affine transformations. A "script" to construct a large pattern from Herschel components would therefore rely on these modules, and probably many others, to run.

And then there is the method by which the script "outputs" its pattern. If it runs under Golly, it has one set of library calls to contend with. If it runs with some other life engine or program, it might need to use a completely different set.

On the other hand, if it outputs RLE, or any other Life pattern format whose implementation is relatively trivial, its output can be read by any program implementing that format. Python and Golly are not trivially implementable. ;) Or, to put it another way, I don't think any future implementation of Life should be required to provide a Golly-compatible Python-callable API so that they can "read" patterns published now as Python/Golly scripts.

Cheers, Paul

User avatar
Andrew
Moderator
Posts: 919
Joined: June 2nd, 2009, 2:08 am
Location: Melbourne, Australia
Contact:

Re: Proposal: Recursive RLE

Post by Andrew » September 15th, 2009, 8:29 am

PM 2Ring wrote:But next time you do something like this, please consider the option of allowing old-style parameters where practical.
Rest assured I do try to ensure that changes to the scripting API are backward compatible. I made an exception in the case of setcursor/getcursor because it became clear when I added the new Pick cursor in 2.0 that using an int was a stupid idea. I actually didn't think there would be all that many scripts out there using those commands, and the few that did exist would be trivial to fix. Anyway, sorry about that.
I'm so glad you're here to answer our Golly questions, but your good advice tends to get scattered around the place. Maybe we should have a dedicated Golly Q&A thread?
Not really sure it's necessary. You can use the forum's search facility to find all posts containing"Golly", or you can go to the Members page and list all my posts (most of which will be Golly-related).
Use Glu to explore CA rules on non-periodic tilings: DominoLife and HatLife

User avatar
Andrew
Moderator
Posts: 919
Joined: June 2nd, 2009, 2:08 am
Location: Melbourne, Australia
Contact:

Re: Proposal: Recursive RLE

Post by Andrew » September 15th, 2009, 9:07 am

igblan wrote:I'm not sure scripts written in Python (or any other language) would always be the best way in which to express a complex construction. At the very least, some "scripts" might actually be organized by the originator as a collection of modules. I hope to start working with Herschel conduits in Python soon, and I would want to put their pattern definitions in a separate, reusable module - or even in a database. I am writing another module for defining a class of general affine transformations. A "script" to construct a large pattern from Herschel components would therefore rely on these modules, and probably many others, to run.
This is one of the purposes of the glife module distributed with Golly (in Scripts/Python). I'd be happy to include more sub-modules within glife that might be useful in various scripts.
... Python and Golly are not trivially implementable. ;) Or, to put it another way, I don't think any future implementation of Life should be required to provide a Golly-compatible Python-callable API so that they can "read" patterns published now as Python/Golly scripts.
I'd argue there's no need for another implementation of Life. :) Golly and Python (and Perl) are free, cross-platform and open source. Golly's GUI code is written using a free, cross-platform, open source library (wxWidgets). None of these choices were accidental -- Golly has been built to last. I'm probably being overly optimistic, but I'd like to think that Golly might outlive all the current developers!

But as I said, don't let me put you off. I'll be interested to follow the progress of your new format, and I certainly don't have any objections to Golly being modified to read/write it. If you or anybody else wants to experiment with making such changes, see the readrle routine in readpattern.cpp and the writerle routine in writepattern.cpp. Note that both those files contain pretty simple C++ code -- there's no wxWidgets stuff.
Use Glu to explore CA rules on non-periodic tilings: DominoLife and HatLife

User avatar
PM 2Ring
Posts: 152
Joined: March 26th, 2009, 11:18 am

Re: Proposal: Recursive RLE

Post by PM 2Ring » September 16th, 2009, 6:23 am

Andrew wrote:
PM 2Ring wrote:But next time you do something like this, please consider the option of allowing old-style parameters where practical.
Rest assured I do try to ensure that changes to the scripting API are backward compatible. I made an exception in the case of setcursor/getcursor because it became clear when I added the new Pick cursor in 2.0 that using an int was a stupid idea. I actually didn't think there would be all that many scripts out there using those commands, and the few that did exist would be trivial to fix. Anyway, sorry about that.
No apology required, Andrew. A man's gotta do what a man's gotta do. :)
And I agree a string argument is a much better idea here than an int argument. Few of my scripts actually change the current cursor. I normally do something like

Code: Select all

oldcursor = getcursor()
new(title)
#stuff
setcursor(oldcursor)
so the argument type is irrelevant.
Andrew wrote:
I'm so glad you're here to answer our Golly questions, but your good advice tends to get scattered around the place. Maybe we should have a dedicated Golly Q&A thread?
Not really sure it's necessary. You can use the forum's search facility to find all posts containing"Golly", or you can go to the Members page and list all my posts (most of which will be Golly-related).
No worries. BTW, thanks to you and the rest of the gang for all the effort you guys have put into Golly. I've been impressed with Tomas's work since the days of the Amiga.

Post Reply