allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (07/19/89)
Posting-number: Volume 7, Issue 80 Submitted-by: loy@gtx.UUCP (Bob Loy) Archive-name: whpl/part07 # whpl07of13.shar #---cut here---cut here---cut here---cut here---cut here--- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files. # This archive created: Sat Jan 14 04:04:43 MST 1989 export PATH; PATH=/bin:$PATH echo shar: extracting "'whx.c2'" '(29028 characters)' if test -f 'whx.c2' then echo shar: will not over-write existing file "'whx.c2'" else sed 's/^X//' << \SHAR_EOF > 'whx.c2' X X/*---------------------------------------------------------------------------* X@^ X@@^ void interim() - Handles interim file output during long runs. Likely to X@@^ be called under the -y cmnd line opt, or if NUMWH is high. X@ output: global chappend[0], filename append character, is incremented X@ global chapend[0], filename append character, may be incremented X@ caller: main() X@ calls : lastuff(), fileout(), countwhales(); malloc(), free(), X@ may call finish() X@^ proc : Outputs interim whale & stat files, and then reallocates the X@^ whale structures of the still living whales X@ X@^ Note : The internal numbering of the whales also gets changed as they X@^ are reallocated into a smaller space. X@ X@*---------------------------------------------------------------------------*/ X Xvoid Xinterim() X{ X register int j, k = 0; X whale_type *newhales; X X lastuff(1); X fileout(1); X if (debug >= 5) X fprintf(stderr, "\n CONTINUING -- FILES OUTPUT\n"); X if (debug >= 6) X fprintf(stdout, "\n CONTINUING -- FILES OUTPUT\n"); X /* Now create the next interim filename append of two extra chars X from "aa" all the way to "zz", if necessary */ X chappend[0]++; X if (chappend[0] == '{') /* Oops, stepped past the ascii 'z' } */ X { X chappend[0] = 'a'; X chapend[0]++; X if (chapend[0] == '{') /* Oops, stepped past the ascii 'z' } */ X { X finish(1); X } X } X countwhales(); X if(truwh != malwh + femwh) X { X if (debug >= 2) X fprintf(stderr, "interim(): truwh != malwh + femwh; %4d != %4d\n", X truwh, malwh + femwh); X truwh = malwh + femwh; X } X /* Create room for live whales only */ X newhales = (whale_type *) malloc(truwh * whale_size); X if (newhales == NULL) X { X if (debug >= 2) X fprintf(stderr, "\ninterim(): whale malloc problems.\n"); X finish(7); X } X /* Do any resets and assign only live whales to a new array */ X for (j = 0; j < numwh; j++) X { X if (whale[j].energy > 9999) X { X /* Now that the files have been output, we want to clear the X most recent internal arrays that were used for printing */ X whale[j].endex--; /* 'cleared' just by dropping the index */ X /* endex should also track the array of success structures: */ X whale[j].comp[whale[j].endex].diff = 0; X whale[j].comp[whale[j].endex].totl = 0; X whale[j].comp[whale[j].endex].rank = 0; X if (k >= truwh) X { X if (debug >= 2) X fprintf(stderr, X "\ninterim(): truwh >= new whale array size.\n"); X free((char*) newhales); X finish(6); X } X newhales[k] = whale[j]; X k++; X } X } X /* Close and reassign pointer to whale array */ X free((char*) whale); X whale = newhales; X numwh = truwh; X if (debug >= 5) X fprintf(stderr, "\n numwh being reset to: %d.\n\n", numwh); X if (debug >= 6) X fprintf(stdout, "\n numwh being reset to: %d.\n\n", numwh); X} X X/*---------------------------------------------------------------------------* X@ X@@ int plankcall() - Calling function for ongoing plankton regeneration. X@ input : global variable regrow X@ output: plankton may be regrown in locarr[] if population is below the X@ lower floor limit X@ caller: movewhale() X@ calls : plankgrow(), countplank(), printscreen() X@ X@*---------------------------------------------------------------------------*/ X Xint Xplankcall() X{ X int plank; X X plank = countplank(); X if (plank < regrow) X { X printscreen(); X if (debug >= 7) X fprintf(stdout, " plank = %d\n", plank); X plankgrow(2); X plankgrow(1); X /* one possible use of stopgrow: ---- X while (plank < stopgrow) X { X plankgrow(2); X plankgrow(1); X plank = countplank(); X } --------------------------------------*/ X plank = countplank(); X if (debug >= 7) X fprintf(stdout, " plank = %d\n", plank); X printscreen(); X return(1); X } X return(0); X} X X/*---------------------------------------------------------------------------* X@ X@@ void movewhale(one) - Moves whales based on individual genes fired. See X@@ also comments in genes.c: at top of file, and in genesets() X@ input : Whole whale list, mvwhle[] & locarr[] arrays X@ output: .energy field changes & location changes for individual whales X@ Plankton removed from locarr[] X@ caller: look(), main() X@ calls : nextrand(), genesets(), boundstest(), plankcall(); X@ malloc(), may call finish(); may call exit() X@ proc : First, an overview of the loops in this function: X@ (1) For the number of move turns this month X@ (2) For each (live) whale X@ (3) While this whale still has room to store moves X@ If whale is in hunt or feed mode? X@ Hunt mode: X@ (4) For each gene in a (randomly picked) chromosome X@ (5) For all the moves that gene stores in mvwhle[], X@ transfer them to proper place in moves[], X@ and update the whale's location in locarr[]. X@ Feed mode: X@ (4)(5), Same basic For-loops X@ Then, a look at what can cause breaks from the loops: X@ (5) Constant BRKGENE = 1 will force break in middle X@ of gene as soon as whale[wich].huntfeed X@ changes state, otherwise gene 'finishes' X@ Chngemode is incremented upon .huntfeed change X@ (4) Variable chngemode > 0 will force break in middle X@ of chromosome loop X@ While-loop test is also specifically tested at X@ this level as well; break is propagated thru X@ level (3) by variable "endturn" X@ (3) While-loop test is to make sure each whale's section X@ of the moves[] array isn't overwritten when X@ constant NORMAL = 1 X@ If constant NORMAL = 0, only one chromosome per X@ whale per move will fire (otherwise all whale X@ moves, regardless of genetypes of whales, will X@ 'normalize' to the maximum .hgperchr or .fgperchr X@ of all the whales in the run), so loop is broken X@ (2) End of loop (3) propagates through this level X@ (1) Counts through constant MVGRP for number of whale turns this X@ 'month' (Do-loop with "months" switch statement in main() X@ can be considered loop level (0)). X@ X@ Note : All whales get a chance to hunt/feed, then plankton are erased X@ X@*---------------------------------------------------------------------------*/ X Xvoid Xmovewhale() X{ X register int h, j, test; X register int wich; X int e, k, n; X int *moves; X int movesdex; X short chromo; X short totmvs; X short maxtotmv; X short chngemode; X short endturn; X int f = 0; X int mvgroup = MVGRP; X X /* Size the maximum number of location changes */ X maxtotmv = MAX(hgpcflg * MAXGMV, fgpcflg * MAXGMV); X /* Allocate space for storage of location changes */ X moves = (int*) malloc(numwh * maxtotmv * MAXGMV * (sizeof(int))); X if (moves == NULL) X { X if (debug >= 2) X fprintf(stderr, "\nMoves malloc problems.\n"); X finish(8); X } X /* Initialize array */ X for (j = 0; j < numwh * maxtotmv * MAXGMV; j++) X moves[j] = -1; X /* Start moving */ X for (k = 0; k < mvgroup; k++) X { X /* For each whale */ X for (wich = 0; wich < numwh; wich++) X { X totmvs = 0; X chngemode = 0; X endturn = 0; X /* Find this whale's section of moves[] */ X movesdex = wich * maxtotmv * MAXGMV; X /* If whale is alive */ X if (whale[wich].energy > 9999) X { X /* While whale's moves are less than there is space for */ X while (totmvs < maxtotmv) X { X /* Is it hunting or feeding? */ X if (whale[wich].huntfeed == 'H') X { X /* Pick a chromosome to fire */ X switch(whale[wich].hgperchr - '0') X { X case 0: X chromo = 0; X randflg = TRUE; X whale[wich].hgperchr += (Uchar) hgpcflg; X break; X case 1: X chromo = nextrand() & 0xF; X break; X case 2: X chromo = nextrand() & 0xE; X break; X case 4: X chromo = nextrand() & 0xC; X break; X case 8: X chromo = nextrand() & 0x8; X break; X case 16: X chromo = 0; X break; X default: X if (debug >= 2) X { X fprintf(stderr, X "whale[%d].hgperchr = %d,\n", X wich, whale[wich].hgperchr - '0'); X fprintf(stderr, " must divide into 16\n"); X } X exit(22); X } X /* For each gene in the chromosome */ X for (j = 0; j < whale[wich].hgperchr - '0'; j++) X { X whale[wich].huntdex = chromo + j; X genesets(wich); X if (totmvs + mvwhle[0] > maxtotmv) X { X endturn++; X break; X } X test = whale[wich].locatn; X /* For each move mapped by the gene */ X for (h = 1; h <= mvwhle[0]; h++) X { X /* Hopefully, this test saves some time */ X if ((test <= MAXGMV * vbias) || X (test >= area - MAXGMV * vbias)) X { X n = mvwhle[h]; X n = boundstest(n); X mvwhle[h] = n; X } X /* Assign moves and increment move count */ X moves[movesdex + (totmvs)] = mvwhle[h]; X whale[wich].locatn = mvwhle[h]; X totmvs++; X /* Found plankton?... */ X if (locarr[whale[wich].locatn] == '.') X { X whale[wich].energy += PLUS; X whale[wich].lastfed = 0; X chngemode++; X if (BRKGENE) X break; X } X else /* ...or not */ X { X whale[wich].energy -= MINUS; X whale[wich].lastfed++; X } X } X if (chngemode) /* Change from hunt to feed */ X { X if (whale[wich].lastfed < COUNTVAL) X whale[wich].huntfeed = 'F'; X chngemode = 0; X break; X } X } X if (randflg) /* Do resets */ X { X whale[wich].hgperchr = '0'; X randflg = FALSE; X } X if (!NORMAL) X break; X if (endturn) X break; X } X else if (whale[wich].huntfeed == 'F') X { X /* Pick a chromosome to fire */ X switch(whale[wich].fgperchr - '0') X { X case 0: X chromo = 0; X randflg = TRUE; X whale[wich].fgperchr += (Uchar) fgpcflg; X break; X case 1: X chromo = nextrand() & 0xF; X break; X case 2: X chromo = nextrand() & 0xE; X break; X case 4: X chromo = nextrand() & 0xC; X break; X case 8: X chromo = nextrand() & 0x8; X break; X case 16: X chromo = 0; X break; X default: X if (debug >= 2) X { X fprintf(stderr, X "whale[%d].fgperchr = %d,\n", X wich, whale[wich].fgperchr - '0'); X fprintf(stderr, " must divide into 16\n"); X } X exit(22); X } X /* For each gene in the chromosome */ X for (j = 0; j < whale[wich].fgperchr - '0'; j++) X { X whale[wich].feeddex = chromo + j; X genesets(wich); X if (totmvs + mvwhle[0] > maxtotmv) X { X endturn++; X break; X } X test = whale[wich].locatn; X /* For each move mapped by the gene */ X for (h = 1; h <= mvwhle[0]; h++) X { X /* Hopefully, this test saves some time */ X if ((test <= MAXGMV * vbias) || X (test >= area - MAXGMV * vbias)) X { X n = mvwhle[h]; X n = boundstest(n); X mvwhle[h] = n; X } X /* Assign moves and increment move count */ X moves[movesdex + (totmvs)] = mvwhle[h]; X whale[wich].locatn = mvwhle[h]; X totmvs++; X /* Found plankton?... */ X if (locarr[whale[wich].locatn] == '.') X { X whale[wich].energy += PLUS; X whale[wich].lastfed = 0; X } X else /* ...or not */ X { X whale[wich].energy -= MINUS; X whale[wich].lastfed++; X if (whale[wich].lastfed >= COUNTVAL) X { X chngemode++; X if (BRKGENE) X break; X } X } X } X if (chngemode) /* Change from feed to hunt */ X { X if (whale[wich].lastfed >= COUNTVAL) X whale[wich].huntfeed = 'H'; X chngemode = 0; X break; X } X } X if (randflg) /* Do resets */ X { X whale[wich].fgperchr = '0'; X randflg = FALSE; X } X if (!NORMAL) X break; X if (endturn) X break; X } X else X { X if (debug >= 2) X fprintf(stderr, X "movewhale(): whale[].huntfeed != H or F\n"); X exit(22); X } X } X } X } X /* Find all the moves (locations) in moves[] and remove plankton */ X /* in locarr[] at those locations */ X for (j = 0; j < numwh * maxtotmv * MAXGMV; j++) X { X if (moves[j] >= 0) X locarr[moves[j]] = ' '; X } X /* The following three if()'s playing with variables e & f are to */ X /* get around the times the % operator yields a result of 0 */ X /* twice or more in a row due to rounding */ X if ((k + 1) % (mvgroup / truwh) == 0) X { X e = k + 10; X f++; X } X if ((f == 1) && (k > 0)) X { X if (debug >= 7) X fprintf(stdout, " Move %5d\n", k); X if (debug >= 9) X { X fprintf(stdout, " hunt moves = %ld\n", aiches); X fprintf(stdout, " feed moves = %ld\n", effs); X } X if (debug >= 9) X for (j = 0; j < numwh; j++) X fprintf(stdout, "Whale %3d has %8d energy.\n", X j, whale[j].energy); X /* Test for low plankton population & regrow, if necessary */ X j = plankcall(); X if (j) /* Re-initialize array of location changes */ X { X for (j = 0; j < numwh * maxtotmv * MAXGMV; j++) X moves[j] = -1; X } X f++; X } X if ((k == e) || ((k + 1) == mvgroup)) X f = 0; X } X if (debug >= 7) X fprintf(stdout, " Move %5d\n", k); X if (debug >= 9) X for (wich = 0; wich < numwh; wich++) X fprintf(stdout, " Whale %3d has %8d energy.\n", X wich, whale[wich].energy); X free((char *) moves); X} X X/*---------------------------------------------------------------------------* X@ X@@ void main(argc, argv) - Calling function for whpl.c and associated files. X@ input : Constants from whpl.h and command line arguments. X@ output: Most output comes from other functions called directly or indir- X@ ectly from here, including finish(), which handles most of the X@ program's file output. X@ calls : ophandle(), randinit(), whaleinit(), finish(), countwhales(), X@ clearlocarr(), plankplace(), countplank(), printscreen(), X@ plankgrow(), movewhale(), whaleplace(), whaledie(), interim(), X@ look(), mate() X@ proc : There are three basic sections to this function: X@ First, the whales are initialized, either randomly, or by a read X@ from a whale file (call to whaleinit). Command line opts X@ heavily condition how these two sources of whales are combined. X@ Second, other initializations take place, including the plankton, X@ which are then grown into their normal population range. X@ Finally comes the main program loops which control the timing of X@ the ecology's overall events; hunting, eating, mating, dying. X@ X@ Note : The variables "months" and "year" do not have the chronological X@ meaning normally associated with them on Earth. Months is X@ the loop variable and switch value used in the main control X@ do-loop, while year is normally incremented when mate() is X@ called, and used in computations involving the "age" of speci- X@ fic whales. "cycle", incremented once each time through the X@ main control do-loop, cooresponds better to our earthly notion X@ of a year. The "MONTHS" constant in whpl.h sets the number of X@ months per cycle. X@ In the version 1.10 release of this function, one cycle equals X@ 5 years. This can have an unexpected effect on the -y option, X@ e.g., using -y6 on the command line will actually create 10 X@ generations of whales, rather than 6, due to this granularity. X@ If you modify the do-loop to call mate() only once, then one X@ cycle will equal one year. X@ X@ Note : Variable "dielim" is changed dynamically in the present (whpl.c X@ v1.10) release version of this function. This variable has X@ the most effect of any as far as keeping the whale population X@ steady. Setting it to 2 for two mate cycles and to 1 for X@ three seems to do reasonably well. When, (in relation to X@ mate()), and how often, whaledie() is called also has an X@ effect on whether whales generaly increase or decrease. X@ X@*---------------------------------------------------------------------------*/ X Xvoid Xmain(argc, argv) X int argc; X char *argv[]; X{ X static int months; X int j = FNMTRUNC - 1; X char datr[11]; X char temp[11]; X Uint dater; X int plank; X short pre = 0; X short post = 0; X short cycle = 0; X X /* Do some simple tests on constants ? */ X X /* Get command line args */ X ophandle(argc, argv); X /* Initialize random number generators */ X randinit(); X /* Other initializations */ X regrow = area / 6; X stopgrow = area / 3; X /* Will we be looking at whale tracks? (Use of -t option restricts X locarr[] array size to 288 * 225 pixels) */ X if(trakflg) X { X area = 64800; X vbias = 225; X } X /* Initialize location array and scratch array */ X locarr = (Uchar*) malloc(area); X if (locarr == NULL) X { X if (debug >= 2) X fprintf(stderr, "\nlocarr malloc problems.\n\n"); X exit(8); X } X secarr = (Uchar*) malloc(area); X if (secarr == NULL) X { X if (debug >= 2) X fprintf(stderr, "\nsecarr malloc problems.\n\n"); X exit(8); X } X /* Are we just browsing... */ X if(trakflg) X { X look(); X exit(0); X } X /* ...or running the program? */ X if (debug >= 5) X fprintf(stdout, "\n\n RUN %u\n\n", daterun); X /* Create archive file name */ X if (!wharcflg) X { X dater = daterun / 10000; X dater *= 100; X sprintf(temp, "%8u", dater); X do{ X j++; X datr[j - FNMTRUNC] = temp[j]; X } while (temp[j] != '\0'); X strcat(wharcfile, "wha"); X strcat(wharcfile, datr); X } X /* Initialize whales */ X whaleinit(); X countwhales(); X /* We've initialized the whales, now let's init the plankton: */ X clearlocarr(); X plankplace(1, 0); X plank = countplank(); X if (debug >= 5) X fprintf(stdout, " Seeded plankton = %7d\n", plank); X printscreen(); X for (j = 0; j < 4; j++) X plankgrow(1); X plank = countplank(); X if (debug >= 7) X fprintf(stdout, " Interim plankton = %7d\n", plank); X printscreen(); X plankgrow(2); X plankgrow(1); X plank = countplank(); X if (debug >= 5) X fprintf(stdout, " Final initial plankton = %7d\n\n", plank); X printscreen(); X /* One finial initialization step; tune Wa-Tor to this set of whales: */ X pre = 6; /* <-- Remove this line to bypass the "pre" loop altogether */ X if (pre) X { X if (debug >= 5) X fprintf(stdout, "Conditioning world for %d months\n", pre); X for (months = 1; months <= pre; months++) X { X movewhale(); X if (debug >= 5) X fprintf(stdout, " %2d\n", months); X } X for (j = 0; j < numwh; j++) X { X whale[j].locatn = whaleplace(); X whale[j].energy = 1000000; X whale[j].lastfed = 1000000; X } X } X /* Now to get into the run for real: */ X dielim = 1; /* Set here just to make sure it's set to a reasonable value */ X do{ X cycle++; /* Number of times through the do-loop */ X /* Count up through the 'months' from 1, THRU the value of MONTHS */ X for (months = 1; months <= MONTHS; months++) X { X if (debug >= 7) X fprintf(stdout, "\nCycle %d, Month %d\n", cycle, months); X if (debug >= 7) X fprintf(stdout, " Year %d\n", year); X switch(months) /* So what do we do with each new 'month'? */ X { X case 1: X dielim = 2; /* <-- Whale population tends to increase */ X movewhale(); X break; X case 13: X dielim = 1; /* <-- Whale population tends to decrease */ X movewhale(); X break; X case 6: X case 12: X case 18: X case 24: X case 30: X /* Be somewhat careful about changing the order of these X statements. Nothing is likely to break, but output X based on year value may not be so meaningful: check X the functions themselves. Also, it's safest to X call interim() before mate() to help keep within X the maximum allowable number of whales */ X year++; X movewhale(); X whaledie(1); X /* Save whales to file & reallocate live ones */ X if (numwh > interlim) /* default limit about 3/5 of MAXWH */ X interim(); X mate(); X break; X default: /* <-- All cases not specifically numbered above */ X movewhale(); /* This, then, gets called every month */ X break; X } X } X if (debug >= 7) X fprintf(stdout, "Cycle %d, Month %d\n", cycle, months); X if (debug >= 7) X fprintf(stdout, " Year %d\n", year); X /* Should't remove this! Modify SAFETY in whpl.h, if necessary: */ X if (cycle >= SAFETY) X { X if (debug >= 2) X fprintf(stderr, X "\nmain(): EXIT FROM MAIN LOOP: cycle > SAFETY\n\n"); X if (debug >= 6) X fprintf(stdout, X "\nmain(): EXIT FROM MAIN LOOP: cycle > SAFETY\n\n"); X break; X } X if (year >= yearflg) X { X break; /* <-- NORMAL EXIT FROM MAIN DO LOOP */ X } X } while (1); /* do-loop continues */ X /* Run whales some more to get their final energy rankings: */ X post = 12; /* <-- Remove this line to bypass the "post" loop altogether */ X if (post) X { X if (debug >= 5) X fprintf(stdout, "Final whale moves for %d months\n", post); X for (months = 1; months <= post; months++) X { X movewhale(); X if (months == 3 || months == 7) X { X for (j = 0; j < numwh; j++) X { X whale[j].locatn = whaleplace(); X whale[j].lastfed = 1000000; X } X } X if (debug >= 5) X if (!(months % 2)) X fprintf(stdout, " %2d\n", months); X } X } X if (debug >= 5) X fprintf(stdout, "main(): finishing run\n"); X if (debug >= 6) X fprintf(stderr, "main(): finishing run\n"); X /* I prefer to trim the whales' numbers one last time */ X whaledie(0); X /* Final computations and file output */ X finish(1); X} SHAR_EOF if test 29028 -ne "`wc -c < 'whx.c2'`" then echo shar: error transmitting "'whx.c2'" '(should have been 29028 characters)' fi fi # end of overwriting check # End of shell archive exit 0 --- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | Bob Loy | Life is the detour you take on the ...!sun!sunburn!gtx!loy | way to where you're really going. | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~