/****************************************************************************
 **
 **    Jed's Quick and dirty automata engine
 **    June 1994
 ****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
/*****************************************************************************
 ** datatypes
 ****************************************************************************/
#define PM fprintf(stdout, " ** "); fflush(stdout);
#define FF fflush(stdout);
#define DB_
#define TOP 0
#define BOTTOM 22
#define LEFT 0
#define RIGHT 30
#define INTERATIONS 5
#define MAXNEIGHBORS 8
#define EXCESS 5
#define LOVE 3
#define LONELY 1
#define SLEEPYTIME 1
/* matrix of cells */
typedef int Matrix[BOTTOM][RIGHT];

/****************************************************************************
 ** forward declarations
 ****************************************************************************/
void Display_Matrix(Matrix m);
void Interate_Matrix(Matrix Master, Matrix Copy);
void Live(int x, int y, Matrix m);
void Die(int x, int y, Matrix m);
void Live_on(int i, int j, Matrix m, Matrix n);
int Neighbors(int i, int j, Matrix m);
int Cell(int i, int j, Matrix m);
void usage();

/***************************************************************************
 ** main
 **************************************************************************/
void main(int argc, char *argv[]) 
{
  int interations = INTERATIONS;
  int r, i, j;
  void *t = NULL;

  Matrix *Base, *Copy, *temp;

  /* startoff frill */
  if (argc == 2) {
    interations = atoi(argv[1]);
  } else {
    usage();
    return;
  }

  /* initialize Base Matrix */
  if ((Base = (Matrix *)malloc(sizeof(Matrix))) == NULL ) {
    fprintf(stderr, "_____memory shortage_________\n");
    exit;
  }
  srand( (int)time(t) );

  /* initialize walls to zero */
  for (i=LEFT; i < RIGHT; i++) {
    Die(i, TOP, *Base);
    Die(i, BOTTOM, *Base);
  }
  for (i=TOP; i < BOTTOM; i++) {
    Die(LEFT, i, *Base);
    Die(RIGHT, i, *Base);
  }

  /* initialize living-room to random shit */
  for (j=TOP+1; j < BOTTOM -1; j++) {
    for (i=LEFT +1; i < RIGHT-1; i++) {
      if ( (r = (random()*3)%3) ) {
       	Live(i, j, *Base);
      } else {
	Die(i, j, *Base);
      }
    }
  }

  /* initialize copy matrix */
  if ( (Copy = (Matrix *)malloc(sizeof(Matrix)) ) == NULL) {
    fprintf(stderr, "+++++++++++++++++++++memory shortage+++++++++++++\n");
    exit;
  }
  
  for (j = TOP; j < BOTTOM; j++) {
    for (i = LEFT; i < RIGHT-1; i++) {
      Die(j,i, *Copy);
    }
  }
  
  /***************************************
   * now it's time for the interation loop
   ***************************************/
     
  for (r=0; r<interations; r++) {
    
    /* display matrix */
    printf("\n     Interation %d :\n", r);
    Display_Matrix(*Base);

    /* interate matrix */
    Interate_Matrix(*Base, *Copy);
    /* swap matricies */
    temp = Base;
    Base = Copy;
    Copy = temp;
    
    sleep(SLEEPYTIME); 

  } /* end of for */
  printf("\n** Interation %d :\n", r);
  Display_Matrix(*Base);

  return;
}/* end of main */

/***************************************************************************
 **  Display_Matrix
 **************************************************************************/
void Display_Matrix(Matrix m)
{
  int i, j;
#ifdef DB
  printf("I'm in Display_Matrix\n");
  FF
#endif
  printf("\n");
  for(j=TOP+1; j<BOTTOM-1; j++) {
    for(i=LEFT+1; i<RIGHT-1; i++) {
      /* printf("%d", Cell(i, j, m) ); */
      if (Cell(i, j, m)) {
	printf("o");
      }else{
	printf(" ");
      } /* end if */
    } /* end for */
    printf("\n");
  } /* end for */
  
  return;
}/* end of Display_Matrix */

/***************************************************************************
 **  Interate_Matrix
 ***************************************************************************/
void Interate_Matrix(Matrix master, Matrix copy)
{
  int i, j, n;
#ifdef DB
  printf("I'm in Interate_Matrix\n");
  FF
#endif

  for(j=(TOP+1); j<(BOTTOM-1); j++) {
    
    for (i=(LEFT+1); i<(RIGHT-1); i++) {
      n = Neighbors(i, j, master);
      
      if ( (n < EXCESS) && (n > LONELY)) {
	/* ideal living conditions */
	if (LOVE==n) {
	  Live(i,j,copy);
	} else {
	  Live_on(i,j,master,copy);
	}
      } else {
	Die(i,j,copy);
      } /* ENDIF */
    } /* endfor */
  } /* endfor */
  
} /* end of Interate_Matrix */

/**************************************************************************
 **  Neighbors
 *************************************************************************/
int Neighbors(int i, int j, Matrix m)
{
  int n;

#ifdef DB
  printf("I'm in Neighbors\n");
  FF
#endif
  /* count the number of neighbors a cell has */
  /* I might want to do some error checking on bounds...*/
  
#if 0  
  n = *m[i-1][j-1] +
    *m[i][j-1] +
      *m[i+1][j-1] +
	*m[i-1][j] +
	  *m[i+1][j] +
	    *m[i-1][j+1] +
	      *m[i][j+1] +
		*m[i+1][j+1];
#else
  n = Cell(i-1, j-1, m) + Cell(i, j-1, m) + Cell(i+1, j-1, m) +
    Cell(i-1,j, m) + Cell(i+1, j, m) +
      Cell(i-1, j+1, m) + Cell(i, j+1, m) + Cell(i+1, j+1, m);
#endif

 return n;
}
/*************************************************************************
 ** Live_on
 *************************************************************************/
void Live_on(int i, int j, Matrix master, Matrix copy)
{
#ifdef DB
  printf("I'm in Live_on\n");
  FF
#endif
  copy[i][j] = master[i][j];
}

/*************************************************************************
 **  Live
 *************************************************************************/
void Live(int i, int j, Matrix m)
{
#ifdef DB
  printf("I'm in Live");
  FF
#endif
    FF
  m[i][j] = 1;
  return;
}

/**************************************************************************
 **  Die
 **************************************************************************/
void Die(int i, int j, Matrix m)
{
#ifdef DB
  printf("I'm in Die");
  FF
#endif
  m[i][j] = 0;
}

/**************************************************************************
 ** Cell
 **************************************************************************/
int Cell(int i, int j, Matrix m)
{
#ifdef DB
  printf("I'm in Cell");
  FF
#endif
/*   printf(" i=%d,j=%d ", i, j); */
  return m[i][j];
}

/***************************************************************************
 **  Usage
 **************************************************************************/
void usage()
{
  char message[]="Jed's Cellular AutoMart: 'otto [interations]', please.";
  fprintf(stderr, "%s\n", message);
  return;
}
/* eof */
