rep_str2bin_struct
No arguments
Description:
Create a binary tree image from a control string as interpreted by BinArbor coding language
(Also made by Reptorian.).
Control characters:
^ = Move to parent node.
< = Create left child if needed, then move to it.
> = Create right child if needed, then move to it.
: = Create missing left/right children without moving.
. = Move to a random branch of current node. If the node has no children, create
one on a random side first, before moving into a branch. If it has only one branch, then move to that branch.
~ = Move to sibling branch. Creates sibling if missing.
* = Move to current subtree root.*
+ = Move upward along same branch direction.
- = Move downward along same branch direction.
% = Mirror a branch across a mirror point (left/right swapped at
every level). If the current node has exactly one child, that
child's branch is mirrored onto the empty side of the current
node.
& = Clone a branch onto the empty side of the current node
(same as %, but without swapping left/right). Does nothing
unless the node has exactly one child.
%%name = Like %, but the branch is taken from the node stored in variable name
and grafted onto the empty sides of the current node. Works on any node.
Occupied sides are left alone, and the current node's own value is not changed.
&&name = Like &, but the same way (no left/right swap) and from variable name.
= = Break out of the innermost enclosing loop (N{...}, N...`, ??{...}[...],
#{n}[...], @?0/@?1 path walks, @<0/@>0/@.0/@:0/@^0 directional loops or
@!{...} and its siblings) and resume right after it. Any if/else body or
[...] local context being left is closed automatically. Error if used
outside a loop.
*A subtree root is the node where the current local branch context began.
Random leaf navigation:
( = Move to random node missing a left child.
) = Move to random node missing a right child.
| = Move to random node missing either child (every such node is equally likely).
! = Move to random node with no children.
At-all constructs (the body is BinArbor code, NOT an expression):
@!{...} = Run the body once at every node that has no children.
@({...} = Same, for every node missing a left child.
@){...} = Same, for every node missing a right child.
@|{...} = Same, for every node missing either child.
The set of nodes is fixed when the construct starts, so children created by the
body are not visited. Inside {...} only nodes of the local subtree are used.
The current node is restored afterwards. = leaves the construct, , continues
with the next node. Nodes are visited in internal stack order, not by index.
Path walks (the path is NOT an expression, and nothing is ever created):
@?0{path}[...] = Check once that path (only ^ < > ~ + - * allowed) leads to existing
nodes. If so, run the body once at the node reached after each step, then return
to the starting node. Nothing happens if the path is invalid.
@?1{path}[...]; = Same, but the current node becomes the path's end node afterwards.
@?1{path}; = Only move to the path's end node (the body is optional for mode 1).
+ and - count as one step. = leaves the walk (mode 0 returns to the start
node, mode 1 stays where the body left it), , continues with the next step.
Directional loops (the body is BinArbor code, nothing is ever created, no ; needed):
@<0{skip}[...] = Run the body at the current node, then step to the left child again and
again, running the body at every node reached. Stops when there is no further left child.
@>0{skip}[...] = Same, toward right children.
@.0{skip}[...] = Same, but each step picks a random side. Stops when that side has no child.
@:0{skip}[...] = Same, but each step picks randomly among existing children. Stops when none.
@^0{skip}[...] = Same, toward the parent. Stops after reaching the subtree root.
The digit is mandatory. 0 = return to the start node afterwards, 1 = stay at the last
node reached. = leaves the loop (mode 1 stays where the body left the node),
, continues with the next step.
{skip} is optional. It is evaluated at a node before the body, including the starting
node. If it gives n, that node and the next n-1 nodes are skipped, and the body runs at
the node after them. The expression is not evaluated again until the body has run.
Expressions and local branching:
{...} = Evaluate expression and store result in node.
[...] = Evaluate inside local subtree context.
Nesting is allowed on [...].
Variables:
name = Assign current node to variable name.*
@name = Move to variable node.
Cannot begin with _ or a number!
This can be reassigned.
Repeat loops:
N{...} = Execute BinArbor code block N amount of time.
N... = The same, but with different construct ''.
Nesting is allowed in all basic repeat loops.
Control flow (the bodies run in the CURRENT node context, like N{...}):
??{cond}[...] = While loop. Runs the body while cond is true (non-zero, not nan).
??[...]{cond} = Do-while loop. Runs the body once, then repeats while cond is true.
?{cond}[...]; = If. Runs the body only if cond is true.
?{cond}[...][...]; = If/else. First body if cond is true, second otherwise.
?{c1}[...]?{c2}[...]...[...]; = If/else-if chain. The final else body is optional.
#{n}[...] = Run the body n times (n is an expression, evaluated once).
?@{n}[b0][b1]...[bx]; = Switch. Evaluates n once, floors it, and runs body number n
(0-based) in the CURRENT node context. If n is nan, negative or
past the last body, nothing runs. There is no default.
Use , or = inside an if body to continue/break out of a loop respectively: ??{1}[ < ?{depth()>=4}[=]; ]
Here {...} is an expression returning a scalar, not a store-in-node expression.
The ; is requred for all constructs that mentions it.
Nesting is allowed in all expression-based control flow codes.
Expression Functions:
dir() = Return current branch direction.
Error at subtree root.
root() = Return value of current subtree root.
Error at subtree root.
L() = Return value of left child.
Error if no left child exists.
R() = Return value of right child.
Error if no right child exists.
sibling() = Return value of the sibling node.
Error at subtree root or if no sibling exists.
self() = Return value of the current node.
depth() = Return depth of the current node relative to the
current subtree root (0 at the root).
isleaf() = Return 1 if the current node has no children,
otherwise 0. Only reflects the tree built so far.
hasleft() = Return 1 if the current node has a left child,
otherwise 0. Only reflects the tree built so far.
hasright() = Return 1 if the current node has a right child,
otherwise 0. Only reflects the tree built so far.
hasparent() = Return 1 if the current node has a parent inside the
current subtree root context, 0 at the subtree root.
hassibling() = Return 1 if the current node has a sibling, otherwise 0.
Always 0 at the subtree root.
idx() = Return the index of the current node (0 is the tree root).
nodes() = Return the number of nodes created so far in the whole tree.
children() = Return the number of children of the current node (0, 1 or 2).
parent_dir() = Return the branch direction of the parent node.
Error at the subtree root and at its direct children.
subtree_size() = Return the number of nodes in the subtree of the current
node, itself included.
leaves() = Return the number of leaves at or below the current node.
height() = Return how many levels lie below the current node (0 for a leaf).
maxdepth() = Return the depth of the deepest node in the whole tree so far.
Absolute depth, not relative to the subtree root.
subtree_size(), leaves(), height() and maxdepth() walk the tree, so their
cost grows with the size of the walked subtree. Calling them in a long
loop on a big tree is slow. idx(), nodes() and children() are instant.
x_ind() = Return the 0-based pass/step index of the innermost enclosing loop.
Error outside a loop.
X_ind() = Return how many times the body of the innermost enclosing loop has been
executed so far, minus 1. Differs from x_ind() only when a skip count is used.
Error outside a loop.
For this implementation, all G'MIC JIT expressions are supported.
Ignored characters:
space, newline, /
Output Binary tree node layout:
0 = parent index*
1 = left child index
2 = right child index
3 = depth level
4+ = stored values (if vector_size > 0)
*For the very first pixel at the top, parent index is actually maximum depth level
Example:
<>~:
Produces:
o
/
o
/
o o
/
o o
Author: Reptorian.