#include <stdio.h>

#define BOXMAX 13
#define WIDTH 5 
#define HEIGHT 2
#define LEFT (40-((BOXMAX * WIDTH) / 2))

#define ESC 0x1b

typedef (*fnptr) ();

unsigned int box [BOXMAX][4];

/***************************************************************************/
param (limit)
  unsigned int limit;
{
  if (limit >= 100)
    fputc ('0' + (limit / 100), stdout);
  if (limit >= 10)
    fputc ('0' + ((limit / 10) % 10), stdout);
  fputc ('0' + (limit % 10), stdout);
}
/***************************************************************************/
crlf ()
{
  fputc ('\r', stdout);
  fputc ('\n', stdout);
}
/***************************************************************************/
eos ()
{
  fputc (ESC, stdout);
  fputc ('[', stdout);
  fputc ('2', stdout);
  fputc ('J', stdout);
}
/***************************************************************************/
home ()
{
  fputc (ESC, stdout);
  fputc ('[', stdout);
  fputc ('H', stdout);
}
/***************************************************************************/
clear ()
{
  fputc (ESC, stdout);
  fputc ('[', stdout);
  fputc ('r', stdout);
  fputc (ESC, stdout);
  fputc ('[', stdout);
  param (40);
  fputc ('m', stdout);
  eos ();
  crlf ();
}
/***************************************************************************/
sgr (index)
{
  fputc (ESC, stdout);
  fputc ('[', stdout);
  param (41 + index % 3);
  fputc ('m', stdout);
}
/***************************************************************************/
ssr (region)
  unsigned int region [4];
{
  fputc (ESC, stdout);
  fputc ('[', stdout);
  param (region [0]);
  fputc (';', stdout);
  param (region [1]);
  fputc (';', stdout);
  param (region [2]);
  fputc (';', stdout);
  param (region [3]);
  fputc ('r', stdout);
}
/***************************************************************************/
su (level)
  unsigned int level;
{
  unsigned int region [4];
  int index;

  region [0] = box [level] [0] - HEIGHT;
  region [1] = box [level] [1];
  region [2] = box [level] [2];
  region [3] = box [level] [3];
  ssr (region);
  home ();
  sgr (level + 1);
  fputc (ESC, stdout);
  fputc ('[', stdout);
  param (HEIGHT);
  fputc ('S', stdout);
  for (index = level;
       index >= 0;
       index--)
  {
    box [index] [0] -= HEIGHT;
    box [index] [1] -= HEIGHT; 
  }    
  crlf ();
}
/***************************************************************************/
sd (level)
  unsigned int level;
{
  unsigned int region [4];
  int index;

  region [0] = box [level] [0];
  region [1] = box [level] [1] + HEIGHT;
  region [2] = box [level] [2];
  region [3] = box [level] [3];
  ssr (region);
  home ();
  sgr (level + 1);
  fputc (ESC, stdout);
  fputc ('[', stdout);
  param (HEIGHT);
  fputc ('T', stdout);
  for (index = level;
       index >= 0;
       index--)
  {
    box [index] [0] += HEIGHT;
    box [index] [1] += HEIGHT; 
  }    
  crlf ();
}
/***************************************************************************/
sr (level)
  unsigned int level;
{
  unsigned int region [4];
  int index;

  region [0] = box [level] [0];
  region [1] = box [level] [1];
  region [2] = box [level] [2];
  region [3] = box [level] [3] + WIDTH;
  ssr (region);
  home ();
  sgr (level + 1);
  fputc (ESC, stdout);
  fputc ('[', stdout);
  param (WIDTH);
  fputc (' ', stdout);
  fputc ('A', stdout);
  for (index = level;
       index >= 0;
       index--)
  {
    box [index] [2] += WIDTH;
    box [index] [3] += WIDTH;
  }    
  if (region [1] - region [0])
    crlf ();
}
/***************************************************************************/
sl (level)
  unsigned int level;
{
  unsigned int region [4];
  int index;

  region [0] = box [level] [0];
  region [1] = box [level] [1];
  region [2] = box [level] [2] - WIDTH;
  region [3] = box [level] [3];
  ssr (region);
  home ();
  sgr (level + 1);
  fputc (ESC, stdout);
  fputc ('[', stdout);
  param (WIDTH);
  fputc (' ', stdout);
  fputc ('@', stdout);
  for (index = level;
       index >= 0;
       index--)
  {
    box [index] [2] -= WIDTH;
    box [index] [3] -= WIDTH;
  }    
  if (region [1] - region [0])
    crlf ();
}
/***************************************************************************/
fnptr sx [] =
  {&sr, &sd, &sl, &su}; 
/***************************************************************************/
scroll (level, way)
  unsigned int level;
  unsigned int way;
{
  if (way)
    if (box [level] [0] == box [level + 1] [0])
      if (box [level] [2] == box [level + 1] [2])
	sr (level);
      else
	sd (level);
    else
      if (box [level] [2] == box [level + 1] [2])
	su (level);
      else
	sl (level);
  else
    if (box [level] [0] == box [level + 1] [0])
      if (box [level] [2] == box [level + 1] [2])
	sd (level);
      else
	sl (level);
    else
      if (box [level] [2] == box [level + 1] [2])
	sr (level);
      else
	su (level);
}
/***************************************************************************/
paint ()
{
  unsigned int index;

  clear ();
  for (index = 0;
       index < BOXMAX;
       index++)
  {
    box [index] [0] = 1;
    box [index] [1] = 1 + (HEIGHT * index);
    box [index] [2] = 1 + LEFT;
    box [index] [3] = 1 + (LEFT + (WIDTH * index));
  }
  for (index = BOXMAX;
       index-- > 0;
       )
  {
    ssr (box [index]);
    sgr (index);
    eos ();
    crlf ();
  }
}
/***************************************************************************/
cycleclock ()
{
  unsigned int level;
  unsigned int direction;

  paint ();
  for (level = 0;
       level < (BOXMAX - 1);
       ++level)
    for (direction = 0;
         direction < 4;
         ++direction)
      scroll (level, 1);  
}
/***************************************************************************/
cyclecounter ()
{
  unsigned int level;
  unsigned int direction;

  paint ();
  for (level = 0;
       level < (BOXMAX - 1);
       ++level)
    for (direction = 4;
         direction-- > 0;
         )
      scroll (level, 0);  
}
/***************************************************************************/
cyclealternate ()
{
  unsigned int level;
  unsigned int direction;

  paint ();
  for (level = 0;
       level < (BOXMAX - 1);
       ++level)
    for (direction = 0;
         direction < 4;
         ++direction)
      scroll (level, (level & 0x0001));
}
/***************************************************************************/
stepclock ()
{
  unsigned int level;
  unsigned int direction;

  paint ();
  for (direction = 0;
       direction < 4;
       ++direction)
    for (level = 0;
         level < (BOXMAX - 1);
         ++level)
      scroll (level, 1);  
}
/***************************************************************************/
stepcounter ()
{
  unsigned int level;
  unsigned int direction;

  paint ();
  for (direction = 0;
       direction < 4;
       ++direction)
    for (level = 0;
         level < (BOXMAX - 1);
         ++level)
      scroll (level, 0);  
}
/***************************************************************************/
stepalternate ()
{
  unsigned int level;
  unsigned int direction;

  paint ();
  for (direction = 0;
       direction < 4;
       ++direction)
    for (level = 0;
         level < (BOXMAX - 1);
         ++level)
      scroll (level, ((level + direction) & 0x0001));  
}
/***************************************************************************/
main ()
{
  cycleclock ();
  cyclecounter ();
  cyclealternate ();
  stepclock ();
  stepcounter ();
  stepalternate ();
  clear ();
}
/***************************************************************************/
