home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / listings / v_08_10 / 8n10055a < prev    next >
Text File  |  1990-11-06  |  23KB  |  877 lines

  1. //////////////////////////////////////////////////////////////////////////
  2. //                                                                      //
  3. //                             ANTHILL                                  //
  4. //                                by                                    //
  5. //                     Mark Weaver and Alex Lane                        //
  6. //                                                                      //
  7. //////////////////////////////////////////////////////////////////////////
  8.  
  9. #include <graphics.h>
  10. #include <stdlib.h>
  11. #include <stdio.h>
  12. #include <conio.h>
  13. #include <math.h>
  14. #include <dos.h>
  15. #include <ctype.h>
  16. #include <string.h>
  17. #include "anthill.h"
  18.                     
  19. #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
  20.  
  21. //////////////////////////////////////////////////////////////////////////
  22. //                                                                      //
  23. //                          Global Variables                            //
  24. //                                                                      //
  25. //////////////////////////////////////////////////////////////////////////
  26. float gfCellSizeX;              // Width (in pixels) of a cell
  27. float gfCellSizeY;              // Height (in pixels) of a cell
  28. unsigned guFoodUnits[100][100]; // How many units of food in each cell
  29. int gnTimeToHatch;              // Cycles required to become a worker ant
  30. int gnDropDistance;             // Distance at which to drop food for queen
  31. unsigned long gulTotalFood;     // Total units of food on board
  32. unsigned guWorkers;             // Total workers on board
  33. unsigned guEggs;                // Total number of eggs on board
  34. unsigned long gulCycle;         // Which life cycle are we in?
  35. unsigned guWorkersPortion;      // What a worker eats from each food packet
  36. unsigned guMaxLifeSpan;         // Longest life span
  37. unsigned guBirthRate;           // Percentage of cycles queen lays an egg
  38. unsigned guMaxSpeed;            // Maximum speed for worker ants
  39. unsigned guQueensEnergy;        // Queens extra starting energy level
  40. unsigned guInitEggs;            // Initial # of eggs
  41. unsigned guInitWorkers;         // Initial # of worker ants
  42. unsigned guInitFood;            // Initial # of cells with food
  43. unsigned guPause;               // Milliseconds to pause each cycle
  44. Queen *gQueen;                  // Queen ant
  45. Worker *headOfAntList;          // Head of linked list of worker ants
  46.  
  47.  
  48. //////////////////////////////////////////////////////////////////////////
  49. //                                                                      //
  50. //                        MOVER class functions                         //
  51. //                                                                      //
  52. //////////////////////////////////////////////////////////////////////////
  53.  
  54. Mover::Mover(unsigned uMaxRng, unsigned uMaxSpd, int nStartX, int nStartY)
  55. {
  56.   uMaxRange = uMaxRng;
  57.   uMaxSpeed = uMaxSpd;
  58.   nX = nInitX = nStartX;
  59.   nY = nInitY = nStartY;
  60.   bVisible = FALSE;
  61.   nVelX = -uMaxSpeed + random(uMaxSpeed + 1);
  62.   nVelY = -uMaxSpeed + random(uMaxSpeed + 1);
  63. }
  64.  
  65. int Mover::getX( void )
  66. {
  67. return nX;
  68. }
  69.  
  70. int Mover::getY( void )
  71. {
  72. return nY;
  73. }
  74.  
  75. BOOLEAN Mover::moveTo(int nNewX, int nNewY )
  76. {
  77.   if ((distance(nNewX, nNewY, nInitX, nInitY) <= uMaxRange || !uMaxRange)){
  78.     erase();
  79.      if ((nX = nNewX) < 0){
  80.         nX = 0;
  81.      }
  82.      else 
  83.         if (nX > 99) {
  84.             nX = 99;
  85.             }
  86.  
  87.      if ((nY = nNewY) < 0){
  88.         nY = 0;
  89.      }
  90.      else 
  91.         if (nY > 99) {
  92.         nY = 99;
  93.         }
  94.  
  95.      draw();
  96.      return( TRUE );
  97.   }
  98.   else {
  99.      return( FALSE );
  100.   }
  101. }
  102.  
  103. BOOLEAN Mover::move( void )
  104. {
  105.   int nNewX, nNewY;
  106.  
  107.   nNewX = nX + nVelX;
  108.   nNewY = nY + nVelY;
  109.  
  110.   if ((distance(nNewX, nNewY, nInitX, nInitY) <= uMaxRange || !uMaxRange)){
  111.     erase();
  112.      if ((nX = nNewX) < 0) {
  113.         nX = 0;
  114.         nVelX = -nVelX;
  115.      } 
  116.      else 
  117.         if (nX > 99) {
  118.             nX = 99;
  119.             nVelX = -nVelX;
  120.             }
  121.      if ((nY = nNewY) < 0) {
  122.         nY = 0;
  123.         nVelY = -nVelY;
  124.      }
  125.      else 
  126.         if (nY > 99) {
  127.         nY = 99;
  128.         nVelY = -nVelY;
  129.      }
  130.      draw();
  131.  
  132.     // Turn once in a while
  133.     if (random(100) < 10){
  134.       nVelX += random(3) - 1;
  135.       nVelY += random(3) - 1;
  136.         if (nVelX > uMaxSpeed) {
  137.           nVelX = uMaxSpeed;
  138.         }
  139.         else 
  140.             if (nVelX < -uMaxSpeed) {
  141.                 nVelX = -uMaxSpeed;
  142.             }
  143.  
  144.         if (nVelY > uMaxSpeed) { 
  145.           nVelY = uMaxSpeed;
  146.         }
  147.         else 
  148.             if (nVelY < -uMaxSpeed) {
  149.                 nVelY = -uMaxSpeed;
  150.             }
  151.  
  152.       // Make sure I do not stop
  153.         if (nVelX == 0 && nVelY == 0) {
  154.           nVelX = 1+random(uMaxSpeed-1);
  155.           nVelY = -1-random(uMaxSpeed-1);
  156.         }
  157.      }
  158.  
  159.      return( TRUE );
  160.   }
  161.   else {
  162.      draw();
  163.      return( FALSE );
  164.   }
  165. }
  166.  
  167. void Mover::show( void )
  168. {
  169.   if (!bVisible){
  170.      draw();
  171.      bVisible = TRUE;
  172.   }
  173. }
  174.  
  175. void Mover::erase( void )
  176. {
  177.   moverDrawFunc(nX, nY, FALSE, BACKGROUND );
  178. }
  179.  
  180. void Mover::draw( void )
  181. {
  182.   moverDrawFunc(nX, nY, TRUE, color);
  183. }
  184.  
  185. void Mover::moverDrawFunc(int nX, int nY, BOOLEAN bVisible, int nColor)
  186. {
  187.     setfillstyle(SOLID_FILL, bVisible ? nColor : BACKGROUND);
  188.     bar(nX * gfCellSizeX,        nY * gfCellSizeY,
  189.             (nX + 0.5) * gfCellSizeX, (nY + 1) * gfCellSizeY - 1);
  190.  
  191.  
  192. //////////////////////////////////////////////////////////////////////////
  193. //                                                                      //
  194. //                          ANT class functions                         //
  195. //                                                                      //
  196. //////////////////////////////////////////////////////////////////////////
  197.  
  198. Ant::Ant( int Range, int Speed, int nX, int nY, int Energy) :
  199.              Consumer( Energy ), // constructor 
  200.              Mover( Range, Speed, nX, nY ) // constructor
  201. {
  202.   bDead= FALSE;
  203. }
  204.  
  205. // Dying ant updates counters and drops any food he is carying
  206. void Ant::die(void)
  207. {
  208.   bDead = TRUE;
  209.   nEnergy = 0;
  210.   erase(); 
  211. }
  212.  
  213. void Ant::doTheAntThing(void)
  214. {
  215. // Age the ant
  216. nAge++;
  217.  
  218. // Every ant uses one energy unit per cycle
  219. nEnergy -= 1;
  220.  
  221. if (nEnergy<1 || nAge > nLifeSpan) {
  222.     die();
  223.     }
  224. else { 
  225.     if (bEgg) {
  226.         // force redraw in case egg has been walked on
  227.         moveTo(nX, nY); 
  228.         if (nAge > gnTimeToHatch) {
  229.             bEgg = FALSE;
  230.             color = GREEN;    
  231.             guEggs--;
  232.             guWorkers++;
  233.             }
  234.         }
  235.     }
  236. }
  237.  
  238. //////////////////////////////////////////////////////////////////////////
  239. //                                                                      //
  240. //                       QUEEN class functions                          //
  241. //                                                                      //
  242. //////////////////////////////////////////////////////////////////////////
  243.  
  244. Queen::Queen( unsigned InitEnergy, int QRange, int QSpeed, 
  245.                   int QIntitX, int QInitY, unsigned _birthRate ) : 
  246.     Ant(QRange, QSpeed, QIntitX, QInitY, random(100)+InitEnergy )
  247. {
  248.   birthRate = _birthRate;
  249.   color = YELLOW;
  250. }
  251.  
  252.  
  253. // Queen ant lays eggs once in a while
  254. void Queen::layEgg(void)
  255. {
  256.   new Worker(TRUE, nX, nY);
  257.   guEggs++;
  258.   nEnergy -= MIN(150, nEnergy);
  259. }
  260.  
  261.  
  262. void Queen::doTheAntThing(void)
  263. {
  264. // Every ant uses one energy unit per cycle
  265. nEnergy -= 1;
  266.  
  267. nVelX = random(uMaxSpeed+1)*(random(2) ? 1 : -1 );
  268. nVelY = random(uMaxSpeed+1)*(random(2) ? 1 : -1 );
  269.  
  270. if (nEnergy<1) {
  271.     die();
  272.     }
  273. else {
  274. // Turn around if at limits of area!
  275. if (distance(nInitX, nInitY, nX + nVelX, nY + nVelY) > uMaxRange) {
  276.     nVelX = -nVelX ;
  277.     nVelY = -nVelY ;
  278.     }
  279.                              
  280.     // Move somewhere
  281.     move();
  282.  
  283.     if (guFoodUnits[nX][nY]) {
  284.         eatFood(guFoodUnits[nX][nY]);
  285.         }
  286.     // need a minimum of 750 units to be able to lay an egg
  287.     // (the idea here is to conserve energy)
  288.     if ((nEnergy > 750) && (random(100) < birthRate)) {
  289.         layEgg();
  290.         }
  291.     // if the energy level gets too high, improve the chances of
  292.     // laying an egg; and vice versa
  293.     // keep the birthrate between 50 and 5 percent.
  294.     if ((nEnergy > 5000) && (birthRate < 49)) birthRate++;
  295.     if ((nEnergy < 3000) && (birthRate > 6)) birthRate--;
  296.     }
  297. }
  298.  
  299. //////////////////////////////////////////////////////////////////////////
  300. //                                                                      //
  301. //                       WORKER class functions                         //
  302. //                                                                      //
  303. //////////////////////////////////////////////////////////////////////////
  304.  
  305. Worker::Worker( BOOLEAN bEggYes, int nX, int nY ) : 
  306.              Ant( 0, guMaxSpeed, nX, nY, random(100)+50 )
  307. {
  308.   bEgg = bEggYes;
  309.   addToList();
  310.   nFood = 0;    // Start out carrying no food
  311.   // ants live for lifespan plus/minus 20%
  312.   nLifeSpan = (0.8 * guMaxLifeSpan) + random(0.4 * guMaxLifeSpan);
  313.  
  314.   if (bEggYes){
  315.      color = CYAN;
  316.      nAge = 0;
  317.   }else{
  318.      color = GREEN;
  319.      nAge = gnTimeToHatch + 1;
  320.   }
  321. }
  322.  
  323. Worker::~Worker(void)
  324. {
  325.   // Remove myself from the ant list
  326.   if (prevWorker == NULL) {
  327.      headOfAntList = nextWorker;
  328.   }
  329.   else {
  330.     prevWorker->nextWorker = nextWorker;
  331.   }
  332.   if (nextWorker != NULL) {
  333.     nextWorker->prevWorker = prevWorker;
  334.   }
  335. }
  336.  
  337. // Lie down and be counted (out)!!
  338. void Worker::die(void)
  339. {
  340.   // Drop any food before going to ant heaven
  341.   if (nFood) {
  342.      guFoodUnits[nX][nY] += nFood;
  343.   }
  344.   Ant::die();           // Call ant die function
  345.  
  346.   if (bEgg){
  347.      guEggs--;
  348.   }else{
  349.     guWorkers--;
  350.   }
  351. }
  352.  
  353.  
  354. // Add new ant to head of doubly linked list
  355. void Worker::addToList()
  356. {
  357.   // Place myself at the head of doubly linked list of ants
  358.   nextWorker = headOfAntList;
  359.   headOfAntList = this;
  360.   prevWorker = NULL;
  361.   if (nextWorker != NULL) {
  362.     nextWorker->prevWorker = this;
  363.   }
  364. }
  365.  
  366. // Drop food for the Queen to eat
  367. void Worker::dropFood(void)
  368. {
  369.   int xDist, yDist;
  370.  
  371.   guFoodUnits[nX][nY] += nFood;
  372.   nFood = 0;
  373.   color = GREEN;
  374.   showFood(nX, nY, TRUE);
  375.  
  376.   // Move AWAY from queen
  377.   if (nX < gQueen->getX()) {
  378.      xDist = -uMaxSpeed;
  379.   }
  380.   else 
  381.     if (nX > gQueen->getX()) {
  382.         xDist = uMaxSpeed;
  383.     }
  384.   if (nY < gQueen->getY()) {
  385.      yDist = -uMaxSpeed;
  386.   }
  387.   else 
  388.     if (nY > gQueen->getY()) {
  389.         yDist = uMaxSpeed;
  390.     }
  391.   moveTo(nX + xDist, nY + yDist);
  392. }
  393.  
  394. // Grab food to carry to queen, after eating a portion for self
  395. void Worker::grabFood(void)
  396. {
  397. // Eat some food to replenish energy
  398. eatFood(guWorkersPortion);
  399.  
  400. // Pick up rest to carry to queen
  401. nFood = guFoodUnits[nX][nY];
  402. guFoodUnits[nX][nY] = 0;
  403. showFood(nX, nY, FALSE);
  404. color = LIGHTRED;
  405. }
  406.  
  407. // Carry food toward queen ant
  408. void Worker::moveTowardQueen(void)
  409. {
  410.   int xDist, yDist;
  411.  
  412.   if (nX > gQueen->getX()) {
  413.      xDist = -1 * MIN(uMaxSpeed / 2, nX - gQueen->getX());
  414.   }
  415.   else 
  416.     if (nX < gQueen->getX()) {
  417.         xDist = MIN(uMaxSpeed / 2, gQueen->getX() - nX);
  418.     }
  419.     else {
  420.         xDist = 0;
  421.     }
  422.  
  423.   if (nY > gQueen->getY()) {
  424.       yDist = -1 * MIN(uMaxSpeed / 2, nY - gQueen->getY());
  425.   }
  426.   else 
  427.       if (nY < gQueen->getY()) {
  428.           yDist = MIN(uMaxSpeed / 2, gQueen->getY() - nY);
  429.       }
  430.       else {
  431.           yDist = 0;
  432.       }
  433.  
  434.   moveTo(nX + xDist, nY + yDist );
  435. }
  436.  
  437.  
  438. // Roam around randomly, looking for food
  439. void Worker::lookForFood(void)
  440. {
  441. if (!bEgg) {
  442.   move();
  443.   if (guFoodUnits[nX][nY]) {
  444.      grabFood();
  445.      }
  446.   }
  447. }
  448.  
  449. void Worker::doTheAntThing(void)
  450. {
  451. Ant::doTheAntThing(); // age, reduce energy, die if necessary
  452. if (nFood) {
  453.     if (distance(nX, nY, gQueen->getX(), gQueen->getY()) <= gnDropDistance) {
  454.         dropFood();
  455.         }
  456.     else {
  457.         moveTowardQueen();
  458.         }
  459.     }
  460. else {
  461.     lookForFood();
  462.     }
  463. }
  464.  
  465.  
  466. //////////////////////////////////////////////////////////////////////////
  467. //                                                                      //
  468. //                     CONSUMER class functions                         //
  469. //                                                                      //
  470. //////////////////////////////////////////////////////////////////////////
  471.  
  472. void Consumer::eatFood(int nUnits)
  473. {
  474.   int nX = getX();
  475.   int nY = getY();
  476.   nEnergy += MIN(nUnits, guFoodUnits[nX][nY]);
  477.   gulTotalFood -= MIN(nUnits, guFoodUnits[nX][nY]);
  478.   if (!(guFoodUnits[nX][nY] -= MIN(nUnits, guFoodUnits[nX][nY]))){
  479.      showFood(nX, nY, FALSE);
  480.   }
  481. }
  482.  
  483.  
  484.  
  485. //////////////////////////////////////////////////////////////////////////
  486. //                                                                      //
  487. //                           Support Functions                          //
  488. //                                                                      //
  489. //////////////////////////////////////////////////////////////////////////
  490.  
  491.  
  492. int distance(int nX1, int nY1, int nX2, int nY2)
  493. {
  494.   double sumSq = (double)((nX2-nX1)*(nX2-nX1) + (nY2-nY1)*(nY2-nY1));
  495.   if (sumSq > 0.0){
  496.     return((int) sqrt(sumSq));
  497.   }else{
  498.     return(0);
  499.   }
  500. }
  501.  
  502. void showFood(int nX, int nY, BOOLEAN bVisible)
  503. {
  504.   setfillstyle(SOLID_FILL, bVisible ? WHITE : BACKGROUND);
  505.   bar((nX + 0.5) * gfCellSizeX + 1,   nY * gfCellSizeY,
  506.       (nX + 1) * gfCellSizeX - 1, (nY + 1) * gfCellSizeY - 1);
  507. }
  508.  
  509. void showStatus(BOOLEAN bShowAll)
  510. {
  511.   char szMsg[100];
  512.  
  513.   setfillstyle(SOLID_FILL, BLACK);
  514.   if (bShowAll){
  515.     bar(0,getmaxy()-19,getmaxx(),getmaxy());
  516.     sprintf(szMsg, "Workers: %4u   Eggs: %4u   Food: %7lu    Cycle: %6lu   \
  517. Queen: %5d     <X-eXit>", guWorkers, guEggs, gulTotalFood, gulCycle++,
  518.             gQueen->nEnergy);
  519.     outtextxy(5,getmaxy()-16,szMsg);
  520.   }else{
  521.     sprintf(szMsg, "%4u", guWorkers);
  522.     bar(5+8*8, getmaxy()-19, 5+8*13, getmaxy());
  523.     outtextxy(5+8*8, getmaxy()-16, szMsg);
  524.  
  525.     sprintf(szMsg, "%4u", guEggs);
  526.     bar(5+8*20, getmaxy()-19, 5+8*24, getmaxy());
  527.     outtextxy(5+8*20, getmaxy()-16, szMsg);
  528.  
  529.     sprintf(szMsg, "%7lu", gulTotalFood);
  530.     bar(5+8*32, getmaxy()-19, 5+8*39, getmaxy());
  531.     outtextxy(5+8*32, getmaxy()-16, szMsg);
  532.  
  533.     sprintf(szMsg, "%6lu", gulCycle++);
  534.     bar(5+8*47, getmaxy()-19, 5+8*53, getmaxy());
  535.     outtextxy(5+8*47, getmaxy()-16, szMsg);
  536.  
  537.     sprintf(szMsg, "%5d", gQueen->nEnergy);
  538.     bar(5+8*61, getmaxy()-19, 5+8*67, getmaxy());
  539.     outtextxy(5+8*61, getmaxy()-16, szMsg);
  540.   }
  541. }
  542.  
  543. void runSimulation(void)
  544. {
  545.   int grMode, grDriver;      // Used to initialize graphics device
  546.   int nErrCode;              // Results of graphics operation
  547.   char ch;
  548.  
  549.  
  550.   // Clear out accumulators
  551.   headOfAntList = NULL;
  552.   gulTotalFood = 0L;
  553.   guWorkers = 0;
  554.   guEggs = 0;
  555.  
  556.   grDriver = DETECT;
  557.   initgraph(&grDriver, &grMode, "");
  558.  
  559.   nErrCode = graphresult();
  560.  
  561.   if (nErrCode != grOk){
  562.     printf("\n\nGraphics error: %s\n", grapherrormsg(nErrCode));
  563.   }else{
  564.      // Determine size of cells for 100 x 100 grid
  565.     gfCellSizeX = getmaxx() / 100.0;
  566.     gfCellSizeY = (getmaxy() - 20) / 100.0; // Allow room for status line
  567.  
  568.     // Draw line to seperate status area
  569.     line(0,getmaxy() - 20, getmaxx(), getmaxy() - 20);
  570.  
  571.     // Reset timer
  572.     gulCycle      = 0;      // Start timer at 0
  573.  
  574.  
  575.     // Create and show the queen ant
  576.      gQueen = new Queen( guQueensEnergy, 20, 2, 10, 10, guBirthRate );
  577.      gQueen->show();
  578.  
  579.     // Now the Worker ants and eggs will be created. The pointers to the
  580.     // newly created ants are not kept because they are automatically put
  581.     // in a doubly linked list by the constructor function. The head of the
  582.     // list is the global variable head.
  583.  
  584.     // Create worker ants
  585.     for (int i=0; i<guInitWorkers; i++){
  586.         Worker *temp = new Worker(FALSE, random(100), random(100));
  587.         temp->show();
  588.         guWorkers++;
  589.      }
  590.  
  591.     // Create the eggs
  592.     for (i=0; i<guInitEggs; i++){
  593.         Worker *temp = new Worker(TRUE, random(30), random(30));
  594.         temp->show();
  595.         guEggs++;
  596.      }
  597.  
  598.     // Create some food
  599.     for (i=0; i<100; i++){
  600.       for (int j=0; j<100; j++){
  601.         guFoodUnits[i][j] = 0;
  602.       }
  603.     }
  604.     for (i=0; i<guInitFood; i++){
  605.       int nY = random(100);
  606.       int nX = (nY>50) ? random(100) : (50 + random(50));
  607.       guFoodUnits[nX][nY] = random(1000) + 1000;
  608.       gulTotalFood += guFoodUnits[nX][nY];
  609.       showFood(nX, nY, TRUE);
  610.     }
  611.  
  612.     BOOLEAN bDone = FALSE;
  613.     showStatus(TRUE);
  614.  
  615.     while(!bDone){
  616.  
  617.       // Update status line
  618.       showStatus(FALSE);
  619.  
  620.       // Pause
  621.       delay(guPause);
  622.  
  623.       // Process the queen ant
  624.       if (!gQueen->bDead){
  625.         gQueen->doTheAntThing();
  626.       }
  627.  
  628.       // Process all ants that are in list
  629.         Worker *thisAnt = headOfAntList;
  630.         while(thisAnt != NULL){
  631.           Worker *nextWorker = thisAnt->next();
  632.           if (!thisAnt->bDead){
  633.              thisAnt->doTheAntThing();
  634.           }
  635.           if (thisAnt->bDead){
  636.              delete thisAnt;
  637.         }
  638.         thisAnt = nextWorker;
  639.       }
  640.  
  641.       // Are all ants dead?
  642.         if (gQueen->bDead && headOfAntList == NULL){
  643.         bDone = TRUE;
  644.         bar(5+8*67, getmaxy()-19, getmaxx(), getmaxy());
  645.         outtextxy(5+8*67,getmaxy()-16,"<Hit A Key>");
  646.         showStatus(FALSE);
  647.         sound(6000);
  648.         delay(1000);
  649.         nosound();
  650.         getch();
  651.       }
  652.  
  653.       // Has user hit X key?
  654.       if (kbhit()){
  655.         ch = toupper(getch());
  656.         bDone = (ch == 'X');
  657.         if (!bDone){
  658.           sound(1000);
  659.           delay(500);
  660.           nosound();
  661.         }
  662.       }
  663.     }
  664.  
  665.     delete gQueen;
  666.  
  667.     // Go back to original screen mode
  668.     closegraph();
  669.   }
  670. }
  671.  
  672. void resetDefaults(void)
  673. {
  674.   /////////////////////////////////////////////////////////////////
  675.   // These are the parameters to adjust to affect the simulation //
  676.   /////////////////////////////////////////////////////////////////
  677.   gnDropDistance   = 4;     // Drop food when distance 8 away from queen
  678.   gnTimeToHatch    = 20;    // Cycles to become a worker ant
  679.   guInitWorkers    = 2;     // Initial # of workers
  680.   guInitEggs       = 2;     // Initial # of eggs
  681.   guInitFood       = 400;   // Initial # of food cells
  682.   guPause          = 0;     // Milliseconds to pause each cycle
  683.   guWorkersPortion = 250;   // What a worker eats from each food cell found
  684.   guBirthRate      = 10;    // How many of 100 rounds does egg get laid
  685.   guMaxLifeSpan    = 200;   // Maximum age ant will live to
  686.   guMaxSpeed       = 2;     // Maximum speed that worker ant will move
  687.   guQueensEnergy   = 2000;  // Queens extra starting energy
  688. }
  689.  
  690. void displayValues(void)
  691. {
  692.   clrscr();
  693.   gotoxy(26,1);
  694.   printf("ANTHILL  by Mark Weaver & Alex Lane");
  695.   gotoxy(35,24);
  696.   printf("SELECT ONE");
  697.  
  698.   gotoxy(2,5);
  699.   printf("[W]               initial number of Worker ants");
  700.   gotoxy(2,6);
  701.   printf("[E]               initial number of Eggs");
  702.   gotoxy(2,7);
  703.   printf("[F]               initial number of cells containing Food");
  704.   gotoxy(2,8);
  705.   printf("[B]               Birth rate (chance in 100 of a birth each cycle)");
  706.   gotoxy(2,9);
  707.   printf("[L]               worker ant's maximum Life span");
  708.   gotoxy(2,10);
  709.   printf("[V]               worker ant's maximum Velocity (cells per cycle)");
  710.   gotoxy(2,11);
  711.   printf("[P]               Portion of food worker eats each time food is \
  712. found");
  713.   gotoxy(2,12);
  714.   printf("[H]               number of cycles it takes an egg to Hatch");
  715.   gotoxy(2,13);
  716.   printf("[Q]               Queens initial energy level");
  717.   gotoxy(2,14);
  718.   printf("[D]               Delay between each cycle (in milliseconds)");
  719.   gotoxy(2,16);
  720.   printf("[R]               Run simulation");
  721.   gotoxy(2,17);
  722.   printf("[X]               eXit to DOS");
  723.  
  724.   gotoxy(7,5);
  725.   printf("%5u", guInitWorkers);
  726.   gotoxy(7,6);
  727.   printf("%5u", guInitEggs);
  728.   gotoxy(7,7);
  729.   printf("%5u", guInitFood);
  730.   gotoxy(7,8);
  731.   printf("%5u", guBirthRate);
  732.   gotoxy(7,9);
  733.   printf("%5u", guMaxLifeSpan);
  734.   gotoxy(7,10);
  735.   printf("%5u", guMaxSpeed);
  736.   gotoxy(7,11);
  737.   printf("%5u", guWorkersPortion);
  738.   gotoxy(7,12);
  739.   printf("%5u", gnTimeToHatch);
  740.   gotoxy(7,13);
  741.   printf("%5u", guQueensEnergy);
  742.   gotoxy(7,14);
  743.   printf("%5u", guPause);
  744. }
  745.  
  746. unsigned getNumber(char *szPrompt, unsigned nMin, unsigned nMax, 
  747.                    unsigned nDefault)
  748. {
  749.   char szBuff[500];
  750.   int nRetval;
  751.   
  752.  
  753.   gotoxy(1,20);
  754.   clreol();
  755.   gotoxy(1,21);
  756.   clreol();
  757.   gotoxy(1,20);
  758.   printf("%s", szPrompt);
  759.   gotoxy(1,21);
  760.   printf("Range (%u to %u), <Return> for %u : ", nMin, nMax, nDefault);
  761.   gets(szBuff);
  762.   gotoxy(1,20);
  763.   clreol();
  764.   gotoxy(1,21);
  765.   clreol();
  766.  
  767.   // strip off leading spaces
  768.   char *ptr = szBuff;
  769.   while(*ptr == ' '){
  770.     ptr++;
  771.   }
  772.  
  773.   if (*ptr == '\0'){
  774.     return(nDefault);
  775.   }else{
  776.     sscanf(ptr, "%d", &nRetval);
  777.     return(nRetval);
  778.   }
  779.  
  780. }
  781.  
  782. char getChoice(void)
  783. {
  784.   char chRetval = ' ';
  785.  
  786.   while (strchr("WEFBLVPHQDRX", chRetval) == NULL){
  787.     chRetval = toupper(getch());
  788.   }
  789.   return(chRetval);
  790. }
  791.  
  792.  
  793. //////////////////////////////////////////////////////////////////////////
  794. //                                                                      //
  795. //                            Main Program                              // 
  796. //                                                                      //
  797. //////////////////////////////////////////////////////////////////////////
  798.  
  799. main()
  800. {
  801.  
  802.   // Initialize random number generator
  803.   randomize();
  804.  
  805.   resetDefaults();
  806.  
  807.   BOOLEAN bDone = FALSE;
  808.   while(!bDone){
  809.     displayValues();
  810.     char ch = getChoice();
  811.     switch(ch){
  812.       case 'X':
  813.         bDone = TRUE;
  814.         break;
  815.  
  816.       case 'H':   // hatch time
  817.         gnTimeToHatch = getNumber("Enter the number of cycles it takes an \
  818. egg to hatch",
  819.                                  5, 100, gnTimeToHatch);
  820.         break;
  821.  
  822.       case 'W':   // Initial workers
  823.         guInitWorkers = getNumber("Enter initial number of worker ants",
  824.                                    0, 100, guInitWorkers);
  825.         break;
  826.  
  827.       case 'E':   // Initial eggs
  828.         guInitEggs = getNumber("Enter initial number of worker eggs",
  829.                                    0, 100, guInitEggs);
  830.         break;
  831.  
  832.       case 'F':   // Initial number of food cells
  833.         guInitFood = getNumber("Enter number of cells initially containing \
  834. food",
  835.                            0, 1000, guInitFood);
  836.         break;
  837.  
  838.       case 'B':   // Birth rate
  839.         guBirthRate = getNumber("Enter percentage chance of a birth each cycle",
  840.                                             5, 50, guBirthRate);
  841.         break;
  842.  
  843.       case 'V':   // Max velocity
  844.         guMaxSpeed = getNumber("Enter workers maximum speed", 1, 20,
  845.                                   guMaxSpeed);
  846.         break;
  847.  
  848.       case 'Q':   // Queens start energy
  849.         guQueensEnergy = getNumber("Enter queens initial energy level",
  850.                                    1000, 100000, guQueensEnergy);
  851.         break;
  852.  
  853.       case 'L':   // Max worker lifespan
  854.         guMaxLifeSpan = getNumber("Enter maximum lifespan of worker ants",
  855.                                    50, 500, guMaxLifeSpan);
  856.         break;
  857.  
  858.       case 'P':   // Workers portion of food
  859.         guWorkersPortion = getNumber("Enter amount of food a worker eats \
  860. each time it finds some food",
  861.                                      0, 500, guWorkersPortion);
  862.         break;
  863.  
  864.       case 'D':   // Delay between each round
  865.         guPause = getNumber("Enter delay for each cycle in milliseconds",
  866.                             0, 10000, guPause);
  867.         break;
  868.  
  869.       case 'R':   // Run simulation
  870.         runSimulation();
  871.         break;
  872.     }
  873.   }
  874.   clrscr();
  875. }
  876.