ConwayLife.com - A community for Conway's Game of Life and related cellular automata
Home  •  LifeWiki  •  Forums  •  Download Golly

rueltabel

For general discussion about Conway's Game of Life.

rueltabel

Postby M. I. Wright » April 18th, 2018, 12:47 am

Hi! For the past month or so I've been working on my own derivative ruletable spec + language, dubbed "rueltabel". I wrote a Python 3.6 utility to compile it down to a normal Golly ruletable:
https://github.com/eltrhn/rueltabel
I don't have actual docs (yet?), but hopefully the "examples" directory and the README up front will suffice for now. I'll also go over a few of the big things in this post. (Note, though, that the whole thing is still in its infancy! I'll reiterate that at the bottom here.)

So the only feature that actually renders my rueltabels incompatible with Golly ruletables, and the only "new" feature that's mandatory for a ruel-writer to work with, is that all multi-state variables are intrinsically unbound. The concept of a "bound" variable -- that is, one that stands for the same state every time it's used in a transition -- doesn't exist.

The introduction of unbound variables to the ruletable format, in order to avoid the "a1 = a; a2 = a; a3 = a; ..." clunkiness, has of course been previously discussed, with one such discussion being in the "UnboundVariables" proposal here. But the fact seems to be overlooked that it isn't actually the variable that needs to be bound to -- only its value in the current transition's context! And with this in mind (that we are actually binding to a value, not a variable's name), it can be shown that in order to make an inconstant cellstate hold the same value throughout a transition, all we need to do is bind to the index it first appeared at:
# Name-bound variables
var a1 = a
var a2 = a
var a3 = a
var a4 = a
0, a, a1, a2, a3, a, a4, a, a3, 1
# Unbound variables
0, a, a, a, a, [1], a, [1], [4], 1
And now that we're binding by indices instead of names, we are (a) freed from having to define multiple identical variables with slightly-variant names just to unbind them from one another, and (b) enabled to use anonymous "on-the-spot" variables, created using the literal {state, state, ...} syntax, directly in transition. (We are unable to do the latter in a Golly ruletable because this ad-hoc variable wouldn't have a name to be bound by)

But I didn't want to stop there -- because indices, though handy, can look rather abstruse at first glance. So rueltabel, noting that each index of a transition can also be represented by a compass* direction (Moore has north through northwest, vonNeumann north/east/south/west, etc.), introduces the symbolic constants N NE E SE S SW W NW. These (at compile time) are substituted for the transition index they refer to in the chosen neighborhood; under the vonNeumann neighborhood, for instance, the names N E S W are provided for indices 1 2 3 4 respectively.
This means that the above transition, assuming it's in the Moore neighborhood, can be rewritten like so:
0, a, a, a, a, [N], a, [N], [NE], 1
Much more readable, IMHO. :D
(Note that the input state -- that is, the one before the first comma -- is still referred to as "0" rather than with some name.)

*I mistakenly refer to these throughout rueltabel as "cardinal directions", having forgotten that this term doesn't encompass(ha) northeast/northwest/southeast/southwest. Oops!

...but that's not all! There's a lot more to rueltabel than just unbound variables and compass-direction indices, although the variables happen to be the only real distinguisher between it and Golly's ruletable format. All the other features, though hopefully useful, are optional and don't have to be used when writing a rueltabel. Allow me to present an example:
@RUEL bml
The Biham–Middleton–Levine traffic model.

0: Road
1: Downward-bound car, moving
2: Rightward-bound car, moving
3: Downward-bound car, waiting
4: Rightward-bound car, waiting

Generation 0 will consist only of states 0, 2, 3.

@TABEL
states: 5
neighborhood: von Neumann
symmetries: none

# Note that the "any" variable is actually given pre-defined, but I wrote it here for clarity's sake
any = (0..4)
move = (1, 2)
wait = (3, 4)

# A waiting car starts moving on the next tick
wait, N..W any, [0: move]

# A downward-bound car moves down if the cell below it is 0, else stays put and becomes a 'waiting'
1, N..W any, [S: (0, 3, ...)] -> S[(3, _, ...)]
# A rightward-bound car moves right if it can, else ditto
2, N..W any, [E: (0, 4, ...)] -> E[(4, _, ...)]

@COLORS
  0: FFF
1 3: 0000FF
2 4: FF0000

and then to go through it from the top:
  • The segment headers are changed from "@RULE" and "@TABLE" to match my project's name, ha. Note that the rulename can also be moved to the line directly below the "@RUEL" header.
  • The n_states directive is changed to "states", and spaces are ignored in the assignment of these directives -- you can write "neighborhood: von Neumann", "symmetries: rotate 4", etc.
    (You also can write "symmetries: p e r m u t e", but... maybe don't)
  • Variables are declared without the "var" keyword, and can be defined with either {braces} or (parentheses). I prefer parens myself, but there's no difference as far as the parser's concerned.
  • Variables can have ranges of states in them, using the double-dot syntax. "(0, 2..4, 6)" expands to "{0, 2, 3, 4, 6}", and "(0..255)" expands to you-know-what.
  • The double-dot 'range' syntax has meaning in transitions as well! Here, "N..W any" means that every state from north through west will be given the "any" variable; the line can be expanded to "wait, any, any, any, any, [0: move]".
  • The construct at the end of the first transition, "[0: move]", is what's called a mapping. It's identical to a binding (which uses just [brackets] enclosing an index), but instead of copying the bound variable's state, it maps it to another.
    Here, it says to take the input state (index 0), being the "wait" variable, and map it to the "move" variable. When compiled, this transition gets expanded into two -- it's equivalent to writing:
    1, any, any, any, any, 3
    2, any, any, any, any, 4
    Note that we didn't actually have to define the "move" and "wait" variables for this; we could have written the transition as "(1, 2), N..W any, [0: (3, 4)]". It's more readable the way it is now, though, especially if you already know how the BML model is supposed to work.
  • The "[S: (0, 3, ...)]" is very similar; it says to take the variable to the south (being "any") and map it to the variable "(0, 3, ...)".
    That ellipsis just tells rueltabel to "fill out the rest" with state 3. If you'll notice, the "any" variable actually comprises five total states, but for the purposes of BML we want a state-1 cell to die if it has an empty cell to its south and in all other cases become a state-3 cell. So instead of "[S: (0, 3, 3, 3, 3)]", we can just write "[S: (0, 3, ...)]" and the ellipsis will copy that "3" out to the rest of the necessary states.
    (At compile time, ellipses are "optimized" into a single Golly transition, using a single variable for all redundant states rather than creating a separate transition for each.)
  • The post-arrow syntax is interesting, a bit. I've always found it somewhat jarring that, while we naturally describe something like a 'car' as moving from one spot to another, this same motion has to be described in terms of CA transitions as two separate actions: one cell dying, and an otherwise-totally-independent adjacent cell being born.
    The "->" syntax allows that motion to be expressed on one line. It says here that, in addition to becoming state 0 (before the ->), a state-1 cell will spawn to its south a new cell mapped from the variable previously there.
    An underscore, "_", in this "output" variable says to leave the cell in question as is.
    In other words, "-> S[(3, _, ...)]" says "if the cell to my south is currently state 0 (which is the first state of the 'any' variable), turn it into a 3 on the next generation. If it's anything else, leave it as is."
    If you don't wish to map to anything -- say you want a state-2 cell to be spawned to the south unconditionally -- you can write "-> S:2", forgoing the mapping stage entirely. You can also chain as many of these output specifiers as needed after the arrow as long as there's some whitespace to separate them. (See examples/rueltabels/newtons.ruel for an example of this)
  • The "@COLORS" segment in a rueltabel allows multiple states to be specified for a single color, and it also allows colors to be specified as hexadecimal numbers. (If you don't want to use hex-notated colors, you can still write r/g/b colors as in Golly, but the colon separating the color from its state(s) is mandatory.)
That was a lot! My main goal here is to cut out as much redundancy as possible while trying my best to maintain or improve readability -- all these new features work to that end. There are also a few things not covered above that are mentioned in the README, if you want to give that a look. Here's the .rule generated by the above ruelfile:
@RULE bml
*********************************
**** COMPILED FROM RUELTABEL ****
*********************************
The Biham–Middleton–Levine traffic model.

0: Road
1: Downward-bound car, moving
2: Rightward-bound car, moving
3: Downward-bound car, waiting
4: Rightward-bound car, waiting

Generation 0 will consist only of states 0, 2, 3.


@TABLE
neighborhood: vonNeumann
symmetries: none
n_states: 5

var __all__0 = {0, 1, 2, 3, 4}
var __all__1 = __all__0
var __all__2 = __all__0

var move_0 = {1, 2}

var wait_0 = {3, 4}

var any_0 = {0, 1, 2, 3, 4}
var any_1 = any_0
var any_2 = any_0
var any_3 = any_0

var _490246945299929_0 = {1, 2, 3, 4}

3, any_0, any_1, any_2, any_3, 1
4, any_0, any_1, any_2, any_3, 2
1, any_0, any_1, 0, any_3, 0
1, any_0, any_1, _490246945299929_0, any_3, 3
0, 1, __all__0, __all__1, __all__2, 3
2, any_0, 0, any_2, any_3, 0
2, any_0, _490246945299929_0, any_2, any_3, 4
0, __all__0, __all__1, __all__2, 2, 4


@COLORS
0 255 255 255
1 0 0 255
3 0 0 255
2 255 0 0
4 255 0 0
"__all__" is a special variable, referred to by the arrow-syntax stuff on expansion to fill in cells that don't overlap with the source cell's neighborhood, and the "_490246945299929" is an 'anonymous' variable generated by the ellipsis.

That's all! Finally, note that this project is still very new (I had the idea barely a month ago, and I basically wrote the entire parser+compiler over the last week*), and I have no doubt that there are things I've overlooked in the specification. I also don't doubt that there are features I could implement better, bits of syntax that I've tragically overwrought, and bugs I didn't catch when testing -- I hope people will find enough merit in this that they start using it, of course, so I can see what needs to be added and fixed and so on.
(*...and it's really quite janky as a result of the short timeframe! My use of regex makes it hard to catch syntax errors (there's a strong chance I'm going the wrong way about parsing), and I started to structure new code quite messily as I got closer to finishing... it's also wanting pretty badly for comments in some key places. I'll hopefully get to documenting it better in the coming weeks.)

If you want to get started writing your own rueltabel, just follow the "setup" instructions in the README (of the GitHub repo at the top of this post) to get the compiler script downloaded, then refer back to this writeup and the "spec" section of the same README for info on syntax/semantics. Please also feel free to give me feedback or ask questions on this post :D
Last edited by M. I. Wright on May 12th, 2018, 8:03 pm, edited 10 times in total.
M. I. Wright
 
Posts: 346
Joined: June 13th, 2015, 12:04 pm

Re: rueltabel

Postby 77topaz » April 18th, 2018, 5:44 am

After witnessing its development over the past few weeks on the Discord, it's nice to finally see this in its finished state on the forums. :D
User avatar
77topaz
 
Posts: 511
Joined: January 12th, 2018, 9:19 pm

Re: rueltable

Postby M. I. Wright » April 22nd, 2018, 2:57 am

Guess I'll log updates here too. Biggest change now is that I've renamed the thing from "rueltabel" to "rueltable" (for which a certain "Is it a typo?" may have been a motivating factor) -- but other than that, I've also added two new things!

  • The README used to make mention of a "tentative" syntax for the output specifiers -- this is tentative no more. You can now write an output map along the lines of "CD[CD: var]", CD being any compass direction. Take, for instance, the following transition:
    1, any, any, 0, SE..SW (3, 4), 0, any, 0 -> E[SE: (1, 2)]
    The "-> E[SE: (1, 2)]" says "Assuming I'm state 1: take the variable southeast of me, map it to the variable (1, 2), and spawn a cell with that value to my east." Or, in graphical terms:
    # T = 0 #
    0 0 0
    0 1 0
    3 3 3

    # T = 1 #
    0 0 0
    0 0 1
    3 3 3
    # T = 0 #
    0 0 0
    0 1 0
    3 3 4

    # T = 1 #
    0 0 0
    0 0 2
    3 3 4
    ...where "1" is the center cell at T=0. This feature, finally, allows me to actually make the rule I created rueltable for! (so expect that... at some point)
    ---
  • Variables now are able to be (a) subtracted from, and (b) negated, using the - (dash) and -- (double dash) operators. I'll copy/paste this one from the README:
    0, foo-bar, bar-2, bar-(2, 3), -1, --1, -bar, --(3, 4), (foo, bar), baz

    # foo-bar says "All states in foo that are not in bar"
    # foo-2 says "All states in foo that are not 2"
    # bar-(2, 3) says "All states in bar that are not in (2, 3)"
    # -1 says "All *live* states that are not 1" (expands to {2, 3, 4} assuming n_states==5)
    # --1 says "*All* states (including 0) that are not 1" (expands to {0, 2, 3, 4} assuming the same)
    # -bar and --(3, 4) say the same but with multiple states enclosed in a variable
    "Addition" of variables can be accomplished by writing them together in a variable literal, as with the last state above.
    Negation means that rules like DeficientSeeds can be written like so:
    @RUEL DeficientSeeds
    @TABLE
    states: 7
    neighborhood: Moore
    symmetries: rotate4 reflect

    0, N 0, NE -1, E..W 0, NW -1, 1
    0, N -2, NE..SW 0, W -2, NW 0, 2
    0, 0, 0, -3, SE..W 0, -3, 3
    0, -4, NE..W 0, -4, 4
    0, -5, NE..SE 0, -5, SW..NW 0, 5
    0, N..E 0, -6, S..W 0, -6, 6

    any, N..NW any, 0
    and this compiles to 30-40+ lines, depending on how you count. (Rueltabel is obsoleted for this purpose by my other script, but take this as a demo)
    It also allows "NewTons", Blinkerspawn's (basic) alpha-particles-y test rule, to be written like so:
    @RUEL NewTons
    @TABLE
    states: 7
    neighborhood: Moore
    symmetries: none

    # photon splitting
    0, (1, 5), NE..SE any, (1, 3), SW..NW any, 0 -> E[(4, _, ...)]  W[(6, _, ...)]
    0, any, any, (1, 6), SE..SW any, (1, 4), any, 0 -> N[(3, _, ...)]  S[(5, _, ...)]

    # photon moving
    0, --3, any, --4, any, 3, any, --6, any, 3
    0, --3, any, --4, any, --5, any, 4, any, 4
    0, 5, any, --4, any, --5, any, --6, any, 5
    0, --3, any, 6, any, --5, any, --6, any, 6

    # photon dying
    (3..6), N..NW any, 0
    (where it previously required a variable to be explicitly defined for each negation)

A future (non-bugfix) release will have support for two other things: a shorthand permute-symmetry syntax that looks something like this,
0, 1:3, 0, 1  # gets filled in automatically
0, 1:3, 0:5, 1

# Both of which expand to:
0, 1, 1, 1, 0, 0, 0, 0, 0, 1

and, off a suggestion from SuperSuperMario24, the ability to change symmetries midway through a table. This would for example allow DeficientLife to be written like so:
@RUEL DeficientLife
@TABLE
states: 12
neighborhood: Moore

# Birth
symmetries: rotate4 reflect
0, 0, -2, 0, 0, 0, -2, 0, -2, 2
0, -3, 0, -3, 0, 0, 0, -3, 0, 3
0, 0, 0, -4, 0, -4, 0, 0, -4, 4
0, N -5, NE..SW 0, W..NW -5, 5
0, N..NE -6, E..W 0, NW -6, 6
0, 0, -7, -7, SE..W 0, NW -7, 7
0, 0, -8, 0, 0, -8, 0, 0, -8, 8
0, -9, 0, 0, -9, 0, 0, 0, -9, 9
0, -10, 0, -10, 0, 0, 0, 0, -10, 10
0, -11, 0, 0, 0, -11, 0, 0, -11, 11

# Survival
symmetries: permute
live, live:2, 0, 1 # s2
live, live:3, 0, 1 # s3

any, N..NW any, 0

...but, being honest, I'm not quite sure how I should go about this. I know I'll have to go through the completed transitions and expand them all to the "least-abstracted" symmetry (e.g. "symmetries:permute" followed by "symmetries:none" would mean expanding the "symmetries:permute" segment), but I'll need to figure out how to make the compiler know to expand the different symmetry levels to each other. If anyone's reading this and has ideas, shoot :!:
Last edited by M. I. Wright on April 22nd, 2018, 12:00 pm, edited 1 time in total.
M. I. Wright
 
Posts: 346
Joined: June 13th, 2015, 12:04 pm

Re: rueltable

Postby 77topaz » April 22nd, 2018, 5:56 am

But isn't changing from "rueltabel" (two differences from "ruletable") to "rueltable" (one difference from "ruletable") going to make people more likely to think the word is simply a typo? :?
User avatar
77topaz
 
Posts: 511
Joined: January 12th, 2018, 9:19 pm

Re: rueltable

Postby calcyman » April 22nd, 2018, 6:33 am

77topaz wrote:But isn't changing from "rueltabel" (two differences from "ruletable") to "rueltable" (one difference from "ruletable") going to make people more likely to think the word is simply a typo? :?


Indeed. I also preferred the original name of 'rueltabel' (and am totally in favour of this new high-level language!).
What do you do with ill crystallographers? Take them to the mono-clinic!
User avatar
calcyman
 
Posts: 1515
Joined: June 1st, 2009, 4:32 pm

Re: rueltable

Postby rowett » April 22nd, 2018, 9:20 am

Perhaps better to call it something completely different that isn't a typo.

How about either of the following:
  • "Dictator" - someone who makes rules.
  • "Scobberlotcher" - someone who avoids hard work.
rowett
Moderator
 
Posts: 849
Joined: January 31st, 2013, 2:34 am
Location: UK

Re: rueltable

Postby M. I. Wright » April 22nd, 2018, 11:52 am

All good points, thank you!
I'm going to change it back to "rueltabel" for now, then -- may as well -- but I do see the value in giving it a more-unique name too. Don't know about those two specifically (humorous as they are) but I'd be 100% open to further suggestions :)
M. I. Wright
 
Posts: 346
Joined: June 13th, 2015, 12:04 pm

Re: rueltable

Postby dvgrn » April 22nd, 2018, 12:24 pm

M. I. Wright wrote:All good points, thank you!
I'm going to change it back to "rueltabel" for now, then -- may as well -- but I do see the value in giving it a more-unique name too. Don't know about those two specifically (humorous as they are) but I'd be 100% open to further suggestions :)

How about just "ruletemplate"? Boring, I know, but maybe more likely to make sense to a casual reader than RULEZtable or SovereignTable or what have you.
User avatar
dvgrn
Moderator
 
Posts: 4478
Joined: May 17th, 2009, 11:00 pm
Location: Madison, WI

Re: rueltabel

Postby M. I. Wright » April 29th, 2018, 5:31 pm

That's absolutely reasonable, but I have to admit I've grown somewhat attached to the idea of a weird name... eh :roll:

Anyway, here's another update. I finally implemented the symmetry-normalization thing as well as the permute shorthand, the former meaning that it's now acceptable to switch symmetries midway through a tabel. For instance, that DeficientLife.ruel file from above --
@RUEL DeficientLife
@TABEL
states: 12
neighborhood: Moore

# Birth
symmetries: rotate4 reflect
0, 0, -2, 0, 0, 0, -2, 0, -2, 2
0, -3, 0, -3, 0, 0, 0, -3, 0, 3
0, 0, 0, -4, 0, -4, 0, 0, -4, 4
0, N -5, NE..SW 0, W..NW -5, 5
0, N..NE -6, E..W 0, NW -6, 6
0, 0, -7, -7, SE..W 0, NW -7, 7
0, 0, -8, 0, 0, -8, 0, 0, -8, 8
0, -9, 0, 0, -9, 0, 0, 0, -9, 9
0, -10, 0, -10, 0, 0, 0, 0, -10, 10
0, -11, 0, 0, 0, -11, 0, 0, -11, 11

# Survival
symmetries: permute
live, live:2, 0, 1 # s2
live, live:3, 0, 1 # s3

# Death otherwise
any, any:8, 0
now produces a working B3/S23-deficient rulefile.

EDIT: It now produces 'optimal' results (an update to the shrunken pre-edit text below)! The issue was that I was doing the normalizing after resolving variable name-bindings, so a transition napkin like "live_1, live_2, live_3, 0, 0, 0, 0, 0" where all the "live_N"s have the same value was producing multiple "distinct" outputs like:
live_1, 0, 0, 0, 0, live_2, 0, live_3
live_3, 0, 0, 0, 0, live_2, 0, live_1
This was fixed by removing the _N suffixes of all variables that only appear once before normalizing and then restoring them afterward. You can see this in examples/compiled_ruletables/DeficientLife.rule.

However, it is suboptimal. Check the comparison here: rueltabel is producing 42 rotate4reflect transitions from permute-symmetric "live, live live, live, 0, 0, 0, 0, 0, 1" (which is the survival-on-3 line above) -- but, as shown by deficient_gen.py, it apparently only needs to be 10. I'm stumped here.
My approach to normalizing symmetries was to implement a class for each symmetry type with a hash function that produces identical hashes for each identical transformation of itself -- for instance, a "Rotate4((0, 1, 2, 3, 4, 5, 6, 7))" object has the same hash as "Rotate4((2, 3, 4, 5, 6, 7, 0, 1))". Each class also has an "expand()" method that returns a multiple-transition representation of itself under "symmetries:none".
So when expanding from, say, "symmetries:permute" to "symmetries:rotate4reflect", I create a Permute() object from the napkin* of every transition under "symmetries:permute" and expand each, then create a Rotate4Reflect() object from each item of this expansion, and finally toss these rotate4reflect objects into a set. (This is where the hash function comes in -- if an object has the same hash as another it won't create a duplicate set entry)
So I figure there's some symmetry stuff I'm not accounting for that would slim the rueltabel transition list from 42 to 10...? Not sure. Again, if anyone has ideas...
(...and note that my actual code is still rather dirty, so I don't know if looking through it will help much. Apologies)



But enough of that :P I've also added a "find this transition" flag:
rueltabel_find.png
rueltabel_find.png (72.45 KiB) Viewed 581 times
which makes it so that, if a cell isn't behaving the way it's supposed to, you can "-f" the transition it's doing and it'll find the offending line for you (instead of you having to guess at what you typo'd). Has been quite handy.

*napkin: The neighborhood segment of a transition. (i.e. transition excluding its first and last items -- coined by 83bismuth38 a while ago? in reference to a triangular-neighborhood 'bowling napkin' specifically)

---

So I think this is pretty much a 'feature-complete' alpha now? Everything from my original spec's been implemented! -- no guarantees of being bug-free, though.
M. I. Wright
 
Posts: 346
Joined: June 13th, 2015, 12:04 pm

Re: rueltabel

Postby M. I. Wright » May 11th, 2018, 2:42 am

Alright, last update for now.

  • Changed permute-symmetry shorthand to use "*" instead of ":" to avoid confusion with the other uses of colons. Breaking change, but fortunately I don't have anything besides my own examples to break :P
  • Made all segments optional. The @TABEL and @RUEL segments, if omitted, will no longer throw a fit and can be made 'normal' by spelling the @header names conventionally, and segments whose headers aren't misspelt (@ICONS, @COLORS) can be ignored during parsing by writing "#golly" as the first word after. (That is: "@COLORS #golly" or "@COLORS<newline>#golly".)
  • Implemented a new @ICONS syntax that uses normal XRLE instead of the XPM format. An example follows:
    @RUEL IconTest

    @TABLE
    n_states:14
    neighborhood:Moore
    symmetries:none

    @COLORS
    10: FFF

    @ICONS
    0: 303030
    1: D0D0D0
    2: 007FFF
    3: 535353
    4: AD331D
    5: 1A1A1A
    6: C0C0C0
    7: 6077A0
    8: 405780
    9: 0000FF

    #C 1
    x = 13, y = 13, rule = //10
    5.3A$5.3A$2.9A$2.3A3.3A$2.3A3.3A$3A7.3A$3A7.3A$3A7.3A$2.3A3.3A$2.3A3.
    3A$2.9A$5.3A$5.3A!

    #C 2
    x = 5, y = 11, rule = //10
    5B$5B$2B$2B$2B$2B$2B$2B$2B$5B$5B!

    #C 3
    x = 5, y = 11, rule = //10
    5B$5B$3.2B$3.2B$3.2B$3.2B$3.2B$3.2B$3.2B$5B$5B!

    #C 4
    x = 11, y = 11, rule = //10
    4.3C$4.3C$4.3C$4.3C$11C$11C$11C$4.3C$4.3C$4.3C$4.3C!

    #C 5
    x = 11, y = 3, rule = //10
    11C$11C$11C!

    #C 6
    x = 11, y = 11, rule = //10
    9.2D$7.4D$5.4D$3.4D$.4D$3D$.4D$3.4D$5.4D$7.4D$9.2D!

    #C 7
    x = 11, y = 11, rule = //10
    2D$4D$2.4D$4.4D$6.4D$8.3D$6.4D$4.4D$2.4D$4D$2D!

    #C 8
    x = 9, y = 11, rule = //10
    .7E$9E$9E$9E$9E$9E$.8E$5.4E$5.4E$4.4E$.6E!

    #C 9
    x = 9, y = 7, rule = //10
    .7E$9E$9E$9E$9E$9E$.7E!

    #C 11
    x = 9, y = 9, rule = //10
    2G5.2G$2G5.2G$.2G3.2G$.2G3.2G$2.2G.2G$2.2G.2G$3.3G$3.3G$4.G!

    #C 12
    x = 9, y = 9, rule = //10
    2H5.2H$2H5.2H$.2H3.2H$.2H3.2H$2.2H.2H$2.2H.2H$3.3H$3.3H$4.H!

    #C 13
    x = 9, y = 9, rule = //10
    4.I$3.3I$3.3I$2.2I.2I$2.2I.2I$.2I3.2I$.2I3.2I$2I5.2I$2I5.2I!
    The idea is that you're going to be in Golly anyway when you're fiddling with a rule, so it'll be easier to quickly copy/paste that RLE in and out of a blank Golly tab than to edit XPM images in your text editor. Icons are automatically centered & resized to the nearest Golly icon size (7, 15, 31).

    The first number on each line (in the bit before the RLEs) corresponds to a cell state used below. "0 303030", for instance, assigns the symbol "." (state 0) the color #303030.
    The parser also accepts the cellstate symbol to be written in place of the numbers, as in ". 303030 / A D0D0D0 / B 007FFF / ..." if it's easier to read. (The colon should not be used in this form.)

    The rule of each RLE is ignored -- I just chose a generic multistate //10 to get all desired colors in -- and the comment above each rule is required to start with '#' and contain numbers somewhere in it; more than one number means more than one cell state gets this icon. Multiple numbers here can be separated either by commas, whitespace, or both.
    Note that the icons don't have to be in sequence or even present (the pre-icon comment facilitates ordering). If an icon is skipped (like state 10 is above!) it will be made as a solid square with a color taken from the @COLORS declaration for that state. (An omitted icon with no fill color defined in @COLORS will raise an error, however.)
  • EDIT 5/14/18: You can now also declare a *gradient* to fill in missing states, even when they aren't addressed in @COLORS. The syntax is "? <hex color> <hex color>" or "? <hex color> <ignored separator> <hex color>", defined along with the other colors in @ICONS (before the RLEs).

    The gradient relies on the "states:" directive in @TABEL to compute its start and end -- but if you don't have any @TABEL section then this won't be available, so in this case you may add a comment to the end of the gradient containing your desired "n_states" value e.g. "? <hex color> <hex color> #<n_states>".

    A full example might look like any of "? 000 FFF", "? 000 - FFF", "? 000 FFF # 13", and "? 000 - FFF # 13" -- indicating a gradient from #000 (black) to #FFF (white), with the latter two implying the absence of the @TABEL section and explicitly defining n_states in its lieu.
    --
    (If you don't want a certain @COLORS color to take precedence over the gradient, put an *asterisk before its cellstate in the part before the colon; for instance, "*10: FFF" above. This is a touch particular/specific, though, so I only implemented it as a "just in case" and I fully expect it to go unused.)

Here's the output of that ruel file:
@RULE IconTest
*********************************
**** COMPILED FROM RUELTABEL ****
*********************************


@TABLE
n_states:15
neighborhood:Moore
symmetries:none



@COLORS
10 255 15 240


@ICONS
XPM
"15 195 11 2"
".. c #303030"
"AA c #D0D0D0"
"BB c #007FFE"
"CC c #535353"
"DD c #AD331D"
"EE c #1A1A1A"
"FF c #C0C0C0"
"GG c #6077A0"
"HH c #405780"
"II c #0000FF"
"}b c #FFFFFF"
".............................."
"............AAAAAA............"
"............AAAAAA............"
"......AAAAAAAAAAAAAAAAAA......"
"......AAAAAA......AAAAAA......"
"......AAAAAA......AAAAAA......"
"..AAAAAA..............AAAAAA.."
"..AAAAAA..............AAAAAA.."
"..AAAAAA..............AAAAAA.."
"......AAAAAA......AAAAAA......"
"......AAAAAA......AAAAAA......"
"......AAAAAAAAAAAAAAAAAA......"
"............AAAAAA............"
"............AAAAAA............"
".............................."
".............................."
".............................."
"..........BBBBBBBBBB.........."
"..........BBBBBBBBBB.........."
"..........BBBB................"
"..........BBBB................"
"..........BBBB................"
"..........BBBB................"
"..........BBBB................"
"..........BBBB................"
"..........BBBB................"
"..........BBBBBBBBBB.........."
"..........BBBBBBBBBB.........."
".............................."
".............................."
".............................."
".............................."
"..........BBBBBBBBBB.........."
"..........BBBBBBBBBB.........."
"................BBBB.........."
"................BBBB.........."
"................BBBB.........."
"................BBBB.........."
"................BBBB.........."
"................BBBB.........."
"................BBBB.........."
"..........BBBBBBBBBB.........."
"..........BBBBBBBBBB.........."
".............................."
".............................."
".............................."
".............................."
"............CCCCCC............"
"............CCCCCC............"
"............CCCCCC............"
"............CCCCCC............"
"....CCCCCCCCCCCCCCCCCCCCCC...."
"....CCCCCCCCCCCCCCCCCCCCCC...."
"....CCCCCCCCCCCCCCCCCCCCCC...."
"............CCCCCC............"
"............CCCCCC............"
"............CCCCCC............"
"............CCCCCC............"
".............................."
".............................."
".............................."
".............................."
".............................."
".............................."
".............................."
".............................."
"....CCCCCCCCCCCCCCCCCCCCCC...."
"....CCCCCCCCCCCCCCCCCCCCCC...."
"....CCCCCCCCCCCCCCCCCCCCCC...."
".............................."
".............................."
".............................."
".............................."
".............................."
".............................."
".............................."
".............................."
"......................DDDD...."
"..................DDDDDDDD...."
"..............DDDDDDDD........"
"..........DDDDDDDD............"
"......DDDDDDDD................"
"....DDDDDD...................."
"......DDDDDDDD................"
"..........DDDDDDDD............"
"..............DDDDDDDD........"
"..................DDDDDDDD...."
"......................DDDD...."
".............................."
".............................."
".............................."
".............................."
"....DDDD......................"
"....DDDDDDDD.................."
"........DDDDDDDD.............."
"............DDDDDDDD.........."
"................DDDDDDDD......"
"....................DDDDDD...."
"................DDDDDDDD......"
"............DDDDDDDD.........."
"........DDDDDDDD.............."
"....DDDDDDDD.................."
"....DDDD......................"
".............................."
".............................."
".............................."
".............................."
"........EEEEEEEEEEEEEE........"
"......EEEEEEEEEEEEEEEEEE......"
"......EEEEEEEEEEEEEEEEEE......"
"......EEEEEEEEEEEEEEEEEE......"
"......EEEEEEEEEEEEEEEEEE......"
"......EEEEEEEEEEEEEEEEEE......"
"........EEEEEEEEEEEEEEEE......"
"................EEEEEEEE......"
"................EEEEEEEE......"
"..............EEEEEEEE........"
"........EEEEEEEEEEEE.........."
".............................."
".............................."
".............................."
".............................."
".............................."
".............................."
"........EEEEEEEEEEEEEE........"
"......EEEEEEEEEEEEEEEEEE......"
"......EEEEEEEEEEEEEEEEEE......"
"......EEEEEEEEEEEEEEEEEE......"
"......EEEEEEEEEEEEEEEEEE......"
"......EEEEEEEEEEEEEEEEEE......"
"........EEEEEEEEEEEEEE........"
".............................."
".............................."
".............................."
".............................."
"}b}b}b}b}b}b}b}b}b}b}b}b}b}b}b"
"}b}b}b}b}b}b}b}b}b}b}b}b}b}b}b"
"}b}b}b}b}b}b}b}b}b}b}b}b}b}b}b"
"}b}b}b}b}b}b}b}b}b}b}b}b}b}b}b"
"}b}b}b}b}b}b}b}b}b}b}b}b}b}b}b"
"}b}b}b}b}b}b}b}b}b}b}b}b}b}b}b"
"}b}b}b}b}b}b}b}b}b}b}b}b}b}b}b"
"}b}b}b}b}b}b}b}b}b}b}b}b}b}b}b"
"}b}b}b}b}b}b}b}b}b}b}b}b}b}b}b"
"}b}b}b}b}b}b}b}b}b}b}b}b}b}b}b"
"}b}b}b}b}b}b}b}b}b}b}b}b}b}b}b"
"}b}b}b}b}b}b}b}b}b}b}b}b}b}b}b"
"}b}b}b}b}b}b}b}b}b}b}b}b}b}b}b"
"}b}b}b}b}b}b}b}b}b}b}b}b}b}b}b"
"}b}b}b}b}b}b}b}b}b}b}b}b}b}b}b"
".............................."
".............................."
".............................."
"......GGGG..........GGGG......"
"......GGGG..........GGGG......"
"........GGGG......GGGG........"
"........GGGG......GGGG........"
"..........GGGG..GGGG.........."
"..........GGGG..GGGG.........."
"............GGGGGG............"
"............GGGGGG............"
"..............GG.............."
".............................."
".............................."
".............................."
".............................."
".............................."
".............................."
"......HHHH..........HHHH......"
"......HHHH..........HHHH......"
"........HHHH......HHHH........"
"........HHHH......HHHH........"
"..........HHHH..HHHH.........."
"..........HHHH..HHHH.........."
"............HHHHHH............"
"............HHHHHH............"
"..............HH.............."
".............................."
".............................."
".............................."
".............................."
".............................."
".............................."
"..............II.............."
"............IIIIII............"
"............IIIIII............"
"..........IIII..IIII.........."
"..........IIII..IIII.........."
"........IIII......IIII........"
"........IIII......IIII........"
"......IIII..........IIII......"
"......IIII..........IIII......"
".............................."
".............................."
".............................."
("}b" is a randomly-chosen name for the auto-filled-in color)
M. I. Wright
 
Posts: 346
Joined: June 13th, 2015, 12:04 pm

Re: rueltabel

Postby Redstoneboi » May 19th, 2018, 11:09 pm

does it have some way to "add" 1 to the state number of cells?
if yes, does it roll over when it reaches the state count?
it would be really nice to have an easy way to make a rock paper scissors rule, or emulate a generations rule.
Redstoneboi
 
Posts: 42
Joined: May 14th, 2018, 3:57 am

Re: rueltabel

Postby M. I. Wright » May 19th, 2018, 11:41 pm

Sure! If I understand correctly, a mapping can handle this:
@TABEL
states: 256
neighborhood: Moore
symmetries: none

(1..255), N..NW any, [0: (2..255, 1)]

That line expands to 255 Golly transitions: state 1 to state 2, 2 to 3, 3 to 4, ..., 254 to 255, and 255 to 1 (there's the roll-over!). The anonymous variables on either end make use of the double-dot 'range' syntax; 1..255 expands to every state from 1 to 255.

If it's easier to visualize, here's an example with fewer states:
@TABEL
states: 5
neighborhood: von Neumann
symmetries: none

(1, 2, 3, 4), N..W any, [0: (2, 3, 4, 1)]
and this expands to
@TABLE
n_states: 5
neighborhood: vonNeumann
symmetries: none

### variable declarations omitted ###

1, any_1, any_2, any_3, any_4, 2
2, any_1, any_2, any_3, any_4, 3
3, any_1, any_2, any_3, any_4, 4
4, any_1, any_2, any_3, any_4, 1


By the way, there's an example of "Rock-Paper-Scissors Life" in the examples/ directory of the repo, although it's not quite as elegant as I'd have hoped thanks to some annoying stuff with variables.

EDIT: Cellstate ranges now also accept a step; you can still write "first..last" to represent all states from first to last (inclusive), but "first+step..last" now indicates that only every "step-th" state should be included. For example, "(1, 3..9)" expands to (1, 3, 4, 5, 6, 7, 8, 9), but "(1, 3+3..9)" expands to (1, 3, 6, 9).

Cellstate ranges don't currently accept a step, though -- not sure how a not-ugly syntax for this might look? -- so if you wanted to do something fancier like only affect every other state you'd sadly have to type the variable out in full:
@TABEL
states: 30
neighborhood: Moore
symmetries: none

from = (1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27)

# minor abuse of subtraction follows
# it represents all even states (i.e. all live states *except* those included in 'from')
to = live-from

from, N..NW any, [0: to]
...still fits the actual transition on one line, though!
M. I. Wright
 
Posts: 346
Joined: June 13th, 2015, 12:04 pm


Return to General Discussion

Who is online

Users browsing this forum: No registered users and 2 guests