Message Boards Message Boards

Programmatic ASCII art - creative, scalable, dynamic, and beyond

Posted 11 years ago
Please feel free to share your ideas!

I can occasionally appreciate a nice ASCII art design. But the better is the design, the more manual and custom approach it needs – or so it seems. It is actually quite challenging, if you think about it, to transform a known image or shape to a limited medium using finite set of geometries. So the question is: are there some nice programmable cases? I got inspired by a recent challenge Make a scalable Christmas tree on a code-golf site. A Christmas tree is indeed a good shape for scalable design. Here is the result with full code and explanations below. BTW watch tree carefully – it changes too ;-)



We can start with something very simple, a one-liner, – just picking some nice symbols for snow and tree needles – and then picking them at random:
Column[Table[Row[RandomChoice[{"+", ".", "*", "~", "^", "o"}, k]], {k, 1, 35, 2}], Alignment -> Center]



Which already looks nice and in the true spirit ASCII. It is also scalable – just increases the size inside the Table. But now we can even add a bit of dynamics to this. It’d be great to have falling snow. How to make it a bit real? We will make it to fall in a straight-down path rarely shifting it randomly to the left or right. Basically our snow will make a lazy random walk. But then if two different snowflakes meet – how do they overlap or pass through each other? These are just characters in a List, so how to accomplish this? Well we can be a bit inventive to avoid the overlap problem. If we place one and only one snowflake in every row, and then shift down 1 step simultaneously for all of them, then no matter what left-right shifts are – snowflakes will never collide. What else could we do? We could create an illusion that snow sometimes sticks to the branches and then falls. For this we do not need to actually correlate snow and tree. We could just randomly replace symbols in the tree and that will be enough for a good ASCII visual. Snow symbols will be white puffs or snowflakes and tree symbols will be green. Note the controlled Dynamic updates too. Here we go.

 DynamicModule[{atoms, tree, pos, snow, p = .8, sz = 15},
 
  atoms = {
    Style["+", White],
    Style["*", White],
    Style["o", White],
    Style[".", Green],
    Style["~", Green],
    Style["^", Green],
   Style["^", Green]
   };

pos = Flatten[Table[{m, n}, {m, 18}, {n, 2 m - 1}], 1];
tree = Table[RandomChoice[atoms, k], {k, 1, 35, 2}];
snow = Table[RotateLeft[ArrayPad[{RandomChoice[atoms[[1 ;; 2]]]}, {0, sz}, " "], RandomInteger[sz]], {sz + 1}];

Dynamic[Refresh[

   Overlay[{

     tree[[Sequence @@ RandomChoice[pos]]] = RandomChoice[atoms];
     Column[Row /@ tree, Alignment -> Center, Background -> Black],

     Grid[snow = RotateRight[
        RotateLeft[#, RandomChoice[{(1 - p)/2, p, (1 - p)/2} -> {-1, 0, 1}]] & /@ snow, {1, 0}]]
    
     }, Alignment -> Center],

   UpdateInterval -> .1, TrackedSymbols -> {}]
  ]
]
POSTED BY: Vitaliy Kaurov
3 Replies
Another idea is to animate already existing ASCII art. For example, by copying the data given at the end into a .TXT files we can create flag animations. My example choice was beautiful US Ohio State Flag designed by John Eisemann for the 1901 Pan-American Exposition; - the only American state flag that is non-rectangular, and one of only two non-rectangular official jurisdictional flags, at the state level or above, in the world (the other is the flag of Nepal). And of course, a pirate flag, was the other example. We could not miss out on a pirate flag, and it came out pretty creepy ;-) Once you save data I gave at the end of the post (found randomly online) into two .TXT files pirate.txt and ohio.txt - execute the following code:
data = Characters /@ StringSplit[Import["pirate.txt"], "\n"];
td = Transpose[data];
lngz = Length[td];

Animate[Grid[Transpose[
   MapIndexed[RotateLeft[#1, Round[Sin[2 (First[#2] - k) 2 Pi/lngz]]] &, Transpose[data]]], Spacings -> {0, 0}]
, {k, 1, lngz, 1}]

or to make a .GIF you see here:
frames = Table[
   Grid[Transpose[MapIndexed[RotateLeft[#1, Round[Sin[2 (First[#2] - k) 2 Pi/lngz]]] &, Transpose[data]]], Spacings -> {0, 0}]
   , {k, 1, lngz, 1}];

Export["pirate.gif", frames]






This is the data. Note, you have to have exactly square array of symbols, so do not miss any blank spaces.

 
  ||                                                            
  ||                                                            
  ||.__                                                         
  ||`\##`--.__                                                   
  ||  `\######`--.__                                             
  ||    `\##########`--.__                                       
  ||      `\##############`--.__                                 
  ||     *  `\'#################`--.__                           
||          `\  '###################`--.__                     
|| *          `\     '####################`--.__               
||              `\       '######################`--.__         
||                `\            '#####################`--.__   
||           *      `\                '#####################`-.
||      *         *   `\                    '#############_.-'
||       .''''''''.     `\                        '####.-'    
||  *   ' .######. '.     `\                   __.-'~~         
||    .` .########. `.      `\##############.-'               
||   .' .##########. `.    *  `\#########.-'                  
|| * :  ############  : *     * >#######<                     
||   `. '##########' .'    *   /##########`-._                
||    '. '########' .'       /############### `--._            
||  *  '. '######' .'      /'                      `--._      
||       `'.......'      /'                        .####'--._ 
||      *          *   /'                    '############## `-
||           *       /'                .###################.-'/
||                 /'           .####################.--'~~   
||               /'       .#####################.--'~~         
||  *          /'    .####################.--'~~               
||           /' .###################.--'~~                     
||      *  /'#################.--'~~                           
||       /##############.--'~~                                 
||     /##########.--'~~                                       
||   /#######.--'~~                                           
|| /##.--'~~                                                   
||'~~~                                                         
||                                                            
||                                                            
||                                                            


 
  .=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-.
  |                     ______                     |
  |                  .-"      "-.                  |
  |                 /            \                 |
  |     _          |              |          _     |
  |    ( \         |,  .-.  .-.  ,|         / )    |
  |     > "=._     | )(__/  \__)( |     _.=" <     |
  |    (_/"=._"=._ |/     /\     \| _.="_.="\_)    |
|           "=._"(_     ^^     _)"_.="           |
|               "=\__|IIIIII|__/="               |
|              _.="| \IIIIII/ |"=._              |
|    _     _.="_.="\          /"=._"=._     _    |
|   ( \_.="_.="     `--------`     "=._"=._/ )   |
|    > _.="                            "=._ <    |
|   (_/   jgs                              \_)   |
|                                                |
'-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-='
POSTED BY: Sam Carrettie
Posted 11 years ago
I like it! The ASCII purist in me questions the validity of overlaying multiple characters at the same position (should a snow character replace a tree character when passing by?), but I'll settle for a minor tweak that scales the two layers to be exactly the same size.
 DynamicModule[{atoms, tree, pos, snow, p = .8, sz = 15},
  atoms = {Style["+", White], Style["*", White], Style["o", White],
    Style[".", Green], Style["~", Green], Style["^", Green],
    Style["^", Green]};
  pos = Flatten[Table[{m, n}, {m, 18}, {n, 2 m - 1}], 1];
  tree = Table[RandomChoice[atoms, k], {k, 1, 35, 2}];
  snow = Table[
    RotateLeft[
     ArrayPad[{RandomChoice[atoms[[1 ;; 2]]]}, {0, 2 sz + 4}, " "],
    RandomInteger[2 sz + 3]], {sz + 3}];
Dynamic[Refresh[
   Overlay[{tree[[Sequence @@ RandomChoice[pos]]] =
      RandomChoice[atoms];
     Column[Row[#, ImageSize -> {Automatic, 12}] & /@ tree,
      Alignment -> Center, Background -> Black],
     Column[Row[#, ImageSize -> {Automatic, 12}] & /@ (snow =
         RotateRight[
          RotateLeft[#,
             RandomChoice[{(1 - p)/2, p, (1 - p)/2} -> {-1, 0,
                1}]] & /@ snow, {1, 0}])]}], UpdateInterval -> .1,
   TrackedSymbols -> {}]]]
POSTED BY: Michael Hale
Posted 11 years ago
Amazing! Congratulations Vitaly
POSTED BY: Luis Ledesma
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract