home *** CD-ROM | disk | FTP | other *** search
/ C!T ROM 2 / ctrom_ii_b.zip / ctrom_ii_b / PROGRAM / PASCAL / 30TURUTL / LIFE.PAS < prev    next >
Pascal/Delphi Source File  |  1985-02-16  |  8KB  |  283 lines

  1. Program LIFE;
  2. {$I-}
  3.  
  4. {
  5. ('** "Life", APPLE PASCAL GAMES, Hergert & Kalash, pp. 223 et seq.,');
  6. ('           Sybex, 1981.  Modified for TURBO Pascal 1/10/84 d.c.o.');
  7. }
  8.  
  9. const height = 24;
  10.       width  = 80;
  11.       minbound = -1;
  12.       lively = '+';
  13.       deadly = ' ';
  14.  
  15. type  state = (alive, dead);
  16.       cell = record
  17.                lookslikeitis: state;
  18.                nearby: integer;
  19.              end;
  20.       edges = record left, right, top, bottom: integer end;
  21.       screenline = string[80];
  22.  
  23. var   board: array[minbound..height] of array[minbound..width] of cell;
  24.       population, births, deaths: integer;
  25.       ch: char;
  26.       quit: boolean;
  27.       pause: integer;
  28.       edge: edges;
  29.  
  30. procedure kill_typeahead;
  31. begin
  32.   if keypressed then read(kbd,ch)
  33. end;  {kill_typeahead}
  34.  
  35. function yes(s:screenline):boolean;
  36. var ch:char;
  37. begin
  38.   write(s,' Y/N ');
  39.   kill_typeahead;
  40.   repeat
  41.     read(kbd,ch)
  42.   until ch in ['y','Y','n','N'];
  43.   yes:=ch in ['y','Y']
  44. end;  {yes}
  45.  
  46. function min(a,b: integer):integer;
  47. begin
  48.   if a<=b then min:=a else min:=b
  49. end;  {min}
  50.  
  51. function max(a,b: integer):integer;
  52. begin
  53.   if a>=b then max:=a else max:=b
  54. end;  {max}
  55.  
  56. procedure resetedges;
  57. begin
  58.   edge.top:=height-1;
  59.   edge.right:=minbound+1;
  60.   edge.left:=width-1;
  61.   edge.bottom:=minbound+1
  62. end;  {resetedges}
  63.  
  64. procedure instructions;
  65. var ch: char;
  66.  
  67.   procedure lecture_on_life;
  68.   begin
  69.     clrscr;
  70.     write('LIFE simulates the growth of a colony of animalcules in a "');
  71.     writeln(width-1:1,' by ',height-1:1,' World".');
  72.     writeln;
  73.     writeln('Whether a cell is born, lives or dies depends on the number of living');
  74.     writeln('animalcules near by.  If a cell is empty and has exactly 3 neighbors, it');
  75.     writeln('will be born in the next generation.  If it is alive and has 2 or 3');
  76.     writeln('neighbors, it will stay alive.  Otherwise, it either dies of loneliness');
  77.     writeln('or suffocates from overcrowding.');
  78.     writeln;
  79.     writeln('You type in the starting pattern, giving the XY location of each cell.');
  80.     writeln('When you enter X Y be sure to leave a SPACE between the numbers.  When');
  81.     writeln('you are through seeding a colony, enter a -1 to begin the generations.');
  82.     writeln('The < key speeds things up a bit, the > key slows things down.  In the');
  83.     writeln('good old days at M.I.T., this game was played with pencil & graph paper.');
  84.     gotoxy(1,22);
  85.     write('(* any key continues *) ');
  86.     kill_typeahead;
  87.     read(kbd,ch)
  88.   end;  {lecture_on_life}
  89.  
  90. begin
  91.   writeln; writeln; writeln; writeln; writeln;
  92.   if yes('Would you like instructions for Life?') then
  93.      lecture_on_life;
  94.   clrscr
  95. end;  {instructions}
  96.  
  97. procedure title;
  98. begin
  99.   clrscr;
  100.   writeln('** "Life", APPLE PASCAL GAMES, Hergert & Kalash, pp. 223 et seq.,');
  101.   writeln('           Sybex, 1981.  Modified for TURBO Pascal 1/10/84 d.c.o.');
  102. end;  {title}
  103.  
  104. procedure initialize;
  105. var down, across: integer;
  106. begin
  107.   for down:=minbound to height do
  108.       for across:=minbound to width do
  109.           begin
  110.             board[down,across].lookslikeitis := dead;
  111.             board[down,across].nearby := 0
  112.           end;
  113.   resetedges
  114. end;  {initialize}
  115.  
  116. procedure limits(x,y: integer);
  117. begin
  118.   with edge do
  119.     begin
  120.       left:=min(left,x);
  121.       right:=max(right,x);
  122.       top:=min(top,y);
  123.       bottom:=max(bottom,y)
  124.     end
  125. end; {limits}
  126.  
  127. procedure clearnearby;
  128. var down, across: integer;
  129. begin
  130.   for down:=edge.top-1 to edge.bottom+1 do
  131.       for across:=edge.left-1 to edge.right+1 do
  132.           board[down,across].nearby := 0
  133. end;  {clearnearby}
  134.  
  135. procedure countneighbors;
  136. var down, across, deltadown, deltacross: integer;
  137. begin
  138.   clearnearby;
  139.   for down:=edge.top-1 to edge.bottom+1 do
  140.       for across:=edge.left-1 to edge.right+1 do
  141.           if board[down][across].lookslikeitis = alive then
  142.              for deltadown:=-1 to 1 do
  143.                  for deltacross:=-1 to 1 do
  144.  
  145.            board[down+deltadown][across+deltacross].nearby :=
  146.            board[down+deltadown][across+deltacross].nearby + 1
  147. end;  {countneighbors}
  148.  
  149. procedure update;
  150. var down, across: integer;
  151.     localedge: edges;
  152.  
  153. begin
  154.   births:=0;
  155.   deaths:=0;
  156.   localedge:=edge;
  157.   resetedges;
  158.  
  159.   for down:=max(minbound+1,localedge.top-1) to
  160.             min(height-1,localedge.bottom+1) do
  161.   for across:=max(minbound+1,localedge.left-1) to
  162.               min(width-1,localedge.right+1) do
  163.       with board[down][across] do
  164.         case lookslikeitis of
  165.           dead:
  166.             if nearby=3 then
  167.               begin
  168.                 lookslikeitis:=alive;
  169.                 gotoxy(across+1,down+1);
  170.                 write(lively);
  171.                 limits(across,down);
  172.                 births:=births+1
  173.               end;
  174.           alive:
  175.             if (nearby=3) or (nearby=4) then limits(across,down)
  176.             else
  177.               begin
  178.                 lookslikeitis:=dead;
  179.                 gotoxy(across+1,down+1);
  180.                 write(deadly);
  181.                 deaths:=deaths+1
  182.               end
  183.           end; {case}
  184.   population:=population+births-deaths;
  185.   gotoxy(1,1)
  186. end;  {update}
  187.  
  188. procedure getpositions;
  189. var down,across: integer;
  190.     finished: boolean;
  191.  
  192.   procedure reprinttopline;
  193.   var across:integer;
  194.   begin
  195.     gotoxy(1,1);
  196.     for across:=minbound+1 to width-1 do
  197.       if board[minbound+1][across].lookslikeitis = dead
  198.         then write(deadly)
  199.         else write(lively)
  200.   end;  {reprinttopline}
  201.  
  202. begin
  203.   finished:=false;
  204.   population:=0;
  205.   gotoxy(1,1);
  206.   write('Position of Cell #',population+1:1,' is: ');
  207.   while not finished do
  208.     begin
  209.       readln(across,down);  {works if you leave a space between x y}
  210.       if ioresult<>0 then
  211.         begin
  212.           clrscr;
  213.           writeln('*** INPUT ERROR ***');
  214.           write('A Demonstration of LIFE with 9 cells from 32 11 to 41 11:');
  215.           for across:=31 to 31+9 do begin
  216.               limits(across,10);
  217.               board[10][across].lookslikeitis:=alive;
  218.               gotoxy(across+1,11); write(lively)
  219.               end;
  220.           for across:=1 to 128 do delay(64);
  221.           finished:=true;
  222.           population:=9
  223.         end
  224.       else
  225.         begin
  226.       if (down<=minbound) or
  227.          (down>=height) or
  228.          (across<=minbound) or
  229.          (across>=width) then
  230.          finished:=true
  231.       else with board[down][across] do
  232.         begin
  233.           limits(across,down);
  234.           gotoxy(across+1,down+1);
  235.           if lookslikeitis = alive then
  236.             begin
  237.               write(deadly);
  238.               lookslikeitis:=dead;
  239.               population:=population-1
  240.             end
  241.           else
  242.             begin
  243.               write(lively);
  244.               lookslikeitis:=alive;
  245.               population:=population+1
  246.             end;
  247.           gotoxy(1,1);
  248.           write('Position of Cell #',population+1:1,' is: ');
  249.         end
  250.       end
  251.     end;
  252.   reprinttopline
  253. end;  {getpositions}
  254.  
  255. BEGIN  {Main}
  256.   repeat
  257.     initialize;
  258.     title;
  259.     instructions;
  260.     getpositions;
  261.     pause:=32;
  262.     quit:=false;
  263.     while not quit do
  264.       begin
  265.         countneighbors;
  266.         update;
  267.         for ch:='A' to 'Z' do delay(pause);
  268.         quit := (population=0) or ((births=0) and (deaths=0));
  269.         if keypressed then
  270.           begin
  271.             read(kbd,ch);
  272.             if ch in ['>','.'] then pause:=min(pause+16,255)
  273.             else if ch in ['<',','] then pause:=max(pause-16,0)
  274.             else quit:=true
  275.           end
  276.       end;
  277.     gotoxy(1,22);
  278.     if population=0
  279.       then writeln('This colony has died out.')
  280.       else writeln
  281.   until not yes('Would you like to run LIFE again?')
  282. END.
  283.