10
$\begingroup$

Ever use MathJax to display mathematical expressions?   Expressions related to fractals?
Ever used it to display fractals themselves?!   The time has come.


These fractals are based on the iconic dragon curve and raise two questions.

  1. What is the rule behind these arrangements of letters? A clear description, or just a MathJax demonstration of the first 7 levels, would merit a vote of approval.

  2. What is the highest level that MathJax can produce within its default limits? To demonstrate a solution, the first 7 levels should be rendered live by the answer but, for the sake of expedient presentation, higher levels should be represented by images. In test-solving this puzzle, getting past level 12 involved cheating the default “maximum macro substitution count.” Just to get past level 8 without cheating required a new round of creativity and longer code. Default limits at post time:  $\scriptsize\texttt{MathJax.Hub.Config({TeX:{MAXBUFFER:5120, MAXMACROS:10000}})}$

Only the letters and their alignment, not their font or spacing, need to match the examples above. No need to produce multiple levels in a single call, or even in a single MathJax block. No need to label the levels or to arrange them in any particular formation. Code minimality, in this puzzle, is just an informal consideration for discriminating between multiple solutions if they reach the same level.

MathJax incidentals
Please practice safe MathJax by using $\texttt{\begingroup} \raise1.7ex\strut$ and $\texttt{\endgroup}$. The following template is good for this:

      $ \require{begingroup} \begingroup   \def \safe {\text{\endgroup error}} $

      (Answer that contains MathJax blocks)

      $ \endgroup \safe $

If all goes well, the answer will end with (as in the image above): $~~~~~~~~~~~~\bbox[mistyrose]{\color{red}{\text{\safe}}} \raise-.8ex\strut$
If $\texttt{\endgroup}$ is not used successfully, the template is meant to show: $~~\text{\endgroup error} \raise-.8ex\strut$
Before posting an answer, be sure to test it on a freshly loaded browser page. Might also need to reload the page while editing, as inadvertent indiscretions in one edit can pervert MathJax results during later edits.

See also   (feel free to add)
Other puzzles tagged 
Defining macros in MathJax
$\sf\scriptsize \raise2mu( L \kern-2mu \raise4mu{\tiny A} \kern0mu \raise2mu) {\scriptsize T} \kern-1mu \raise-4mu E \kern1mu X$ commands in MathJax
$\sf\scriptsize {\scriptsize T} \kern-1mu \raise-4mu E \kern1mu X$ commands available in MathJax
MathJax reference at Mathematics Meta
MathJax questions at Meta SE | Physics Meta | Puzzling Meta | Mathematics Meta

$\endgroup$
11
  • $\begingroup$ I'm a little confused about the starting conditions. Is the code suppose to produce all the levels, or does it take a given level (serialized) and produce the next? Are the "level x" labels part of the requirement? $\endgroup$ Commented Aug 9, 2016 at 16:03
  • $\begingroup$ Yeh, the wording was rushed originally and is a little clearer now. Also, this puzzle seemed complicated enough without code minimality as a formal goal. $\endgroup$
    – humn
    Commented Aug 9, 2016 at 21:38
  • $\begingroup$ Have you tried to pitch this at Code Golf? It might be a better fit there. $\endgroup$
    – user20
    Commented Aug 9, 2016 at 21:41
  • 1
    $\begingroup$ Thanks, @humn, that makes things clearer. Now I understand your separation of the \begingroup and \endgroup into separate math delimiters. You can do each level separately in a new expression (taking advantage of previous definitions, and since each expression resets the MAXBUFFER and MAXMACROS settings, each level will have its own limits. Got it. $\endgroup$ Commented Aug 9, 2016 at 21:54
  • 1
    $\begingroup$ I think I know why you are not hitting the MAXMACROS limitation, and I know how to exploit it to allow for creating much larger levels without having to change the limits. On the other hand, that does mean there is a way to get around the limits that probably should be considered a bug in MathJax. So I may have to fix it (and so break my new solution to creating larger levels). But at least for now, I can make bigger fractals without resetting the macro count. I'll try to post an updated solution tomorrow (I only have proof of concept done tonight). $\endgroup$ Commented Aug 11, 2016 at 23:46

1 Answer 1

12
$\begingroup$

Answer to Part 1

We encode a dragon, $D$, as a string of $L$s and $R$s, where we start facing right and place the first letter at our starting point. If it is an $L$, we turn left and move forward one space; if it is an $R$ turn right and move forward one space. Then place the second letter, and repeat the process until the string of letters is used up.

Given a dragon, $D$, we write $\overline D$ to mean the dragon obtained from $D$ by replacing all its $L$s with $R$s and vice versa. We write $\neg D$ to represent the dragon whose string of letters is the string for $D$ listed in reverse. Finally, for two dragons, $D$ and $D'$, we write $DD'$ to mean the dragon whose string is the concatenation of the strings for $D$ and $D'$, in that order.

Let $D_i$ represent the level $i$ dragon, and take $D_1 = R$ and $D_2 = LRR$. Then $D_i$ (for $i\ge3$) is obtained by $(\neg\overline{D_{i-2}})\, D_{i-1}\, D_{i-2}$.


Answer to Part 2

This is an updated solution to part 2. It produces all the dragons through level 19 without needing to adjust the MathJax parameters, though the later levels take quite a long time to produce, and are beginning to push the limits of the browser itself to display the result (for levels past 15 or so, I have to wait a while for the browser to update when I scroll the page). Printing the page to PDF (in order to make the images) turned out to take as log as MathJax generating the picture in the first place. So although the technique I used theoretically could be extended to go to even larger dragons, it probably isn't practical to do so.

I employ a trick to get around MathJax's macro-substitution limit that currently is a "feature" of MathJax, but should probably be fixed, so these examples may not work in the future if that occurs. The idea is that each expression typeset by MathJax gets its own parsing environment, and with it its own copy of the buffer and macro limits; some actions in MathJax introduce such parsing environments automatically, and this can be used to get additional macro substitutions. One such place is using mathematics within a \text{} macro, so the inner expression in \text{$...$} will have its own 5120 macro substitutions, regardless of the number that have already been performed outside the \text{} call.

We use this by breaking up the Dragon into pieces: taking advantage of the fact that $D_k = (\neg \overline D_{k-2})D_{k-1}D_{k-2}$, we can draw the three pieces $\neg\overline D_{k-2}$, $D_{k-1}$, and $D_{k-2}$ separately, each in its on expression, to get three times as many macro substitutions as we would if we tried to do them all in one expression. Larger dragons can be handled by chaining together more parts. By hooking together more and more pieces we can get to level 20 before running into the maximum buffer size for the parts. These are produced by the \BigDragon macro (and the \NextBigDragon macro) below.

Of course, we could then do the same trick again to set up an extra big dragon (\BiggDragon?) to get up to level 30, but level 19 is already pushing the limits of the browser, so that seems impractical. It would also require improving the addition and subtraction macros to use 4-digit numbers rather than the current 3-digit ones. Although the current version can handle level 20 in terms of macro substitutions, it also requires the 4-digit numbers, so that is why the code below only goes to 19.

I have put some comments in the code (listed after the diagrams below), but don't have time to write anything more about it at the moment. I think it should be pretty straight forward.

It is best to use the PreviewHTML output for MathJax rather than the HTML-CSS output, since this will be much faster. To switch, right-click (or CTRL-click) on any typeset math, and select the "Math Settings" menu, then the "Math Renderer" submenu, then the "Preview HTML" output. I'd also turn off the "Fast Preview", and the "Assistive MathML" options for best results.

$\require{begingroup}\begingroup \def\safe{\text{\endgroup error}}$ $ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Some utility functions: % % % Make a large rectangle to surround the dragon. % \def\Board#1#2{\bbox[border:1px solid black]{\xspace{#1}\Rule{0em}{#2em}{0em}}} % % Place a letter at the right location on the board. % \def\Place#1#2#3{\smash{\rlap{\xspace{#1}\raise{#2em}{#3}}}} % % Do the horizontal space (the letters are a bit bigger than an ex at % \small size, so add extra space via pts). % \def\init{\sf\small} \def\xspace#1{\hskip #1ex\hskip #1pt \hskip #1pt \hskip #1pt} %\def\init{\sf\tiny} % for \BigDragons, use these two lines %\def\xspace#1{\hskip #1ex} % and comment out the previous two % % Place a marker with a given color at the correct place. % \def\Marker#1#2#3{\Place{#2}{#3}{\color{#1}{\kern-2.25pt\raise.25pt\bigcirc}}} % for \small %\def\Marker#1#2#3{\Place{#2}{#3}{\color{#1}{\kern-1.25pt\raise2pt\bigcirc}}} % for \tiny \def\Marker#1#2#3{} % don't put in markers -- comment out to show them % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Create a dragon from the currently saved dragon string starting % at the given location on the board, or a big dragon from % the last big dragon collections. % \def\Dragon#1#2{\Start{#1}{#2}\E \Continue\Db \End} \def\BigDragon#1#2{\Start{#1}{#2}\E \Bq{}\Bb{}\Ba{} \End} % % Check if there are more letters and call \P if so and \X if not. % \def\D#1 #2#3 #4{#4#1 #2#3 #4} % % Place the letter at the current location. % Then define \T to determine the new orientation from % the current one and the current letter. % Perform the orientation command in order to move to the new location. % \def\P#1#2#3#4{ \Place{#1}{#2}#4 \def\T##1#4#3 ##2##3\T{##2{#1}{#2}##2 } \T L\E \N R\E \S L\S \E R\S \W L\W \S R\W \N L\N \W R\N \E \T } % % These are the commands to move in the given direction. % \def\N#1#2{\def\n##1##2##3{\D{#1}{##1##2##3}}\p\n#2} \def\E#1#2{\def\n##1##2##3{\D{##1##2##3}{#2}}\p\n#1} \def\S#1#2{\def\n##1##2##3{\D{#1}{##1##2##3}}\m\n#2} \def\W#1#2{\def\n##1##2##3{\D{##1##2##3}{#2}}\m\n#1} % % Routines to add or subtract (plus or minus) 1 from % a three-digit number, so we can handle 000 to 999. % These roll over if they go too far. % \def\p#1#2#3#4{ \def\:##1#4##2##3 ##4#4 ##5##6\:{##5#1#2#3##2} \: 01234567890 9 \pp #4 {} \: } \def\pp#1#2#3{\p\drop0#2#3#1} \def\m#1#2#3#4{ \def\:##1#4##2##3 ##4#4 ##5##6\:{##5#1#2#3##2} \: 98765432109 0 \mm #4 {} \: } \def\mm#1#2#3{\m\drop9#2#3#1} \def\drop#1#2#3#4{#4#2#3} % % Start a dragon by placing a marker and creating the \Continue function. % End a dragon by continuing with the end marker, cleaning up, and then % placing the board boundary. % \def\Start#1#2#3{\init\Marker{green}{#1}{#2}\X{#1}{#2}#3\X} \def\End{\C\EndMarker\Board} \def\EndMarker#1#2\X{\EndPlace#1} \def\EndPlace#1#2#3#4{\Marker{red}{#2}{#3}} % % End the current portion of the dragon by defining a continuation % function that records the current location and orientation. % Each continuation is done in \text{$...$} so that it gets its own % equation environment with its own MAXMACROS and MAXBUFFER space. % This lets us do multiple pieces without exceeding the limitations. % \def\X#1#2#3#4\X{\def\C##1{\text{$\init ##1{\D{#1}{#2}#3} \P \X$}}\let\Continue=\C} % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % These functions produce new dragons from old ones. % We keep a separate reversed copy so that we don't have % to reverse them later. % \def\NextDragon{\Next\Da\Db\Dq\Dr} \def\NextBigDragon{\Next\Ba\Bb\Bq\Br} \def\Next#1#2#3#4{ #3\Copy\It #2\Copy\It #1\Copy\It \Define \EndD \tmpA #3\Copy\It #4\Copy\It #1\Copy\It \Define \EndD \tmpB \let#1=#2 \let#2=\tmpA \let#3=#4 \let#4=\tmpB \def\tmpA{} \let\tmpB=\tmpA } \def\Define#1\EndD#2{\def#2##1{##1 #1}} \def\Copy#1\It#2\EndD{#2#1\EndD} % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % The initial two dragons (D_0 and D_1) and their reversed versions, % and the initial two Big Dragons, based on them. Big Dragons use % \C (\Continue) to do multiple pieces (based on the largest small % Dragon that can be processed within the MathJax limits). % \def\Da#1{#1 R} \let\Db=\Da \def\Dq#1{#1 L} \let\Dr=\Dq % \def\Ba#1{#1 \C\Da} \def\Bb#1{#1 \C\Db} \def\Bq#1{#1 \C\Dq} \def\Br#1{#1 \C\Dr} % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% $

$\Dragon{002}{002} {5}{5}$ $\NextDragon\Dragon{002}{002} {6}{6}$ $\NextDragon\Dragon{003}{002} {6}{7}$ $\NextDragon\Dragon{005}{002} {8}{8}$ $\NextDragon\Dragon{007}{004} {10}{9}$
$\NextDragon\Dragon{009}{007} {12}{12}$ $\NextDragon\Dragon{007}{012} {13}{16}$

Some links to larger dragons:

This is the largest that I've made (the level 19 dragon):

Level 19 dragon curve

$\endgroup\safe$

The code:

$\require{begingroup}\begingroup \def\safe{\text{\endgroup error}}$
$
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Some utility functions:
%
%
%  Make a large rectangle to surround the dragon.
%
\def\Board#1#2{\bbox[border:1px solid black]{\xspace{#1}\Rule{0em}{#2em}{0em}}}
%
%  Place a letter at the right location on the board.
%
\def\Place#1#2#3{\smash{\rlap{\xspace{#1}\raise{#2em}{#3}}}}
%
%  Do the horizontal space (the letters are a bit bigger than an ex at 
%  \small size, so add extra space via pts).
%
\def\init{\sf\small}
\def\xspace#1{\hskip #1ex\hskip #1pt \hskip #1pt \hskip #1pt}
%\def\init{\sf\tiny}           %  for \BigDragons, use these two lines
%\def\xspace#1{\hskip #1ex}    %    and comment out the previous two
%
%  Place a marker with a given color at the correct place.
%
\def\Marker#1#2#3{\Place{#2}{#3}{\color{#1}{\kern-2.25pt\raise.25pt\bigcirc}}} % for \small
%\def\Marker#1#2#3{\Place{#2}{#3}{\color{#1}{\kern-1.25pt\raise2pt\bigcirc}}}    % for \tiny
\def\Marker#1#2#3{} % don't put in markers -- comment out to show them
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Create a dragon from the currently saved dragon string starting
%    at the given location on the board, or a big dragon from
%    the last big dragon collections.
%
\def\Dragon#1#2{\Start{#1}{#2}\E \Continue\Db \End}
\def\BigDragon#1#2{\Start{#1}{#2}\E \Bq{}\Bb{}\Ba{} \End}
%
%  Check if there are more letters and call \P if so and \X if not.
%
\def\D#1 #2#3 #4{#4#1 #2#3 #4}
%
%  Place the letter at the current location.
%  Then define \T to determine the new orientation from
%    the current one and the current letter.
%  Perform the orientation command in order to move to the new location.
%
\def\P#1#2#3#4{
  \Place{#1}{#2}#4
  \def\T##1#4#3 ##2##3\T{##2{#1}{#2}##2 }
  \T L\E \N  R\E \S  L\S \E  R\S \W  L\W \S  R\W \N  L\N \W  R\N \E  \T
}
%
%  These are the commands to move in the given direction.
%
\def\N#1#2{\def\n##1##2##3{\D{#1}{##1##2##3}}\p\n#2}
\def\E#1#2{\def\n##1##2##3{\D{##1##2##3}{#2}}\p\n#1}
\def\S#1#2{\def\n##1##2##3{\D{#1}{##1##2##3}}\m\n#2}
\def\W#1#2{\def\n##1##2##3{\D{##1##2##3}{#2}}\m\n#1}
%
%  Routines to add or subtract (plus or minus) 1 from
%    a three-digit number, so we can handle 000 to 999.
%    These roll over if they go too far.
%
\def\p#1#2#3#4{
  \def\:##1#4##2##3 ##4#4 ##5##6\:{##5#1#2#3##2}
  \: 01234567890 9 \pp #4 {} \:
}
\def\pp#1#2#3{\p\drop0#2#3#1}
\def\m#1#2#3#4{
  \def\:##1#4##2##3 ##4#4 ##5##6\:{##5#1#2#3##2}
  \: 98765432109 0 \mm #4 {} \:
}
\def\mm#1#2#3{\m\drop9#2#3#1}
\def\drop#1#2#3#4{#4#2#3}
%
%  Start a dragon by placing a marker and creating the \Continue function.
%  End a dragon by continuing with the end marker, cleaning up, and then 
%    placing the board boundary.
%  
\def\Start#1#2#3{\init\Marker{green}{#1}{#2}\X{#1}{#2}#3\X}
\def\End{\C\EndMarker\Board}
\def\EndMarker#1#2\X{\EndPlace#1}
\def\EndPlace#1#2#3#4{\Marker{red}{#2}{#3}}
%
%  End the current portion of the dragon by defining a continuation 
%    function that records the current location and orientation.
%    Each continuation is done in \text{$...$} so that it gets its own
%    equation environment with its own MAXMACROS and MAXBUFFER space.
%    This lets us do multiple pieces without exceeding the limitations.
%
\def\X#1#2#3#4\X{\def\C##1{\text{$\init ##1{\D{#1}{#2}#3} \P \X$}}\let\Continue=\C}
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  These functions produce new dragons from old ones.
%  We keep a separate reversed copy so that we don't have
%  to reverse them later.
%
\def\NextDragon{\Next\Da\Db\Dq\Dr}
\def\NextBigDragon{\Next\Ba\Bb\Bq\Br}
\def\Next#1#2#3#4{
  #3\Copy\It #2\Copy\It #1\Copy\It \Define \EndD \tmpA
  #3\Copy\It #4\Copy\It #1\Copy\It \Define \EndD \tmpB
  \let#1=#2 \let#2=\tmpA
  \let#3=#4 \let#4=\tmpB
  \def\tmpA{} \let\tmpB=\tmpA
}
\def\Define#1\EndD#2{\def#2##1{##1 #1}}
\def\Copy#1\It#2\EndD{#2#1\EndD}
%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  The initial two dragons (D_0 and D_1) and their reversed versions,
%  and the initial two Big Dragons, based on them.  Big Dragons use
%  \C (\Continue) to do multiple pieces (based on the largest small
%  Dragon that can be processed within the MathJax limits).
%
\def\Da#1{#1 R} \let\Db=\Da
\def\Dq#1{#1 L} \let\Dr=\Dq
%
\def\Ba#1{#1 \C\Da} \def\Bb#1{#1 \C\Db}
\def\Bq#1{#1 \C\Dq} \def\Br#1{#1 \C\Dr}
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$

$\Dragon{002}{002} {5}{5} % Level 1 $
$\NextDragon\Dragon{002}{002} {6}{6} % Level 2 $
$\NextDragon\Dragon{003}{002} {6}{7} % Level 3 $
$\NextDragon\Dragon{005}{002} {8}{8} % Level 4 $
$\NextDragon\Dragon{007}{004} {10}{9} % Level 5 $
<br/>
$\NextDragon\Dragon{009}{007} {12}{12} % Level 6 $
$\NextDragon\Dragon{007}{012} {13}{16} % Level 7 $
$\NextDragon\Dragon{006}{015} {20}{20} % Level 8 $
<br/>
$\NextDragon\Dragon{006}{012} {28}{23} % Level 9 $
<br/>
$\NextDragon\Dragon{006}{010} {36}{36} % Level 10 $
<br/>
$\NextBigDragon$$\BigDragon{019}{009} {41}{52} % Level 11 $
<br/>
$\NextBigDragon$$\BigDragon{049}{010} {68}{68} % level 12 $
$\NextBigDragon$$\BigDragon{085}{036} {102}{79} % Level 13 $
$\NextBigDragon$$\BigDragon{113}{095} {132}{132} % Level 14 $
$\NextBigDragon$$\BigDragon{083}{164} {153}{196} % Level 15 $
$\NextBigDragon$$\BigDragon{071}{223} {262}{260} % Level 16 $
$\NextBigDragon$$\BigDragon{062}{164} {389}{302} % Level 17 $
$\NextBigDragon$$\BigDragon{071}{138} {518}{516} % Level 18 $
$\NextBigDragon$$\BigDragon{277}{121} {604}{771} % Level 19 $

$\endgroup\safe$

Decorated Dragons

Rather than "L" and "R", I thought it would be nice to use actual corners, or the classical rounded corners, and a small change to the code allows for that. Then I started to experiment with other ideas, like color. The code below allows you to select one of several different corner types. Simply include the macro that defines that type of corner and run the dragon. These are best viewed in SVG output, though most work in CommonHTML as well. PreviewHTML doesn't always work for these, unfortunately.

The following are all the level 14 dragon:

  • Using \Corners

    Level 14 dragon - angled corners

  • Using \RoundCorners

    Level 14 dragon - rounded corners

  • Using \TransparentBlocks

    Level 14 dragon - transparent colored blocks

  • Using \Diagonals

    Level 14 dragon - diagonal corners

  • Using \BlackTriangles

    enter image description here

  • Using \OpenTriangles

    enter image description here

  • Using \Paths.

    enter image description here

  • Using \RedDots. This highlights the paths from one "side" of the dragon line.

    enter image description here

  • Using \RedBlueDots. This makes dotted paths along both sets of paths, one set colored red, the other blue.

    enter image description here

See the code for additional options, and try them out.

$
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Some utility functions:
%
%
%  Make a large rectangle to surround the dragon.
%
\def\Board#1#2{\bbox[border:1px solid black]{\hskip#1ex\Rule{0ex}{#2ex}{0ex}}}
%
%  Place a letter at the right location on the board.
%
\def\Place#1#2#3{\smash{\rlap{\hskip #1ex\raise{#2ex}{#3}}}}
%
%  Place a marker with a given color at the correct place.
%
%\def\Marker#1#2#3{\Place{#2}{#3}{\color{#1}{\kern-2.25pt\raise.25pt\bigcirc}}} % for \small
%\def\Marker#1#2#3{\Place{#2}{#3}{\color{#1}{\kern2.1pt\raise.5pt\bigcirc}}}    % for \tiny
\def\Marker#1#2#3{} % don't put in markers -- comment out to show them
%
%  The shape of the corners
%
\def\Corners{
  \def\SEs{\kern.47ex\Rule{.06ex}{.53ex}{0ex}\raise.47ex{\Rule{.47ex}{.06ex}{0ex}}}
  \def\SWs{\raise.47ex{\Rule{.47ex}{.06ex}{0ex}}\Rule{.06ex}{.53ex}{0ex}}
  \def\NEn{\kern.47ex\raise.47ex{\Rule{.06ex}{.53ex}{0ex}\Rule{.47ex}{.06ex}{0ex}}}
  \def\NWn{\raise.47ex{\Rule{.47ex}{.06ex}{0ex}\Rule{.06ex}{.53ex}{0ex}}}
  \let\SEe=\SEs \let\SWw=\SWs \let\NEe=\NEn \let\NWw=\NWn
}
\def\HalfBlocks{
  \def\SEs{\kern.47ex\Rule{.53ex}{.53ex}{0ex}}
  \def\SWs{\Rule{.53ex}{.53ex}{0ex}}
  \def\NEn{\kern.47ex\raise.47ex{\Rule{.53ex}{.53ex}{0ex}}}
  \def\NWn{\raise.47ex{\Rule{.53ex}{.53ex}{0ex}}}
  \let\SEe=\SEs \let\SWw=\SWs \let\NEe=\NEn \let\NWw=\NWn
}
\def\TransparentBlocks{
  \def\SEs{\style{opacity:.5}{\color{red}{\Rule{1ex}{1ex}{0ex}}}}
  \def\SWs{\style{opacity:.5}{\color{blue}{\Rule{1ex}{1ex}{0ex}}}}
  \def\NEn{\style{opacity:.5}{\color{green}{\Rule{1ex}{1ex}{0ex}}}}
  \def\NWn{\style{opacity:.5}{\color{orange}{\Rule{1ex}{1ex}{0ex}}}}
  \let\SEe=\SEs \let\SWw=\SWs \let\NEe=\NEn \let\NWw=\NWn
}
\def\RoundCorners{
  \def\SEs{\style{font-size:85%}{\unicode{x256D}}}
  \def\SWs{\style{font-size:85%}{\unicode{x256E}}}
  \def\NEn{\style{font-size:85%}{\unicode{x2570}}}
  \def\NWn{\style{font-size:85%}{\unicode{x256F}}}
  \let\SEe=\SEs \let\SWw=\SWs \let\NEe=\NEn \let\NWw=\NWn
}
\def\Diagonals{
  \def\SEs{\hskip.5ex\style{font-size:28%}{\unicode{x2571}}}
  \def\SWs{\style{font-size:28%}{\unicode{x2572}}}
  \def\NEn{\hskip.5ex\raise.5ex{\style{font-size:28%}{\unicode{x2572}}}}
  \def\NWn{\raise.5ex{\style{font-size:28%}{\unicode{x2571}}}}
  \let\SEe=\SEs \let\SWw=\SWs \let\NEe=\NEn \let\NWw=\NWn
}
\def\OpenTriangles{
  \def\SEs{\hskip.5ex\style{font-size:25%}{\unicode{x25FF}}}
  \def\SWs{\style{font-size:25%}{\unicode{x25FA}}}
  \def\NEn{\hskip.5ex\raise.5ex{\style{font-size:25%}{\unicode{x25F9}}}}
  \def\NWn{\raise.5ex{\style{font-size:25%}{\unicode{x25F8}}}}
  \let\SEe=\SEs \let\SWw=\SWs \let\NEe=\NEn \let\NWw=\NWn
}
\def\BlackTriangles{
  \def\SEs{\hskip.5ex\style{font-size:25%}{\unicode{x25E2}}}
  \def\SWs{\style{font-size:25%}{\unicode{x25E3}}}
  \def\NEn{\hskip.5ex\raise.5ex{\style{font-size:25%}{\unicode{x25E5}}}}
  \def\NWn{\raise.5ex{\style{font-size:25%}{\unicode{x25E4}}}}
  \let\SEe=\SEs \let\SWw=\SWs \let\NEe=\NEn \let\NWw=\NWn
}
\def\Paths{
  \def\SEs{
    \style{opacity:.25}{\color{red}{\Rule{1ex}{1ex}{0ex}}}
    \hskip-.5ex\raise.08ex{\style{font-size:25%; opacity:.25}{\color{blue}{\unicode{x25E2}}}}
  }
  \def\SWs{
    \style{opacity:.25}{\color{blue}{\Rule{1ex}{1ex}{0ex}}}
    \hskip-1ex\raise.08ex{\style{font-size:25%; opacity:.25}{\color{red}{\unicode{x25E3}}}}
  }
  \def\NEn{
    \style{opacity:.25}{\color{blue}{\Rule{1ex}{1ex}{0ex}}}
    \hskip-.5ex\raise.58ex{\style{font-size:25%; opacity:.25}{\color{red}{\unicode{x25E5}}}}
  }
  \def\NWn{
    \style{opacity:.25}{\color{red}{\Rule{1ex}{1ex}{0ex}}}
    \hskip-1ex\raise.58ex{\style{font-size:25%; opacity:.25}{\color{blue}{\unicode{x25E4}}}}
  }
  \def\SEe{
    \style{opacity:.25}{\color{blue}{\Rule{1ex}{1ex}{0ex}}}
    \hskip-.5ex\raise.08ex{\style{font-size:25%; opacity:.25}{\color{red}{\unicode{x25E2}}}}
  }
  \def\SWw{
    \style{opacity:.25}{\color{red}{\Rule{1ex}{1ex}{0ex}}}
    \hskip-1ex\raise.08ex{\style{font-size:25%; opacity:.25}{\color{blue}{\unicode{x25E3}}}}
  }
  \def\NEe{
    \style{opacity:.25}{\color{red}{\Rule{1ex}{1ex}{0ex}}}
    \hskip-.5ex\raise.58ex{\style{font-size:25%; opacity:.25}{\color{blue}{\unicode{x25E5}}}}
  }
  \def\NWw{
    \style{opacity:.25}{\color{blue}{\Rule{1ex}{1ex}{0ex}}}
    \hskip-1ex\raise.58ex{\style{font-size:25%; opacity:.25}{\color{red}{\unicode{x25E4}}}}
  }
}
\def\BlueDots{
 \def\SEs{\hskip.5ex\style{font-size:25%}{\unicode{x25FF}}}
  \def\SWs{\color{blue}{\rlap{\hskip.45ex\raise.1ex.}}\style{font-size:25%}{\unicode{x25FA}}}
  \def\NEn{\color{blue}{\rlap{\hskip.1ex\raise.5ex.}}\hskip.5ex\raise.45ex{\style{font-size:25%}{\unicode{x25F9}}}}
  \def\NWn{\raise.5ex{\style{font-size:25%}{\unicode{x25F8}}}}
  \def\SEe{\color{blue}{\rlap{\hskip.45ex\raise.5ex.}}\hskip.5ex\style{font-size:25%}{\unicode{x25FF}}}
  \def\SWw{\style{font-size:25%}{\unicode{x25FA}}}
  \def\NEe{\hskip.5ex\raise.5ex{\style{font-size:25%}{\unicode{x25F9}}}}
  \def\NWw{\color{blue}{\rlap{\hskip.1ex\raise.1ex.}}\raise.5ex{\style{font-size:25%}{\unicode{x25F8}}}}
}
\def\RedDots{
  \def\SEs{\hskip.5ex\style{font-size:25%}{\unicode{x25E2}}}
  \def\SWs{\color{red}{\rlap{\hskip.45ex\raise.1ex.}}\style{font-size:25%}{\unicode{x25E3}}}
  \def\NEn{\color{red}{\rlap{\hskip.1ex\raise.5ex.}}\hskip.5ex\raise.45ex{\style{font-size:25%}{\unicode{x25E5}}}}
  \def\NWn{\raise.5ex{\style{font-size:25%}{\unicode{x25E4}}}}
  \def\SEe{\color{red}{\rlap{\hskip.45ex\raise.5ex.}}\hskip.5ex\style{font-size:25%}{\unicode{x25E2}}}
  \def\SWw{\style{font-size:25%}{\unicode{x25E3}}}
  \def\NEe{\hskip.5ex\raise.5ex{\style{font-size:25%}{\unicode{x25E5}}}}
  \def\NWw{\color{red}{\rlap{\hskip.1ex\raise.1ex.}}\raise.5ex{\style{font-size:25%}{\unicode{x25E4}}}}
}
\def\RedBlueDots{
  \def\SEs{\color{blue}{\rlap{\hskip.1ex\raise.1ex.}}\hskip.5ex\style{font-size:25%}{\unicode{x25E2}}}
  \def\SWs{\color{red}{\rlap{\hskip.45ex\raise.1ex.}}\style{font-size:25%}{\unicode{x25E3}}}
  \def\NEn{\color{red}{\rlap{\hskip.1ex\raise.5ex.}}\hskip.5ex\raise.45ex{\style{font-size:25%}{\unicode{x25E5}}}}
  \def\NWn{\color{blue}{\rlap{\hskip.45ex\raise.5ex.}}\raise.5ex{\style{font-size:25%}{\unicode{x25E4}}}}
  \def\SEe{\color{red}{\rlap{\hskip.45ex\raise.5ex.}}\hskip.5ex\style{font-size:25%}{\unicode{x25E2}}}
  \def\SWw{\color{blue}{\rlap{\hskip.1ex\raise.5ex.}}\style{font-size:25%}{\unicode{x25E3}}}
  \def\NEe{\color{blue}{\rlap{\hskip.45ex\raise.1ex.}}\hskip.5ex\raise.5ex{\style{font-size:25%}{\unicode{x25E5}}}}
  \def\NWw{\color{red}{\rlap{\hskip.1ex\raise.1ex.}}\raise.5ex{\style{font-size:25%}{\unicode{x25E4}}}}
}
\RoundCorners
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Create a dragon from the currently saved dragon string starting
%    at the given location on the board, or a big dragon from
%    the last big dragon collections.
%
\def\Dragon#1#2{\Start{#1}{#2}\E \Continue\Db \End}
\def\BigDragon#1#2{\Start{#1}{#2}\E \Bq{}\Bb{}\Ba{} \End}
%
%  Check if there are more letters and call \P if so and \X if not.
%
\def\D#1 #2#3 #4{#4#1 #2#3 #4}
%
%  Place the letter at the current location.
%  Then define \T to determine the new orientation from
%    the current one and the current letter.
%  Perform the orientation command in order to move to the new location.
%
\def\P#1#2#3#4{
  \def\T##1#4#3 ##2##3##4\T{\Place{#1}{#2}##3 ##2{#1}{#2}##2 }
  \T L\E \N\NWw  R\E \S\SWw  L\S \E\NEn  R\S \W\NWn  L\W \S\SEe
     R\W \N\NEe  L\N \W\SWs  R\N \E\SEs  \T
}
%
%  These are the commands to move in the given direction.
%
\def\N#1#2{\def\n##1##2##3{\D{#1}{##1##2##3}}\p\n#2}
\def\E#1#2{\def\n##1##2##3{\D{##1##2##3}{#2}}\p\n#1}
\def\S#1#2{\def\n##1##2##3{\D{#1}{##1##2##3}}\m\n#2}
\def\W#1#2{\def\n##1##2##3{\D{##1##2##3}{#2}}\m\n#1}
%
%  Routines to add or subtract (plus or minus) 1 from
%    a three-digit number, so we can handle 000 to 999.
%    These roll over if they go too far.
%
\def\p#1#2#3#4{
  \def\:##1#4##2##3 ##4#4 ##5##6\:{##5#1#2#3##2}
  \: 01234567890 9 \pp #4 {} \:
}
\def\pp#1#2#3{\p\drop0#2#3#1}
\def\m#1#2#3#4{
  \def\:##1#4##2##3 ##4#4 ##5##6\:{##5#1#2#3##2}
  \: 98765432109 0 \mm #4 {} \:
}
\def\mm#1#2#3{\m\drop9#2#3#1}
\def\drop#1#2#3#4{#4#2#3}
%
%  Start a dragon by placing a marker and creating the \Continue function.
%  End a dragon by continuing with the end marker, cleaning up, and then 
%    placing the board boundary.
%  
\def\Start#1#2#3{\Marker{green}{#1}{#2}\X{#1}{#2}#3\X}
\def\End{\C\EndMarker\Board}
\def\EndMarker#1#2\X{\EndPlace#1}
\def\EndPlace#1#2#3#4{\Marker{red}{#2}{#3}}
%
%  End the current portion of the dragon by defining a continuation 
%    function that records the current location and orientation.
%    Each continuation is done in \text{$...$} so that it gets its own
%    equation environment with its own MAXMACROS and MAXBUFFER space.
%    This lets us do multiple pieces without exceeding the limitations.
%
\def\X#1#2#3#4\X{\def\C##1{\text{$##1{\D{#1}{#2}#3} \P \X$}}\let\Continue=\C}
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  These functions produce new dragons from old ones.
%  We keep a separate reversed copy so that we don't have
%  to reverse them later.
%
\def\NextDragon{\Next\Da\Db\Dq\Dr}
\def\NextBigDragon{\Next\Ba\Bb\Bq\Br}
\def\Next#1#2#3#4{
  #3\Copy\It #2\Copy\It #1\Copy\It \Define \EndD \tmpA
  #3\Copy\It #4\Copy\It #1\Copy\It \Define \EndD \tmpB
  \let#1=#2 \let#2=\tmpA
  \let#3=#4 \let#4=\tmpB
  \def\tmpA{} \let\tmpB=\tmpA
}
\def\Define#1\EndD#2{\def#2##1{##1 #1}}
\def\Copy#1\It#2\EndD{#2#1\EndD}
%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  The initial two dragons (D_0 and D_1) and their reversed versions,
%  and the initial two Big Dragons, based on them.  Big Dragons use
%  \C (\Continue) to do multiple pieces (based on the largest small
%  Dragon that can be processed within the MathJax limits).
%
\def\Da#1{#1 R} \let\Db=\Da
\def\Dq#1{#1 L} \let\Dr=\Dq
%
\def\Ba#1{#1 \C\Da} \def\Bb#1{#1 \C\Db}
\def\Bq#1{#1 \C\Dq} \def\Br#1{#1 \C\Dr}
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$

$\NextDragon\NextDragon\NextDragon\NextDragon\NextDragon$
$\NextDragon\NextDragon\NextDragon\NextDragon$
$\NextBigDragon\NextBigDragon\NextBigDragon$
$\RoundCorners$
$\BigDragon{113}{095} {132}{132} % Level 14 (9 sec) $
$\endgroup$
17
  • 2
    $\begingroup$ I could not help working on this (when I should have been doing other things), @humn, so I spent three hours coming up with a preliminary solution. I have posted a version that works up to level 11 without adjusting the MathJax parameters. I haven't spent any time optimizing it, but just wanted to get something that works. See the caveat about using CommonHTML output rather than the default HTML-CSS, however. $\endgroup$ Commented Aug 10, 2016 at 19:25
  • 1
    $\begingroup$ Yow! And in a fraction of the coding time it took for my test version. And an even smaller fraction of the run time (9 secs vs 2 mins for level 11 locally, and that's only after reducing inner-loop macros to single letters). Isn't it a gas to make fractals with MathJax? Ah, stolen moments. And thanks, of course, for the lessons on HTML options and on revising macro definitions ($\small\texttt{\Define{}}$), along with other lessons yet to register. $\endgroup$
    – humn
    Commented Aug 10, 2016 at 20:35
  • 1
    $\begingroup$ It's art, ain't it though? Here's a quick experiment that indicates how level 19 tiles. (Preparing a 62-token $\small\texttt{\stars{}}$ post now. It's almost neat enough to be mistaken for something you'd figure out. Well, most of it you did. Thanks for leaving some elbow room, much of it for the sake of clarity no doubt.) $\endgroup$
    – humn
    Commented Aug 14, 2016 at 12:51
  • 1
    $\begingroup$ I've added some new code and images to my answer, @humn. Thought you might enjoy some decorated dragons (near the bottom of the answer). $\endgroup$ Commented Aug 14, 2016 at 21:25
  • 1
    $\begingroup$ Oooooh, and, ahhhhh. \Corners is classic fractalania. \RoundCorners sweetly verifies non-crossing. \TransparentBlocks reveals a substructure reminiscent of Greek fretwork and the Hilbert curve. Except for having recreational provenance these mathterpieces would feel right at home in your gallery or somewhere like MathJax's portfolio. Letters were just clues, and you sure do have more than a clue. $\endgroup$
    – humn
    Commented Aug 14, 2016 at 22:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.