/*
 * History : Written by tjalk.cs.vu.nl	( I got no name from the article)
 *
 * Hacked to use termcap by: Josh Siegel (josh@hi.unm@hc.dspo.gov)
 *
 *
 * Please note, The hack that handles loading the atributes into the system
 * is exactly that... a hack.  I had little time and little want to make
 * it better.
 *
 *
 * --Josh Siegel
 *
 * Re-hacked by: Tom Hageman.
 */

char Zoo[] = "*#Ox@~.+!&%$'`=-oXwW()^~*#x0@+./";	/* welcome to the Zoo */

#define MaxNrOfWorms (sizeof Zoo - 1)

#define MaxLength   64		/* This really is long enough! */
int		ScreenWidth;
int		ScreenHeigth;
char		*cm, *cl, *vi, *ve;


#include <stdio.h>
#include <signal.h>

char		*strcpy();
void		end();

int		wormlength = 20;/* 20 by default, can be redefined by
				 * -l<nr> */
int		nrofworms = 3;	/* 3 by default, can be redefined by
				 * -n<nr> */
char	       *message = "				W O R M S ! ! !";
/* message can be redifined by -m<string> */

int		x_direction[8] = {1, 1, 0, -1, -1, -1, 0, 1};
int		y_direction[8] = {0, 1, 1, 1, 0, -1, -1, -1};

int		screen[100][100];

main(argc, argv)
  char		**argv;

{
  int		  wormx[MaxNrOfWorms][MaxLength], wormy[MaxNrOfWorms][MaxLength];
  int		  dir[MaxNrOfWorms], i, j;
  int		  ptr1, ptr2, x, y, *direction;
  long		  dummy;
  char		 *pos();


  setbuf(stdout, NULL);
  /* First test for any flags... */

  for (i = 1; i < argc; i++)
    if (argv[i][0] == '-') {
      switch (argv[i][1]) {
      case 'l':
      case 'L':
	if (
	    sscanf(argv[i], "-l%d", &wormlength) == 0 ||
	    wormlength < 2 || wormlength > MaxLength) {
	  puts("Bad length.");
	  exit(1);
	} break;
      case 'n':
      case 'N':
	if (
	    sscanf(argv[i], "-n%d", &nrofworms) == 0 ||
	    nrofworms < 1 || nrofworms > MaxNrOfWorms) {
	  puts("Bad number of worms.");
	  exit(1);
	} break;
      case 'm':
      case 'M':
	message = argv[i] + 2;
	break;
      default:
	printf(" -%c: bad option.\n", argv[i][1]);
	exit(1);
      }
    } else {
      printf("Syntax: %s [ -l<nr> ] [ -n<nr> ] \
[ -m<message> ]\n", argv[0]);
      exit(1);
    }

  /* Now let's initialize !! */

  initsys();
  if (vi) puts(vi);
  signal(SIGINT, end);
  clear_screen();
  printf("%s%s", pos(0, 22), message);

  for (j = 0; j < nrofworms; j++) {
    for (i = 0; i < wormlength; i++)
      wormx[j][i] = wormy[j][i] = 0;
    dir[j] = 1; 		/* direction of worm j */
  }

  screen[0][0] = nrofworms * wormlength;
  ptr1 = ptr2 = 0;
  /* They point to the front and the back of a worm, respectively. */


  /* init randomizer... I hope this will work, it works on UNIX */
  srand((int) time(&dummy));




  while (1) {
    ptr2 = (ptr1 + 1) % wormlength;
    /* Take the next part of each worm. */

    for (i = 0; i < nrofworms; i++) {
      int	      enough = 0;

      x = wormx[i][ptr2];
      y = wormy[i][ptr2];
      /*
       * x and y are the coordinates of the tail of worm i, which has
       * to be removed.
       */
      if ((--screen[x][y]) == 0)
	printf("%s ", pos(x,y));

      /*
       * It will only be removed when there are no other "parts" of
       * worms on that spot on the screen.
       */

      /* Now put a head somewhere. */
      /*
       * We'll modify the direction just until we've got a correct
       * direction (so that the worm will not cross or	overlap another
       * worm or itself, nor will run of the screen),  or that we've had
       * enough,  since than there probably is no such direction.
       */

      direction = &dir[i];

      do
	*direction = (*direction + (rand()) % 3 + 7) % 8;
      while ((x = wormx[i][ptr1] + x_direction[*direction]) < 0 ||
	     x > ScreenWidth - 1 ||
	     (y = wormy[i][ptr1] + y_direction[*direction]) < 0 ||
	     y > ScreenHeigth - 2 ||
	     ((screen[x][y] != 0 || cross(x, y, *direction))
	      && enough++ < 19));

      if (enough >= 19) {	/* We can't move this poor worm */
	x = wormx[i][ptr1];	/* old coordinates  */
	y = wormy[i][ptr1];
      }
      /*
       * x and y now contain the new coordinates of the worms head. Let's
       * just place it on the screen (and in memory)
       */
      wormx[i][ptr2] = x;
      wormy[i][ptr2] = y;
      printf("%s%c", pos(x, y), Zoo[i]);
      screen[x][y]++;
    }
    ptr1 = ptr2;
  }
}




cross(x, y, d)
{				/* keeps two worms from crossing */
  if (d & 1 == 0)
    return 0;			/* worm moving diagonally? */

  return (screen[x][y - y_direction[d]] && screen[x - x_direction[d]][y]);
}

/*
 * I assume there are betters ways of doing this but since I had no
 * interest in spending more then 5 minutes making this use termcap ...
 */

initsys()
{
  static char	strs[100];
  char		bp[2048];
  char		 *p1 = strs, *getenv(), *tgetstr();

  if (tgetent(bp, getenv("TERM")) <= 0) {
	printf("tgetent failed for terminal \"%s\"\n", getenv("TERM"));
	exit(1);
  }
  cl = tgetstr("cl", &p1);
  cm = tgetstr("cm", &p1);
  vi = tgetstr("vi", &p1);
  ve = tgetstr("ve", &p1);
  if ((ScreenHeigth = tgetnum("li") - 1) > 99) {
    ScreenHeigth = 99;
  }
  if ((ScreenWidth = tgetnum("co") - 1) > 99) {;
    ScreenWidth = 99;
  }
  if (!cm || ScreenWidth < 0 || ScreenHeigth < 0) {
	printf("Terminal \"%s\" is too dumb to run worms.\n", getenv("TERM"));
	exit(1);
  }	
}

static char	*out_p;
static
outc(c)
{
	if (c)
		*out_p++ = c;
}

short	ospeed;		/* for tputs */
char	PC;

char	       *
pos(x, y)
{
  static char	result[40];

  char		 *ret, *tgoto();

  out_p = result;
  tputs(tgoto(cm, x, y), 1, outc);
  *out_p = '\0';
  return result;
}



clear_screen()
{
  if (cl) puts(cl);
}


/* catch signal */

void end(sig)
{
	if (ve) puts(ve);
	clear_screen();
	exit(0);
}
