/* **********************************************************
 * Sample Serial Code : Conways' game of life
 *
 * Usage : life [-nx <x meshpoints>] [-ny <y meshpoints>] 
 *              [-p <prob>]  [-nt <timesteps>]
 *
 * - 'life' with no arguments uses default parameters.
 * - sample run with parameters : life -nx 30 -ny 30 -nt 200 -p 0.5
 * 
 *  Author : Urvashi R.V. [04/06/2004]
 *     Modified by Scott Baden [10/8/06]
 *     Modified by Pietro Cicotti [10/8/08]
 *     Modified by Scott Baden [10/13/06]
 * 
 *************************************************************/


#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <assert.h>

#define MATCH(s) (!strcmp(argv[ac], (s)))

int MeshPlot(int t, int m, int n, char **mesh);

double real_rand();
int seed_rand(long sd);

static char **gmesh=NULL, **pmesh=NULL, **tmesh=NULL;
static int maxiter = 200; /* number of iteration timesteps */
static int population[2] = {0,0}; /* numbero of live cells */

int nx = 16;      /* number of mesh points in the x dimension */
int ny = 16;      /* number of mesh points in the y dimension */

static int w_update = 0;
static int w_plot = 1;

extern FILE *gnu;

int main(int argc,char **argv)
{
    int i,j,ac;

    /* Set default input parameters */
    
    float prob = 0.5;   /* Probability of placing a cell */
    long seedVal = 0;
    int game = 0;
    
    /* Over-ride with command-line input parameters (if any) */
    
    for(ac=1;ac<argc;ac++)
    {
        if(MATCH("-nx")) {nx = atoi(argv[++ac]);}
        else if(MATCH("-ny")) {ny = atoi(argv[++ac]);}
        else if(MATCH("-nt")) {maxiter = atoi(argv[++ac]);}
        else if(MATCH("-p"))  {prob = atof(argv[++ac]);}
        else if(MATCH("-s"))  {seedVal = atof(argv[++ac]);}
        else if(MATCH("-g"))  {game = atoi(argv[++ac]);}
        else {
            printf("Usage: %s [-nx <x meshpoints>] [-ny <y meshpoints>]  [-nt <timesteps>] [-p prob]\n",argv[0]);
            return(-1);
        }
    }

    int rs = seed_rand(seedVal);
    /* Increment sizes to account for boundary ghost cells */
    
    nx = nx+2;
    ny = ny+2;
    
    /* Allocate contiguous memory for two 2D arrays of size nx*ny.
     * Two arrays are required because in-place updates are not
     * possible with the simple iterative scheme listed below */
    
    gmesh = (char**)malloc(sizeof(char*)*nx + sizeof(char)*nx*ny);
    for(i=0;i<nx;i++) gmesh[i] = (char*)(gmesh+nx) + i*ny;
    
    pmesh = (char**)malloc(sizeof(char*)*nx + sizeof(char)*nx*ny);
    for(i=0;i<nx;i++) pmesh[i] = (char*)(pmesh+nx) + i*ny;
    
    /* Set the boundary ghost cells to hold 'zero' */
    for(i=0;i<nx;i++)
    {
        gmesh[i][0]=0;
        gmesh[i][ny-1]=0;
        pmesh[i][0]=0;
        pmesh[i][ny-1]=0;
    }
    for(i=0;i<ny;i++)
    {
        gmesh[0][i]=0;
        gmesh[nx-1][i]=0;
        pmesh[0][i]=0;
        pmesh[nx-1][i]=0;
    }

    // Generate a world
    
    if (game == 0){ // Use Random input
        for(i=1;i<nx-1;i++)
            for(j=1;j<ny-1;j++) {
                gmesh[i][j] = (real_rand() < prob);
                population[w_plot] += gmesh[i][j];
            }
    }
    else if (game == 1){ //  Block, still life
        printf("2x2 Block, still life\n");
        int nx2 = nx/2;
        int ny2 = ny/2;
        gmesh[nx2+1][ny2+1] = gmesh[nx2][ny2+1] = gmesh[nx2+1][ny2] = gmesh[nx2][ny2] = 1;
        population[w_plot] = 4;
    }
    else if (game == 2){ //  Glider (spaceship)
        printf("Glider (spaceship)\n");
        // Your code codes here
    }
    else{
        printf("Unknown game %d\n",game);
        exit(-1);
    }

   
    
    printf("probability: %f\n",prob);
    printf("Random # generator seed: %ld\n", rs);

    /* Plot the initial data */
    
    /* Perform updates for maxiter iterations */
    int t=0;
    for(t=0;t<maxiter && population[w_plot];t++)
    {
        /* Use gmesh to compute the updates and store it in pmesh */
        population[w_update] = 0;
        for(i=1;i<nx-1;i++)
            for(j=1;j<ny-1;j++) {
                int nn = gmesh[i+1][j]+gmesh[i-1][j]+gmesh[i][j+1]+gmesh[i][j-1] + gmesh[i+1][j+1]+gmesh[i-1][j-1]+gmesh[i-1][j+1]+gmesh[i+1][j-1];
                pmesh[i][j] = gmesh[i][j] ? (nn == 2 || nn == 3) : (nn == 3);
                population[w_update] += pmesh[i][j];
            }

        /* Wait for previous plot to end */
            
        /* Pointer Swap : pmesh <-> gmesh */
        tmesh = pmesh;
        pmesh = gmesh;
        gmesh = tmesh;

        /* Update the ghost cells */

        /* Start the new plot */
        MeshPlot(t,nx,ny,gmesh);
    printf("Press enter to continue.\n");
    getchar();

    }
    printf("Press enter to end.\n");
    getchar();
    pclose(gnu);

    /* Wait for plot of final data */


    /* Free resources */
    free(pmesh);
    free(gmesh);

    return(0);
}
