larger versions on the paster:
>>149 http://paste.textboard.org/76fb47c2/raw intrapatch rendering
>>153 http://paste.textboard.org/ab1e1c1b/raw Sierpinski triangles
>>157 http://paste.textboard.org/661ab540/raw triangles over carpets
apply
* { line-height: 1em; }
to the larger versions for more symmetry
But does the code have to be obfuscated?
This has been covered in >>75.
I tried to make sense of it, but it's too much for me.
The complexity has been slowly built up over 40+ >>114 demos. It is unreasonable to expect to be able to jump straight into the latest demo from scratch and find it a piece of cake. If instead you follow the demos one by one from the beginning, even skipping some occasionally, you will find the increase in complexity you have to digest between adjacent demos to be minor.
Do you have a more concise, maybe a general expression of how you do these?
This is the concise form, an easily readable version would be considerably longer and would not fit into a single post >>127 in this thread. Here's the overall structure of >>157.
Rec is the recursive bootstrapper that you are familiar with from SICP exercise 4.21 https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-26.html#%_thm_4.21 Its only job is to make a function available to itself as an argument to enable recursive calls. Xjoin maps a string-producing function over a iota and joins the results on a separator. For larger demos this needs to be >>24 tail recursive. Symbol produces the string for a pair of coordinates in the overall matrix. Two nested xjoins map symbol over all lines and columns and pass the assembled result to display. These form the outermost layer of the structure and can generate any pattern by customizing symbol. Everything below this layer exists to produce the custom symbol function.
Symbol deals with separating logical matrix element generation from character selection. Index generates the logical matrix element and extract knows how to extract substrings from strings. Symbol simply passes te output of index to extract. For example, if you switch out all the flowers in the chars constant for fruits, you can draw orchards instead of flower gardens.
Index applies the coordinate transformation from the lines-and-columns matrix of the terminal to the diagonal grid of the garden. It produces the cactus diagonals and delegates the content of the flower patches to patch. This can produce any garden by customizing patch. Everything below this layer exists to produce the custom patch function.
Patch is produced by twolevels which takes two levels of garden content as arguments. It tries the first level, in this case the triangles, and if that returns empty it tries the second level, in this case the carpets. This paints the triangles over the carpets. Up to this point the code path is linear, but from here it splits into patch1 for the triangles and patch2 for the carpets.
Patch1, which produces the layer of the triangles, uses three components. Cell produces one logical Sierpinski triangle by returning -1/0/1 for left/empty/right, and is passed in from the outside to patch1. Halfcell knows how to produce left or right half-triangles in a flower patch by filling below the first or the second diagonal of the current flower patch. Quadrant knows how to draw one quadrant by calling cell with its calling convention and passing the result to halfcell. Patch1 itself applies the coordinate transformation from the diagonal grid of the garden to each of the >>137 gapped quadrants, and calls quadrant to deal with a quadrant. Either reflection or rotation could be used for the four quadrants, and patch1 happens to use rotation.
Cell, which produces one logical Sierpinski triangle for patch1, consists of the same half and cell functions as in >>21, and there is nothing new to understand here compared to that post.
Patch2, which produces the layer of the carpets, uses two components. Quad produces one logical Sierpinski carpet, and is passed in from the outside to patch2. Reflect knows how to apply the coordinate transformation from the diagonal grid of the garden to each of the >>132 proper, ungapped quadrants delimited by the cactus diagonals that cross on the central cactus, and calls quad to deal with each quadrant. Reflect uses reflection symmetry on its quadrants. Patch2 simply passes quad to reflect.
The quad that produces one logical Sierpinski carpet for patch2 is the carpet lambda, which is simply the pred lambda from >>17, and there is nothing new to understand here compared to that post.
And that's all there is to >>157.