Nutshell
-
- Posts: 372
- Joined: June 13th, 2015, 12:04 pm
Nutshell
Hi! For the past month or so I've been working on my own derivative ruletable spec+language. I've written a Python 3.6+ utility to compile it down to a normal Golly ruletable.
https://github.com/eltrhn/nutshell
Its main draw, for anyone curious, is in not binding variables by name: this means that the same variable name can be used multiple times in a transition without needing to define uniquely-named variants as in a Golly table. There are many other features too, however!
The README serves as documentation and is as comprehensive as I could make it. Please be aware that a large amount of the info in this thread below is outdated, because I started posting very early on (when the project's name was still "rueltabel", among other larger differences) -- so don't rely on anything I say in my posts below up through May 19th, 2018, lol.
If you want to get started writing your own Nutshell rule, just follow the "setup" instructions in the README to get the transpiler script downloaded, then continue referring to it for info on syntax/semantics/etc. Please also feel free to give me feedback or ask questions on this post
https://github.com/eltrhn/nutshell
Its main draw, for anyone curious, is in not binding variables by name: this means that the same variable name can be used multiple times in a transition without needing to define uniquely-named variants as in a Golly table. There are many other features too, however!
The README serves as documentation and is as comprehensive as I could make it. Please be aware that a large amount of the info in this thread below is outdated, because I started posting very early on (when the project's name was still "rueltabel", among other larger differences) -- so don't rely on anything I say in my posts below up through May 19th, 2018, lol.
If you want to get started writing your own Nutshell rule, just follow the "setup" instructions in the README to get the transpiler script downloaded, then continue referring to it for info on syntax/semantics/etc. Please also feel free to give me feedback or ask questions on this post
Last edited by M. I. Wright on October 23rd, 2018, 4:47 pm, edited 20 times in total.
Re: rueltabel
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.
-
- Posts: 372
- Joined: June 13th, 2015, 12:04 pm
Re: rueltable
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!
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:
...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
- 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: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:
Code: Select all
1, any, any, 0, SE..SW (3, 4), 0, any, 0 -> E[SE: (1, 2)]
Code: Select all
# T = 0 # 0 0 0 0 1 0 3 3 3 # T = 1 # 0 0 0 0 0 1 3 3 3
...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)Code: Select all
# T = 0 # 0 0 0 0 1 0 3 3 4 # T = 1 # 0 0 0 0 0 2 3 3 4
--- - 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:"Addition" of variables can be accomplished by writing them together in a variable literal, as with the last state above.
Code: Select all
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
Negation means that rules like DeficientSeeds can be written like so: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)Code: Select all
@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
It also allows "NewTons", Blinkerspawn's (basic) alpha-particles-y test rule, to be written like so:(where it previously required a variable to be explicitly defined for each negation)Code: Select all
@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
Code: Select all
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
Code: Select all
@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
Last edited by M. I. Wright on April 22nd, 2018, 12:00 pm, edited 1 time in total.
Re: rueltable
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?
Re: rueltable
Indeed. I also preferred the original name of 'rueltabel' (and am totally in favour of this new high-level language!).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?
What do you do with ill crystallographers? Take them to the mono-clinic!
Re: rueltable
Perhaps better to call it something completely different that isn't a typo.
How about either of the following:
How about either of the following:
- "Dictator" - someone who makes rules.
- "Scobberlotcher" - someone who avoids hard work.
LifeViewer https://lazyslug.com/lifeviewer
-
- Posts: 372
- Joined: June 13th, 2015, 12:04 pm
Re: rueltable
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
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
Re: rueltable
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.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 :)
-
- Posts: 372
- Joined: June 13th, 2015, 12:04 pm
Re: rueltabel
That's absolutely reasonable, but I have to admit I've grown somewhat attached to the idea of a weird name... eh
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 --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: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 I've also added a "find this transition" flag: 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.
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 --
Code: Select all
@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
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:
Code: Select all
live_1, 0, 0, 0, 0, live_2, 0, live_3
live_3, 0, 0, 0, 0, live_2, 0, live_1
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 I've also added a "find this transition" flag: 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.
-
- Posts: 372
- Joined: June 13th, 2015, 12:04 pm
Re: rueltabel
Alright, last update for now.
EDIT: The @COLORS syntax has changed, as have of course the @RUEL/@TABEL segment headers. Please view the repo's README (@COLORS described near the bottom) for the currently-correct syntax.
("}b" is a randomly-chosen name for the auto-filled-in color)
EDIT: The @COLORS syntax has changed, as have of course the @RUEL/@TABEL segment headers. Please view the repo's README (@COLORS described near the bottom) for the currently-correct syntax.
- 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
- 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: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).
Code: Select all
@NUTSHELL 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 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 append to this line a bracketed number indicating 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.)
Code: Select all
@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......"
".............................."
".............................."
".............................."
Last edited by M. I. Wright on July 24th, 2018, 8:07 pm, edited 2 times in total.
- Redstoneboi
- Posts: 433
- Joined: May 14th, 2018, 3:57 am
Re: rueltabel
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.
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.
c(>^w^<c)~*
This is 「Fluffy」
「Fluffy」is my sutando.
「Fluffy」has the ability to engineer r e p l i c a t o r s.
「Fluffy」likes to watch spaceship guns in Golly.
「Fluffy」knows Natsuki best girl.
This is 「Fluffy」
「Fluffy」is my sutando.
「Fluffy」has the ability to engineer r e p l i c a t o r s.
「Fluffy」likes to watch spaceship guns in Golly.
「Fluffy」knows Natsuki best girl.
-
- Posts: 372
- Joined: June 13th, 2015, 12:04 pm
Re: rueltabel
Sure! If I understand correctly, a mapping can handle this:
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:and this expands to
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:...still fits the actual transition on one line, though![/size]
Code: Select all
@TABLE
states: 256
neighborhood: Moore
symmetries: none
(1..255), N..NW any, [0: (2..255, 1)]
If it's easier to visualize, here's an example with fewer states:
Code: Select all
@TABLE
states: 5
neighborhood: von Neumann
symmetries: none
(1, 2, 3, 4), N..W any, [0: (2, 3, 4, 1)]
Code: Select all
@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
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:
Code: Select all
@TABLE
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]
-
- Posts: 372
- Joined: June 13th, 2015, 12:04 pm
Re: Nutshell
A small, belated update: Nutshell’s mostly stable + usable now. Some features worth highlighting:
- Constants: The @NUTSHELL segment, Nutshell’s analogue to @RULE, provides a syntax for declaring “constants” (names that refer to a single cellstate) alongside a description of some particular state. These names can then be used in the rest of the rule (a) without clogging up @TABLE with single-cellstate variable declarations, and (b) without, in some cases, ever needing to refer to cellstates by number.
- Optional directives: All of “neighborhood: Moore”, “symmetries: none”, and “states: ?” (where states is n_states) are preinitialized and need not be written outright (as long as those values are what’s desired). In particular, states: ? says to infer the states value from the maximum cellstate referred to in the table or declared in @NUTSHELL.
- Custom range-1-Moore-subset neighborhoods: Passing a comma-delimited list of compass directions to the “neighborhood” directive, such as “neighborhood: NW, N, NE”, makes the rest of the table use that neighborhood (in that order) for its transitions. Nutshell then expands each transition into the smallest encompassing Golly neighborhood.
- Inline-rulestring transitions: If a certain cellstate or group thereof needs to behave according to a Golly-compatible 2-state rulestring, Nutshell lets you declare so by replacing the middle states (the neighborhood) of a transition with a special syntax that indicates the rulestring, foreground state/s, and background state/s. Among other uses, this allows rules which extend some totalistic or isotropic-nontot rule to not waste precious space manually defining its transitions.
For example, a History ruletable for any Hensel-expressible rule can be created by replacing the birth and survival conditions in the following template:Code: Select all
@NUTSHELL XHistory Template for History rules. 1: ON cell : {History} Indicates whether cell was ever ON : {MarkedON} Marked ON cell; may change to OFF, but remains marked : {MarkedOFF} Marked OFF cell; may change to ON, but remains marked : {InitialON} Becomes a normal marked OFF cell on dying, but is initially marked differently from a normal marked ON cell : {Boundary} Grey boundary cell @COLORS 0F0: 1 000080: History D8FFD8: MarkedON F00: MarkedOFF FF0: InitialON 606060: Boundary @TABLE symmetries: permute off = (MarkedOFF, History, 0) on = (1, MarkedON, InitialON) # Birth; REPLACE THE 3 BELOW off, <3 / on / (off, Boundary)>; [0: (MarkedON, 1, ...)] # Death on touching a boundary cell on, Boundary ~ 1, (0, Boundary); [0: (History, MarkedOFF, ...)] # Survival; REPLACE THE 23 BELOW on, <23 / on / off>; [0] # Death on, any; [0: (History, MarkedOFF, ...)]
Re: Nutshell
I've discovered nutshell and used it in my script to generate the QCA rule.
In order to do that I've implemented a lua script. It allows to use golly to create the rule. But instead of stating the "states" your states in golly as input represent variables and functions to unroll some variable. For example I had majority gate - so it's a function that takes three arguments, they came at place 3, 5, 7. The script unrolls all the possibilities and generates a rule based on the options, while keeping other variables just as strings. You write the function in lua, which is relatively simple job usually. The maintenance and bug fixing of rule generated by the script reduced dramatically - I fix only the functions, or the input.
The compilation is done into Nutshell. I also hope to join forces and make a universal script for universal rule table generator, which is defined in golly visually only.
Here is an example of the input:
Input example (make sure all cells centers are at X = 0, Y = 10*N and the functions codes are at same Y, and X = 10) - better use the attached file.
In order to do that I've implemented a lua script. It allows to use golly to create the rule. But instead of stating the "states" your states in golly as input represent variables and functions to unroll some variable. For example I had majority gate - so it's a function that takes three arguments, they came at place 3, 5, 7. The script unrolls all the possibilities and generates a rule based on the options, while keeping other variables just as strings. You write the function in lua, which is relatively simple job usually. The maintenance and bug fixing of rule generated by the script reduced dramatically - I fix only the functions, or the input.
The compilation is done into Nutshell. I also hope to join forces and make a universal script for universal rule table generator, which is defined in golly visually only.
Code: Select all
--A script by michael simkin 2019 - auto generates rules using states in golly which represent variables.
--Insert your code only between user definition start and end definitions.
--Register your variables using the line: def:append("any", any)
--f1, f2, ..., fn - represent state 1,2,3...n in golly.
--index_function is the part which selects what part of the rule you want to unroll in order to use the functions.
--index_function[] = {2, 3} will unroll variables which placed in golly in the second and third place.
--In golly you fill 8 states around some x = 0 y = 10*N. You also place the function index in x = 10 y = 10*N next to the rule.
--Forum post here: http://conwaylife.com/forums/viewtopic.php?f=7&t=3361&p=59227&hilit=nutshell#p59227
------------------------------------Helper functions----------------------------------
-- class.lua
-- Compatible with Lua 5.1 (not 5.0).
function class(base, init)
local c = {} -- a new class instance
if not init and type(base) == 'function' then
init = base
base = nil
elseif type(base) == 'table' then
-- our new class is a shallow copy of the base class!
for i,v in pairs(base) do
c[i] = v
end
c._base = base
end
-- the class will be the metatable for all its objects,
-- and they will look up their methods in it.
c.__index = c
-- expose a constructor which can be called by <classname>(<args>)
local mt = {}
mt.__call = function(class_tbl, ...)
local obj = {}
setmetatable(obj,c)
if init then
init(obj,...)
else
-- make sure that any stuff from the base class is initialized!
if base and base.init then
base.init(obj, ...)
end
end
return obj
end
c.init = init
c.is_a = function(self, klass)
local m = getmetatable(self)
while m do
if m == klass then return true end
m = m._base
end
return false
end
setmetatable(c, mt)
return c
end
Definitions = class(function(df)
df.table_of_everything = {}
df.table_of_keys = {}
df.table_of_idx = {}
end)
function Definitions:append(name, value)
self.table_of_everything[name] = value
self.table_of_keys[#self.table_of_keys + 1] = name
self.table_of_idx[name] = #self.table_of_keys
end
function interpret(f, params)
if #params == 0 then
return f()
elseif #params == 1 then
return f(params[1])
elseif #params == 2 then
return f(params[1], params[2])
elseif #params == 3 then
return f(params[1], params[2], params[3])
end
end
function index_to_function(idx)
if idx == 1 then
return f1
elseif idx == 2 then
return f2
elseif idx == 3 then
return f3
elseif idx == 4 then
return f4
elseif idx == 5 then
return f5
elseif idx == 6 then
return f6
elseif idx == 7 then
return f7
elseif idx == 8 then
return f8
elseif idx == 9 then
return f9
elseif idx == 10 then
return f10
elseif idx == 11 then
return f11
elseif idx == 12 then
return f12
elseif idx == 13 then
return f13
elseif idx == 14 then
return f14
elseif idx == 15 then
return f15
end
end
NdIterator = class(function(it, sizes)
it.box = sizes
it.cur = {}
it.flags = {}
for i = 1, #sizes do
it.cur[#it.cur + 1] = 1
it.flags[#it.flags + 1] = false
end
end)
function NdIterator:next()
for i = 1, #self.box do
self.cur[i] = self.cur[i] + 1
if self.cur[i] > self.box[i] then
self.cur[i] = 1
else
break
end
end
end
function NdIterator:total()
total = 1
for i = 1, #self.box do
total = total * self.box[i]
end
return total
end
local def = Definitions()
--------------------------------------User definitions Start--------------------------------------
--visual compiler
local g = golly()
--0 - empty space
--switch - 0,1,unk,A0,A1 : 1, 2, 3, 4, 5
--hold - 0,1,unk,A0,A1 : 6, 7, 8, 9, 10
--relese A0, A1, r, : 11, 12, 13
--relax - A0, A1, r, : 14, 15, 16
function from_idx(idx)
if idx <= 10 then
idx = (idx - 1) % 5 + 1
if idx == 1 then
return 0
elseif idx == 2 then
return 1
elseif idx == 3 then
return 2
elseif idx == 4 then
return 0
else
return 1
end
else
idx = idx - 10
idx = idx % 3
return idx
end
end
--state 1
any = {"any"}
--state 2
live = {"live"}
--state 3
switch = {1, 2, 3, 4, 5}
--state 4
hold = {6, 7, 8, 9, 10}
--state 5
relese = {11, 12, 13}
--state 6
relax = {14, 15, 16}
--state 7
switch_hold = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
--state 8
not_switch_hold = {0, 11, 12, 13, 14, 15, 16}
--state 9
undefined_relax = {16}
--state 10
defined_relax = {14, 15}
--state 11
not_switch = {0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
def:append("any", any)
def:append("live", live)
def:append("switch", switch)
def:append("hold", hold)
def:append("relese", relese)
def:append("relax", relax)
def:append("switch_hold", switch_hold)
def:append("not_switch_hold", not_switch_hold)
def:append("undefined_relax", undefined_relax)
def:append("defined_relax", defined_relax)
def:append("not_switch", not_switch)
--switch->hold
function f1(sw)
return sw + 5
end
--hold->relese
function f2(hld)
if hld < 9 then
return 13
else
return hld + 2
end
end
--release->relax
function f3(ease)
return ease + 3
end
--(defined_relax)->(defined_switch)
function f4(defax)
return defax - 10
end
--switch_hold->switch
function f5(sw)
return (from_idx(sw) + 1)
end
--(swr1, swr2)->switch (known or unknown depending)
function f6(sw1, sw2)
if from_idx(sw1) == from_idx(sw2) then
return from_idx(sw1) + 1
else
return 3
end
end
function f7(sw1, sw2)
if from_idx(sw1) == from_idx(sw2)then
if from_idx(sw2) ~= 2 then
return 2 - from_idx(sw1)
else
return 3
end
else
return 3
end
end
function f8(sw1, sw2, sw3)
arr = {sw1, sw2, sw3}
counter = {0,0,0}
for i = 1, 3 do
idx = from_idx(arr[i]) + 1
counter[idx] = counter[idx] + 1
if counter[idx] == 2 then
return idx
end
end
return 3
end
function f9(sw)
return 3
end
index_function = {{0}, {0}, {0}, {0}, {7}, {3, 7}, {4, 6}, {3, 5, 7}, {0}}
colors = {
"0 255 0: 1, 4, 6, 9, 11, 14",
"0 150 0: 6",
"255 255 0: 2, 5, 10, 12, 15",
"150 150 0: 7",
"192 192 192: 3, 8",
"64 64 64: 13, 16"
}
--------------------------------------User definitions End--------------------------------------
---------------------Compilation part don't touch--------------------------------
for i = 1, #index_function do
indeces = index_function[i]
for j = 1, #indeces do
index_function[i][j] = index_function[i][j] + 1
end
end
function toskip(x, y)
if #(g.getcells({x - 10, y, 20, 1})) >= 60 or #(g.getcells({x - 10, y, 20, 1})) == 0 then
return true
else
return false
end
end
golly_order = {{0, 0},{0, -1},{1, -1},{1, 0},{1, 1},{0, 1},{-1, 1},{-1, 0},{-1, -1}}
rules = {}
rect = g.getrect()
y0 = math.floor(rect[2] / 10) * 10 - 20
y1 = math.floor((rect[2] + rect[4]) / 10) * 10 + 20
y = y0
total = 0
while y < y1 do
rule = {{}, 0}
--Fill the variables
if toskip(0, y) == false then
for i = 1, 9 do
rule[1][#rule[1] + 1] = g.getcell(0 + golly_order[i][1], y + golly_order[i][2])
end
--This is the function index
rule[2] = g.getcell(10, y)
rules[#rules + 1] = rule
end
y = y + 10
end
name = g.getstring("Enter full path with file name")
local file = io.open(name, "w")
file:write("@NUTSHELL QdCA\n\n@TABLE\nstates: 17\nsymmetries: rotate4 reflect\nneighborhood: Moore\n")
for i = 1, #def.table_of_keys do
value = def.table_of_everything[def.table_of_keys[i]]
if (value[1] == "any" or value[1] == "live") == false then
file:write(def.table_of_keys[i].." = (")
for idx = 1, #value do
if idx == #value then
file:write(tostring(value[idx])..")\n")
else
file:write(tostring(value[idx])..", ")
end
end
end
end
for i = 1, #rules do
rule = rules[i]
vars = rule[1] --9 variables around me
func_idx = rule[2] -- function index
input_vars = index_function[func_idx]
local state_iterator = NdIterator({1, 1, 1, 1, 1, 1, 1, 1, 1})
for j = 1, #input_vars do
values = def.table_of_everything[def.table_of_keys[vars[input_vars[j]]]]
state_iterator.box[input_vars[j]] = #values
state_iterator.flags[input_vars[j]] = true
end
max_idx = state_iterator:total()
for state_iterator_idx = 1, max_idx do
input_func = {}
for j = 1, #state_iterator.box do
if state_iterator.flags[j] == false then
var_name = "0"
if vars[j] ~= 0 then
var_name = def.table_of_keys[vars[j]]
end
if j == #state_iterator.box then
file:write(var_name.."; ")
else
file:write(var_name..", ")
end
else
values = def.table_of_everything[def.table_of_keys[vars[j]]]
value = values[state_iterator.cur[j]]
input_func[#input_func + 1] = value
if j == #state_iterator.box then
file:write(tostring(value).."; ")
else
file:write(tostring(value)..", ")
end
end
end
value = interpret(index_to_function(func_idx), input_func)
file:write(tostring(value).."\n")
state_iterator:next()
end
end
file:write("@COLORS\n")
for i = 1,#colors do
file:write(colors[i].."\n")
end
file.close()
Code: Select all
x = 144, y = 246, rule = QdCA
63.80F7$60.F$60.F$60.F31.3A$60.F31.ACA8.A$60.F31.3A$61.F$4.5F52.F$3.F
2.F.2F51.F$2.F59.F$2.F59.F$.F35.4F21.F$.F23.F10.2F2.F3.F.6F.2F7.F$.F
5.4F5.4F5.3F7.F3.2F3.F.F5.3F6.F30.3A$.2F7.2F3.2F2.F5.2F.F5.F2.3F4.2F
5.2F.F6.F30.ADA8.B$2.F6.2F.F2.5F4.3F2.F3.2F2.2F5.2F5.F2.2F5.F30.3A$3.
2F4.F2.F2.F6.4F3.2F2.F2.F7.2F5.F.F.2F.F3.F$4.3F2.F2.F3.2F3.2F.2F5.F.
3F8.F7.2F2.F.F3.2F$7.2F3.F5.4F9.3F5.3F2.F11.3F4.F$31.9F23.F4$92.3A$
92.AEA8.C$92.3A8$92.3A$92.AJA8.D$92.3A9$64.80F9$92.3H$21.F70.GIH8.E$
20.F3.F67.A2H$7.F11.2F19.3F$7.F11.F7.F4.F5.3F.F$7.F11.F7.F3.3F4.F2.2F
$8.F5.F3.F4.2F2.F2.F6.F2.2F$8.F4.3F2.F5.F2.F.2F6.3F$9.F3.F.F.2F5.F2.F
.F5.4F$10.3F2.3F6.F2.2F8.F8.F$10.2F12.F2.2F8.F7.2F45.3H$38.F4.3F46.GI
G8.F$38.5F49.3H8$92.3H$92.HIH8.I$92.3H8$92.3K$92.CIK8.J$92.3K89$10.F
52.80F$9.2F23.F$.F7.F24.F$3F6.F24.F$4F4.F25.F2.F11.4F$2F.F4.F6.2F3.2F
4.2F3.7F8.4F3.3F$2F.F4.F4.2F.F2.F5.3F5.F8.2F5.4F$2F.2F3.F3.2F.2F2.F4.
2F2.F4.2F.F2.3F.F$2F2.F2.F3.4F4.F.F2.F3.F4.2F.F.F3.F$F3.F2.F3.2F5.F2.
F2.2F.2F4.F2.3F2.2F50.H$F3.F2.F2.F3.2F2.F.3F2.5F2.2F.6F52.I9.G$F4.2F
3.4F4.2F2.F6.F2.4F2.F3.2F48.G.G$5.2F3.2F10.F6.F.2F6.4F$5.2F15.F6.2F$
19.3F.F$18.F4.F$18.F4.F$18.F4.F$18.F4.F$18.F4.F$18.2F3.F39.80F$20.4F
8$93.H$92.GIG8.H$93.G$3.2F8.2F16.F21.2F$4.2F7.2F15.2F22.2F$4.3F5.2F.F
39.F$4.F.F5.F2.F39.F$4.F2.2F2.F3.F9.2F5.2F22.F$4.F4.3F3.F7.2F.F3.2F
17.F6.F$5.F3.2F4.F6.2F2.F3.2F3.3F11.F6.F$5.F10.F4.2F2.2F2.3F.6F17.F4.
F$5.F10.F3.2F3.2F2.2F2.2F2.F.F4.3F2.F6.F3.2F$5.2F9.F3.F3.F.F.3F2.F3.F
.F3.2F.F3.F6.F.2F.F8.F$5.2F9.F3.F2.F3.2F.F2.F2.2F.F3.F2.F3.F6.2F4.F7.
F$6.F10.F3.3F5.F3.F.2F2.F2.F7.F5.2F6.F5.2F$17.F11.F3.3F3.F2.F7.F7.F6.
2F3.F$17.F11.F3.2F5.2F8.2F6.F7.F3.F$18.F10.F10.2F9.F6.F4.F3.4F$18.F
10.F10.2F9.F7.F3.F6.F$18.2F8.2F29.F3.F5.F$19.F8.F30.F2.2F5.F$19.F8.F
31.2F7.F$28.F31.F8.F$27.F41.F$25.3F40.F$25.2F41.F$68.F$68.F$68.F$68.F
$67.F$66.2F$65.F$64.F$64.F$63.F$62.2F!
- Attachments
-
- Golly_input_simkin_script.mc
- (5.84 KiB) Downloaded 440 times