/* ************************************************************************************ ************************************************************************************ ** ** ** NANITES! A program to simulate growth and death. ** ** V1.33HX/112393 BY ANDY GRUENENWALD ** ** ** ** Originally written in QuickBASIC 4.5 -- converted to Turbo C++. ** ** With the translation to C++, a few bugs in how nanites breed were fixed. ** ** ** ** When compiling with TURBO C++ 3.0 the following LINK options MUST be used: ** ** ** ** љ Graphics and standard run-time libraries must be loaded automatically ** ** љ the link must be case-sensative. ** ** ** ** ** ** The rules and conditions for the nanites is explained below: ** ** ** ** ** ** NANITE ENVIRONMENT ** ** ------------------ ** ** љ The Nanite environment consists of a 320 x 240 wrap-round box. ** ** ** ** љ There is a chance of Famin that will effect 25% to 60% of the Nanite ** ** population. The chance of a Famin occuring is "FaminChance" to 1. ** ** A test is made every cycle based on the following formula: ** ** ** ** (CurrentPopulation - d) ** ** ( 1 - ----------------------- ) * FaminChance ** ** (MaxAllowed - d) ** ** ** ** Young nanites age 50% LifeSpan, middle-aged nanites get old and old ** ** nanites die. The chance of famin increases as the population increases ** ** beyond 1/2 the way from "PopLimiter" to "MaxAllowed". Famin also effects ** ** the Nanites' will to breed. "WillToBreed" is cut from 20% to 80% for a ** ** period of "FaminEffect" cycles after which "WillToBreed" will be ** ** recalculated. ** ** ** ** ** ** NANITE MOVEMENT ** ** --------------- ** ** љ The Nanites move in straight lines either up, down, left, or right. The ** ** length of these lines renges from "MINL" to "MAXL". ** ** ** ** љ Nanites can not do 180ј torns, they must either keep going straight or ** ** turn left or right. ** ** ** ** ** ** NANITE AGE AND BREEDING ** ** ----------------------- ** ** љ A Nanite can live an ultimate life span of "LifeSpan" cycles. ** ** ** ** љ Nanites must be within a certain age to breed. Those below "MinimumLife" ** ** are too young and are colored green. Nanites at or older than ** ** "NearDeath" can nolonger produce and are colored brown. Nanites ** ** in-between these ages can produce and are colored yellow. ** ** ** ** љ If two yellow Nanites collide, a new green nanite is created. The two ** ** yellow Nanites will keep moving their same directions. The new Nanite ** ** will start moving in a direction different from the two yellow Nanites. ** ** ** ** љ Nanites will breed until the total population equals "MaxAllowed". ** ** ** ** љ When two yellow Nanites breed, they lose "Aged" cycles of life (their ** ** life span shortens). ** ** ** ** љ When a nanite reaches the age of "LifeSpan" it dies. ** ** ** ** љ Wether or not two Nanites breed in slightly effected by "WillToBreed". ** ** The value in this variable acts as a percent as to if a nanite wants to ** ** breed or not. When the nanite population exceeds "PopLimiter" this value ** ** drops according to this formula: ** ** ** ** (nanites - PopLimiter) ** ** 100 - ( ------------------------- ) * 100 ** ** (MaxAllowed - PopLimiter) ** ** ** ** The "WillToBreed" effects all Nanites. ** ** ** ************************************************************************************ ************************************************************************************ */ #include #include #include #include #include #define ARR_LIM 2000 // nanite constants int StartNumber, MaxAllowed, MinMoveLength, MaxMoveLength, LifeSpan; int MinimumLife, Aged, NearDeath; // nanite loop variables (movement, famin, will to breed, cycle counts, etc...) int CurrentNumber, Cycle, MX, MY; int WillToBreed, PopLimiter, FaminChance, FaminEffect, PC, PV, DF, OrigWill,FC,C; int OC1, OC2, OC3, OWB, NC1, NC2, NC3; float FaminOdds; // Video initialization / display variables int gdrv, gmod, errorcode; char buffer[12]; // misc. looping and temporary variables int F, dx, dy, D, I, J, N, EscapeKey; // nanite log file and parameter file declaration variables FILE *DFfile, *ParamFile; // variables for scrolling population graph int GraphX; float GraphScale, GraphBottom; // arrays for nanite ages and positions (primary and secondary) int DX[ARR_LIM], DY[ARR_LIM], X[ARR_LIM], Y[ARR_LIM], Length[ARR_LIM], Life[ARR_LIM]; int NC[ARR_LIM]; int mx[4] = {0,0,-1,1}, my[4] = {-1,1,0,0}; void LoadParams() { char FieldID[25]; int l,v; printf("Accessing initial parameters file..."); for (l=1;l<=14;l++) { fscanf(ParamFile,"%25s %d\n",FieldID,&v); switch (l) { case 1: C=v; case 2: StartNumber=v; case 3: MaxAllowed=v; case 4: PopLimiter=v; case 5: MinMoveLength=v; case 6: MaxMoveLength=v; case 7: WillToBreed=v; case 8: FaminChance=v; case 9: FaminEffect=v; case 10: LifeSpan=v; case 11: MinimumLife=v; case 12: NearDeath=v; case 13: Aged=v; case 14: DF=v; } } fclose(ParamFile); printf("Done!\n"); } void DrawScreen() { int N; gdrv = VGA; initgraph(&gdrv, &gmod, ""); errorcode = graphresult(); if (errorcode != grOk) // an error occurred { printf("Graphics error: %s\n", grapherrormsg(errorcode)); printf("Press any key to halt:"); getch(); exit(1); // terminate with an error code } setcolor(8); rectangle(259,59,581,301); rectangle(257,57,583,58); rectangle(257,58,258,301); rectangle(583,58,582,301); rectangle(299,301,639,384); rectangle(0,301,299,479); setcolor(12); line(299,478-(PopLimiter*GraphScale)+GraphBottom,301,478-(PopLimiter*GraphScale)+GraphBottom); N = (MaxAllowed - PopLimiter) / 2 + PopLimiter; setcolor(10); line(299,478-N*GraphScale+GraphBottom,301,478-N*GraphScale+GraphBottom); setcolor(14); outtextxy(0,0,"NANITES - A program to simulate growth/death cycles. V1.33HX/112393"); outtextxy(0,8,"Originaly written in QuickBASIC 4.5 and Upgraded to C++ by Andy Gruenenwald."); setcolor(3); outtextxy(0,56,"INITIAL PARAMITERS:"); setcolor(8);outtextxy(0,72,"Random seed:"); setcolor(7);sprintf(buffer,"%d",C);outtextxy(104,72,buffer); setcolor(8);outtextxy(0,88,"Initial population:"); setcolor(7);sprintf(buffer,"%d",StartNumber);outtextxy(160,88,buffer); setcolor(8);outtextxy(0,104,"Maximum population:"); setcolor(7);sprintf(buffer,"%d",MaxAllowed);outtextxy(160,104,buffer); setcolor(8);outtextxy(0,120,"Population limiter:"); setcolor(7);sprintf(buffer,"%d",PopLimiter);outtextxy(160,120,buffer); setcolor(8);outtextxy(0,152,"Range of length:"); setcolor(7);sprintf(buffer,"%d %d",MinMoveLength,MaxMoveLength);outtextxy(136,152,buffer); setcolor(8);outtextxy(0,168,"Will to breed:"); setcolor(7);sprintf(buffer,"%d",WillToBreed);outtextxy(120,168,buffer); setcolor(8);outtextxy(0,184,"Chance of a famin:"); setcolor(7);sprintf(buffer,"1/%d",FaminChance);outtextxy(152,184,buffer); setcolor(8);outtextxy(0,200,"Famin effect:"); setcolor(7);sprintf(buffer,"%d",FaminEffect);outtextxy(112,200,buffer); setcolor(8);outtextxy(0,232,"Ultimate life span:"); setcolor(7);sprintf(buffer,"%d",LifeSpan);outtextxy(160,232,buffer); setcolor(8);outtextxy(0,248,"Minimum age to breed:"); setcolor(7);sprintf(buffer,"%d",MinimumLife);outtextxy(176,248,buffer); setcolor(8);outtextxy(0,264,"Maximum age to breed:"); setcolor(7);sprintf(buffer,"%d",NearDeath-1);outtextxy(176,264,buffer); setcolor(8);outtextxy(0,280,"Added age after breeding:"); setcolor(7);sprintf(buffer,"%d",Aged);outtextxy(208,280,buffer); setcolor(3);outtextxy(312,312,"RUNNING VALUES:"); setcolor(8);outtextxy(312,328,"Cycle: Nanites:"); outtextxy(312,344,"Will to breed:"); outtextxy(312,360,"Famins: Victims:"); outtextxy(312,376,"Chance of famin:"); setcolor(8);outtextxy(320,448,"Graph vertical scale:"); setcolor(7);sprintf(buffer,"%d",MaxAllowed-StartNumber);outtextxy(496,448,buffer); setcolor(8);outtextxy(320,464,"Vertical scaler:"); setcolor(7);sprintf(buffer,"%f",GraphScale);outtextxy(456,464,buffer); } void Famin() { int J,K,N,N1,N2,N3; for(J=100;J<=500;J+=10) { for(K=J;K>=100+(J/50);K-=5) { sound(K); delay(2); } } nosound(); // Age the entire population. young gain 50% of lifespan cycles, // middle-aged age to NearDeath+1 and old ones die. if (DF==1) { fprintf(DFfile,"Famin occured at cycle %d...\n",Cycle); fprintf(DFfile,"PRE-FAMIN nanite count: %d %d %d - Total: %d\n",NC1, NC2, NC3, NC1+NC2+NC3); fprintf(DFfile,"PRE-FAMIN Will to breed: %d\n",WillToBreed); } PC++; // Famin COUNT N = (rand() % 36)+25; // KILL BETWEEN 25 AND 60%. if (DF==1) fprintf(DFfile,"The famin effected %d%% of the nanites...\n",N); N = (float)(((float)(N)/100)*(NC1+NC2+NC3)); N1 = N2 = N3 = 0; for (J=1;J<=N;J++) { K = 1; do { K = (rand() % CurrentNumber)+1; // pick out nanites at random to effect } while (Life[K] > LifeSpan); if (Life[K] < MinimumLife) // Age the young to half of LifeSpan { Life[K] += LifeSpan/2; N1++; } if (Life[K] >= MinimumLife && Life[K] <= NearDeath) { Life[K] = NearDeath+1; // age adult nanites to old age N2++; } if (Life[K] > NearDeath+1) { Life[K] = LifeSpan + 1; // kill old nanites putpixel(X[K], Y[K], 0); N3++; } } if (DF==1) { fprintf(DFfile,"A total of %d young nanites aged.\n",N1); fprintf(DFfile,"A total of %d middle-aged nanites became old.\n",N2); fprintf(DFfile,"A total of %d old nanites died.\n",N3); } PV += N; // Famin VICTIMS if (DF==1) fprintf(DFfile,"POST-FAMIN nanite count: %d %d %d - Total: %d\n",NC1-N1, NC2-N2, NC3-N3, NC1-N1+NC2-N2+NC3-N3); // famin effects WillToBreed. N = (rand() % 61) + 20; // 20% TO 80% if (DF==1) fprintf(DFfile,"The nanites' will to breed dropped %d%%\n",N); N = (float)(((100-(float)N) / 100) * WillToBreed); OrigWill = WillToBreed; WillToBreed = N; if (Cycle - FC > FaminEffect) FC = Cycle; // Mark when the famin started. else FC += FaminEffect; // IF ALLREADY SUFFERING, ADD TO IT. if (DF==1) { fprintf(DFfile,"POST-FAMIN Will to breed: %d\n",WillToBreed); fprintf(DFfile,"The effects of the famin will be felt for the next %d cycles.\n",(FC-Cycle)+FaminEffect); fprintf(DFfile,"\n"); } } void GraphData() { int J,Y; GraphX++; if (GraphX==299) { for(J=1;J<299;J++) { if (NC[J] > 478) putpixel(J,478,0); else putpixel(J,NC[J],0); NC[J] = NC[J + 1]; if (NC[J] > 478) putpixel(J,478,4); else putpixel(J,NC[J],7); } GraphX = 298; } Y = 478-((NC1+NC2+NC3)*GraphScale)+GraphBottom; if (Y > 478) putpixel (GraphX,478,4); else putpixel(GraphX,Y,7); NC[GraphX] = Y; } void Multiply() { int D,J,N,N1; if (CurrentNumber < MaxAllowed-1) // only breed if population < maximum { D = (rand() % 100) + 1; if (D <= WillToBreed) // are nanites willing to breed? { N=I;N1=1; while (X[N1]!=X[I]||Y[N1]!=Y[I]) N1++; // find addrssses of the nanites if (Life[N1] >= MinimumLife && Life[N1] < NearDeath) // are nanites in age range to breed? { // NEW NANITE!!! FIND A PLACE FOR HIM IN THE ARRAY OF LIFE. // Done by finding dead nanite positions and using those first before // increasing CurrentNumber. J=1; while (Life[J] <= LifeSpan && J <= CurrentNumber) J++; if (J > CurrentNumber) CurrentNumber++; Life[J] = 0; X[J] = X[N]; Y[J] = Y[N]; // place new nanite at location of collision do // pick new direction different { // from both parents D = rand() % 4; dx=mx[D]; dy=my[D]; F = 1; if (dx==DX[N] && dy==DY[N]) F = 0; if (dx==DX[N1] && dy==DY[N1]) F = 0; } while (F != 1); DX[J] = dx; DY[J] = dy; Length[J] = MinMoveLength + (rand() % (MaxMoveLength - MinMoveLength)); // GIVING LIFE WILL AGE THE TWO MATES. Life[N] += Aged; Life[N1] += Aged; } } } } void main() { MX = 580; MY = 300; StartNumber = 80; MaxAllowed = 500; MinMoveLength = 5; MaxMoveLength = 20; LifeSpan = 1000; // How long a nanite COULD live MinimumLife = 150; // Nanites has to be this old to have a kid. Aged = 15; // When nanites have kids they get this much older. NearDeath = 900; // Nanites are getting old - can't produce WillToBreed = 100; // This is a percent. right now, Nanites want to breed! PopLimiter = 200; // When population > this, nanite will to breed drops inversly FaminChance = 5000; // Chance of a Famin (kills from 25 to 75% of population FaminEffect = 75; // Cycles after a famin that "WillToBreed" drops. PC = 0; PV = 0; // Famin count and victims. DF = 0; // Write a data file (0-NO,1-YES) OrigWill = WillToBreed; FC = 0; // used for famins - cycle # last famin occured OWB = 0; FaminOdds = 0; // odds of a famin (1 / FaminOdds) C = 724; // A RANDOM SEED if ((ParamFile = fopen("NANITES.PAR","rt")) != NULL) LoadParams(); CurrentNumber = StartNumber; // CurrentNumber is not exactally the // current number of living nanites, it // is the highest position in the array // that has been accessed thus far. srand(C); gmod = VGAHI; // 640 x 480 x 16 (standard VGA) EscapeKey = 0; // CLEAR ARRAYS - Very important to clear those arrays for (I=1;I<=ARR_LIM;I++) { DX[I]=0; DY[I]=0; X[I]=0; Y[I]=0; Length[I]=0; NC[I]=0; } // Pick random starting location and prepare all nanites for life. for (I=1;I<=StartNumber;I++) { X[I] = 160 + rand() % MX; Y[I] = 60 + rand() % MY; D = rand() % 4; DX[I]=mx[D]; DY[I]=my[D]; Length[I] = MinMoveLength + (rand() % (MaxMoveLength - MinMoveLength)); Life[I] = 0; } Cycle = 1; GraphX = 0; GraphScale = (float)176 / (MaxAllowed - StartNumber); GraphBottom = StartNumber * GraphScale; OC1 = CurrentNumber; OC2 = OC3 = 0; OWB = WillToBreed; NC1 = CurrentNumber; NC2 = NC3 = 0; DrawScreen(); if (DF==1) { DFfile = fopen("NANITES.DTA","wt"); fprintf(DFfile,"NANITES! progress report file. \n"); fprintf(DFfile,"\n"); fprintf(DFfile,"RANDOM SEED USED: %d\n",C); fprintf(DFfile,"\n"); fprintf(DFfile,"INITIAL PARAMITERS:\n"); fprintf(DFfile,"Start population: %d\n",CurrentNumber); fprintf(DFfile,"Maximum population: %d\n",MaxAllowed); fprintf(DFfile,"Population limiter: %d\n",PopLimiter); fprintf(DFfile,"\n"); fprintf(DFfile,"Range of length: %d %d\n",MinMoveLength,MaxMoveLength); fprintf(DFfile,"Will to breed: %d\n",WillToBreed); fprintf(DFfile,"Chance of a Famin: 1/%d\n",FaminChance); fprintf(DFfile,"Famin effect: %d\n",FaminEffect); fprintf(DFfile,"\n"); fprintf(DFfile,"Ultimate life span: %d\n",LifeSpan); fprintf(DFfile,"Minimum age to breed: %d\n",MinimumLife); fprintf(DFfile,"Maximum age to breed: %d\n",NearDeath); fprintf(DFfile,"Added age after breeding: %d\n",Aged); fprintf(DFfile,"\n"); fprintf(DFfile,"------------------------------------------------------------------------------\n"); fprintf(DFfile,"\n"); } // Nanite loop do { setcolor(0);outtextxy(376,328,"лллллллл"); setcolor(7);sprintf(buffer,"%d",Cycle);outtextxy(376,328,buffer); if (NC1 != OC1 || NC2 != OC2 || NC3 != OC3 || WillToBreed != OWB) { setcolor(0); outtextxy(512,328,"лллллллллллллл"); outtextxy(432,344,"лллллллллллллллллллллллл"); outtextxy(560,360,"лллллллл"); outtextxy(448,376,"ллллллл"); setcolor(7);sprintf(buffer,"%d",NC1+NC2+NC3);outtextxy(512,328,buffer); setcolor(2);sprintf(buffer,"%d",NC1);outtextxy(560,328,buffer); setcolor(14);sprintf(buffer,"%d",NC2);outtextxy(560,344,buffer); setcolor(6);sprintf(buffer,"%d",NC3);outtextxy(560,360,buffer); setcolor(7);sprintf(buffer,"%d",WillToBreed);outtextxy(432,344,buffer); sprintf(buffer,"1/%d",(int)FaminOdds);outtextxy(448,376,buffer); if (PV > 0) { setcolor(0); outtextxy(376,360,"ллл"); outtextxy(480,360,"ллллл"); setcolor(7); sprintf(buffer,"%d",PC);outtextxy(376,360,buffer); sprintf(buffer,"%d",PV);outtextxy(480,360,buffer); } OC1 = NC1; OC2 = NC2; OC3 = NC3; OWB = WillToBreed; } NC1 = 0; NC2 = 0; NC3 = 0; for (I=1;I<=CurrentNumber;I++) { // Move those nanites! if (Life[I] <= LifeSpan) { putpixel(X[I],Y[I],0); X[I] += DX[I]; if (X[I] < 260) X[I] = MX; if (X[I] > MX) X[I] = 260; Y[I] += DY[I]; if (Y[I] < 60) Y[I] = MY; if (Y[I] > MY) Y[I] = 60; if (getpixel(X[I],Y[I])==14 && Life[I]>=MinimumLife && Life[I]= MinimumLife && Life[I] < NearDeath) {NC2++; putpixel(X[I], Y[I], 14);} if (Life[I] >= NearDeath) {NC3++; putpixel(X[I], Y[I],6);} if (Life[I] > LifeSpan) putpixel(X[I], Y[I], 0); Length[I]--; // change nanite direction if necessary if (Length[I] == 0) { do { D = rand() % 4; dx=mx[D]; dy=my[D]; F = 1; // these lines make sure if (dx==-DX[I]) F = 0; // nanite doesn't do a 180 if (dy==-DY[I]) F = 0; // degree turn. } while (F == 0); DX[I] = dx; DY[I] = dy; Length[I] = MinMoveLength + (rand() % (MaxMoveLength - MinMoveLength)); } } } if (Cycle - FC > FaminEffect) { if (NC1+NC2+NC3>=PopLimiter) // drop nanite will-to-breed. WillToBreed = 100 - (float)((NC1+NC2+NC3)-PopLimiter) / (MaxAllowed-PopLimiter)*100; else WillToBreed = 100; } if (Cycle % 5 == 0) GraphData(); if (Cycle % 50 == 0 && DF == 1) { fprintf(DFfile,"Cycle # %d report:\n",Cycle); fprintf(DFfile,"Nanite count (R,Y,B): %d %d %d - Total: %d\n",NC1, NC2, NC3, NC1+NC2+NC3); fprintf(DFfile,"Will to breed: %d\n",WillToBreed); fprintf(DFfile,"Chance of famin: 1/%d\n",FaminChance); fprintf(DFfile,"\n"); } // Calculate famin using nasty formula D = (float)((PopLimiter+MaxAllowed)/2); if (NC1+NC2+NC3-D>0) FaminOdds = (1-((float)(NC1+NC2+NC3-D)/(MaxAllowed-D)))*FaminChance; else FaminOdds = FaminChance; N = (rand() % (int)FaminOdds) + 1; if (N==(int)FaminOdds) Famin(); Cycle++; if (kbhit()) if (getch()==27) EscapeKey = 1; } while (NC1+NC2+NC3 > 1 && EscapeKey == 0); if (DF==1) { if (EscapeKey==1) fprintf(DFfile,"***NANITE CULTURE TERMINATED BY USER***\n"); fprintf(DFfile,"NANITES DIED AT CYCLE %d\n",Cycle); fclose(DFfile); } // NANITES ALL DEAD! for (I=10000;I>=1000;I-=200) { for (J=I;J>50;J-=1000) { sound(J); delay(10); } } nosound(); do { setcolor(13); outtextxy(352,408,"Nanites have died!!!"); delay(20); setcolor(9); outtextxy(352,408,"Nanites have died!!!"); delay(20); } while (!(kbhit())); closegraph(); }