/* ******************************** */
/* WOLF.C                           */
/* A Wolf Population Simulation     */
/* rps   Microsoft C version        */
/* (c) Copyright 1987,'95 R P Sarna */
/* Maine Maritime Academy           */
/* Castine, Maine 04420             */
/* All Rights Reserved              */
/* May be copied for non-commercial */
/* use.                             */
/* Routines may also be used for    */
/* non-commercial uses.             */
/* Please tell me if you find it    */
/* useful!                          */
/* ******************************** */

/* *************************************************************** */
/* Note this kind of simulation actually creates "individuals".    */
/* you can actually track the life of each individual, if you wish */
/*                                                                 */
/* The routines were originally used to force optimum scheduling   */
/* for logging operations analysis.  A looooong time ago!          */
/*                                                                 */
/* Somebody should put better wolf data in it.                     */
/*                                                                 */
/* Note that you can modify it to either accept a starting number  */
/* from the user, or get one depending on the system clock.        */
/*                                                                 */
/* To contact me:                                                  */
/* sarna@saturn.caps.maine.edu                                     */
/* *************************************************************** */

#include <stdio.h>
#include <stdlib.h>
#ifdef MSC
#include <process.h>
#endif
#include <time.h>

char id[] = "$Header: c:/programs/rcs/wolf.c 1.5 95/06/27 08:42:31 Red Exp $";

char copyrite[] = "Copyright (c) 1995  R. P. Sarna  All Rights Reserved.";
char copyleft[] = "Permission granted for non-profit copying and Distribution.";

/* event definitions: */

#define STATS 0
#define BIRTH 1
#define DEATH 2
#define ENDSM 10

/* define sex number: */

#define MALE 1
#define FEMALE 0

struct link {           /* structure definition for link in queue */
        int time;
        char priority;
        char event;
        int wolfnum;
        int sex;
        struct link *lastptr;
        struct link *nextptr;
};

struct link *beginlink;
struct link *endlink;

struct vect {           /* vector type (for each event) */
        int vtime;
        char vprior;
        char vevent;
        int vwolfnum;
        int vsex;
};

struct vect *vector;

/* function declarations */

void init(void);        /* initialize simulation */
void add2q(void);       /* add event to queue */
void mallerr(void);     /* exit if memory allocation error */
void birth(void);       /* birth of wolf event, set up future births */
void death(void);       /* death of wolf event */
void stats(void);       /* event to print out statistics */
void endsim(void);       /* event to end simulation */
void getone(void);      /* get next event from queue */
void typeout(void);     /* print information at beginning */

void *malloc(size_t size);              /* standard C memory allocation */
void free(void *memblock);              /* standard C freeing of allocated memory */
int rand(void);                                 /* standard C random number function */
void srand(unsigned int seed);  /* standard C seed random number */

int timenow;            /* present simulated time */
int population;         /* present population */
int lastwolf;           /* wolf serial numbers */
int males;              /* present number of males */
int females;            /* present number of females */
int sfactor;            /* starvation factor if population too high */

                                        /* to put copyright into object code */
char copyrt1[]= "(c) Copyright 1987,1995 R P Sarna";
char copyrt2[]= "39 Cushnoc Drive";
char copyrt3[]= "Augusta, ME 04330";
char copyrt4[]= "All Rights Reserved";
char copyrt5[]= "May be copied for non-commercial use";
char copyrt6[]= "if copied intact";

long clock();

void main(void)
{
        init();

        while (1) {
                getone();
                timenow = vector->vtime;
                if (vector->vevent == STATS) {
                        stats();
                        continue;
                }
                if (vector->vevent == BIRTH) {
                        birth();
                        continue;
                }
                if (vector->vevent == DEATH) {
                        death();
                        continue;
                }
                if (vector->vevent == ENDSM) endsim();
        }

}


void init(void)
{
        int garbchar;
        unsigned seed;
        char throwaway[80];

        timenow = 0;
        population = 2;
        lastwolf = 2;
        males = 1;
        females = 1;

        if ((beginlink = (struct link *)malloc(sizeof(*beginlink))) == NULL)
                mallerr()
        ;
        if ((endlink = (struct link *)malloc(sizeof(*beginlink))) == NULL)
                mallerr()
        ;
        if ((vector = (struct vect *)malloc(sizeof(*vector))) == NULL)
                mallerr()
        ;

        endlink->nextptr = NULL;
        endlink->lastptr = beginlink;
        beginlink->nextptr = endlink;
        beginlink->lastptr = NULL;

        beginlink->time = -32768;
        beginlink->priority = 0;
        endlink->time = 32767;
        endlink->priority = 255;

/* Put in first birth: */

        vector->vtime = 1;
        vector->vprior = 10;
        vector->vevent = BIRTH;
        vector->vwolfnum = 0;   /* numbered at birth */
        vector->vsex = FEMALE;
        add2q();

/* Put in death of wolf #1: */

        vector->vtime = 5;
        vector->vprior = 5;
        vector->vevent = DEATH;
        vector->vwolfnum = 1;   /* numbered at birth */
        vector->vsex = MALE;
        add2q();

/* Put in death of wolf #2: */

        vector->vtime = 5;
        vector->vprior = 5;
        vector->vevent = DEATH;
        vector->vwolfnum = 2;   /* numbered at birth */
        vector->vsex = FEMALE;
        add2q();

/* Put in End-Of-Simulation event: */

        vector->vtime = 25;
        vector->vprior = 0;
        vector->vevent = ENDSM;
        vector->vwolfnum = 0;
        vector->vsex = 0;
        add2q();

/* Put in first printout of statistics: */

        vector->vtime = 10;
        vector->vprior = 100;
        vector->vevent = STATS;
        vector->vwolfnum = 0;
        vector->vsex = 0;
        add2q();

/* Tell about this simulation: */

        typeout();

/* Set up random number generator and begin: */

        seed = (unsigned)(clock()) & 0x0000FFFF;

        fprintf(stderr, "\nPress <return> to begin:");
        gets(throwaway);

        seed = (unsigned)(clock() & 0x0000FFFF);
        srand(seed);

}


void mallerr(void)
{
/* Exception Handler For Memory Allocation: */

        fprintf(stderr, "\nERROR: Memory allocation failure\n");
        exit(1);
}


void add2q(void)  /* Version with priorities */
{
        struct link *biglink;
        struct link *nextlink;
        struct link *newlink;

        if ((newlink = (struct link *)malloc(sizeof(*beginlink))) == NULL)
                mallerr()
        ;

        biglink = endlink;
        nextlink = (*biglink).lastptr;

        while (1) {
/* T != */      if ((vector->vtime < biglink->time) &&
                   (vector->vtime > nextlink->time)) {
                        biglink->lastptr = newlink;
                        newlink->nextptr = biglink;
                        newlink->lastptr = nextlink;
                        nextlink->nextptr = newlink;
                        newlink->time = vector->vtime;
                        newlink->priority = vector->vprior;
                        newlink->event = vector->vevent;
                        newlink->wolfnum = vector->vwolfnum;
                        newlink->sex = vector->vsex;
                        break;
                }
/* = T */       if ((vector->vtime == nextlink->time) &&
/* < P */          (vector->vprior >= nextlink->priority)) {
                        biglink->lastptr = newlink;
                        newlink->nextptr = biglink;
                        newlink->lastptr = nextlink;
                        nextlink->nextptr = newlink;
                        newlink->time = vector->vtime;
                        newlink->priority = vector->vprior;
                        newlink->event = vector->vevent;
                        newlink->wolfnum = vector->vwolfnum;
                        newlink->sex = vector->vsex;
                        break;
                }
/* = T = */     if ((vector->vtime == biglink->time) &&
/* <= P <= */      (vector->vtime == nextlink->time) &&
                   (vector->vprior >= nextlink->priority) &&
                   (vector->vprior <= biglink->priority)) {
                        biglink->lastptr = newlink;
                        newlink->nextptr = biglink;
                        newlink->lastptr = nextlink;
                        nextlink->nextptr = newlink;
                        newlink->time = vector->vtime;
                        newlink->priority = vector->vprior;
                        newlink->event = vector->vevent;
                        newlink->wolfnum = vector->vwolfnum;
                        newlink->sex = vector->vsex;
                        break;
                }
/* T = */       if ((vector->vtime == biglink->time) &&
/* P <= */         (vector->vtime != nextlink->time) &&
                   (vector->vprior <= biglink->priority)) {
                        biglink->lastptr = newlink;
                        newlink->nextptr = biglink;
                        newlink->lastptr = nextlink;
                        nextlink->nextptr = newlink;
                        newlink->time = vector->vtime;
                        newlink->priority = vector->vprior;
                        newlink->event = vector->vevent;
                        newlink->wolfnum = vector->vwolfnum;
                        newlink->sex = vector->vsex;
                        break;
                }
                else {
                        biglink = nextlink;
                        nextlink = biglink->lastptr;
                }
        }
}


void getone(void)
{
/* Get next event and put it into vector: */

        struct link *smalllink;
        struct link *nextlink;
        struct link *dellink;

        smalllink = beginlink;

        nextlink = smalllink->nextptr;

        if (nextlink->time == 32767) {
           fprintf(stderr,"\nERROR: Attempt to get event from empty queue\n");
           exit(1);
        }

        dellink = nextlink;
        nextlink = dellink->nextptr;
        smalllink->nextptr = nextlink;
        nextlink->lastptr = smalllink;

        vector->vtime = dellink->time;
        vector->vprior = dellink->priority;
        vector->vevent = dellink->event;
        vector->vwolfnum = dellink->wolfnum;
        vector->vsex = dellink->sex;

        free(dellink);

        return;
}

void birth(void)
{
        int breedage;
        int lifespan;
        int i,j;
        int sex;

        sex = vector->vsex;

/* Are there any adults left? */

        if (population < 1) return;

/* Are there any males left? */

        if (males < 1) {
            printf("\nSorry, no males left, so no births, though scheduled.");
                return;
        }

/* Update population: */

        population++;
        lastwolf++;
        printf("\nCongratulations on the birth of new ");
        if (sex == MALE) {
                printf("male ");
                males++;
        }
        if (sex == FEMALE) {
                printf("female ");
                females++;
        }
        printf("puppy #%d", lastwolf);

/* Determine breeding age: */

        breedage = (rand() % 2);        /* 0 or 1 */
        breedage = breedage + 1;        /* 1 - 2 years, total */

/* Determine lifespan: */

        lifespan = (rand() % 9);        /* 0 - 8 */

/* Create death event for parent: */

        vector->vtime = timenow + lifespan;   /* 0 - 5 years */
        vector->vprior = 5;
        vector->vevent = DEATH;
        vector->vwolfnum = lastwolf;
        vector->vsex = sex;
        add2q();
        if (lifespan == 0) return;

/* If male, that's it: */

        if (sex == MALE) return;

/* As pack grows, so does starvation factor: */

        if (population >= 20) sfactor = 4; /* high population */
        if (population < 20)  sfactor = 2; /* pack too big */
        if (population < 15)  sfactor = 0; /* pack size ok */

/* If still alive and female, births may occur, create them: */

   for (j = breedage; j <= lifespan; j++) {
/* 0 - 6 offspring */
        for (i = 0; i < ((rand() % 7) - sfactor); i++) {
                vector->vtime = timenow + breedage + j;
                vector->vprior = 10;
                vector->vevent = BIRTH;
                vector->vwolfnum = 0;          /* numbered at birth */
                vector->vsex = (rand() % 2);            /* 0 or 1 */
                add2q();
        }
   }

}


void death(void)
{
/* Change population: */

        population--;
        printf("\nSincere sympathy on the death of ");
        if (vector->vsex == MALE) {
                printf("male ");
                males--;
        }
        if (vector->vsex == FEMALE) {
                printf("female ");
                females--;
        }
        printf("wolf #%d", vector->vwolfnum);

}


void stats(void)
{
/* Print out statistics: */

        printf("\n===================");
        printf("\nSTATISTICS:");
        printf("\n-------------------");
        printf("\n       Year: %d", timenow);
        printf("\n Population: %d", population);
        printf("\n      males: %d", males);
        printf("\n    females: %d", females);
        printf("\n# of wolves: %d", lastwolf);
        printf("\n===================");

/* Put in next printout of statistics: */

        vector->vtime = timenow + 10;
        vector->vprior = 100;
        vector->vevent = STATS;
        vector->vwolfnum = 0;
        vector->vsex = 0;
        add2q();

}


void endsim(void)
{
/* End simulation: */
        printf("\n===================");
        printf("\n===================");
        printf("\nEND OF SIMULATION: ");
        printf("\n===================");
        stats();
        printf("\n===================\n");
        exit(0);
}


void typeout(void)
{
   fprintf(stderr, "\n            WOLF POPULATION SIMULATION");
   fprintf(stderr, "\n\nThis is a simulation of a wolf population.  It is");
   fprintf(stderr, "\nstochastic; that is, individual wolves are born or die");
   fprintf(stderr, "\ndepending on the result of a random number generator.");
   fprintf(stderr, "\nThe random (actually pseudo-random) number generator");
   fprintf(stderr, "\nuses a 'seed' at the start; this comes from the computer's");
   fprintf(stderr, "\nclock.  Therefore, each time you run the program, you");
   fprintf(stderr, "\ncan get different answers.  This is as it should be:");
   fprintf(stderr, "\nsometimes a population prospers, sometimes it dies out.");
   fprintf(stderr, "\nIn general, life is rough: it is very hard, both in this");
   fprintf(stderr, "\nsimulation and in the real world, to get a stable");
   fprintf(stderr, "\npopulation going!");

   fprintf(stderr, "\n\nThis simulation is in its very early stages.  Currently,");
   fprintf(stderr, "\nit assumes that the wolves live from zero to eight years. ");
   fprintf(stderr, "\nFrom one or two years until the end of their lives, they");
   fprintf(stderr, "\nmay have from zero to six pups per year.  As the pack ");
   fprintf(stderr, "\nsize grows, litter size will become smaller.");

   fprintf(stderr, "\n\nEventually, the simulation dreamed of will have wolves and");
   fprintf(stderr, "\nprey, all interacting in the same fashion.  Until then,");
   fprintf(stderr, "\ntry this!  (Redirect output to file to trace lives.)\n");

}
