home *** CD-ROM | disk | FTP | other *** search
- Program GameOfLife;{INPUT,OUTPUT}
- {
- Program to play the game of Life as developed by H.L. Conway
- at the University of Cambridge and introduced in the
- "Mathematical Games" section of the October 1970 "Scientific
- American" magazine.
-
- SUMMARY:
- Life is played on a grid of squares. A given square is either
- occupied or empty. The program user specifies which squares are
- occupied initially. The game of Life program produces new generations
- of the matrix by applying life's laws for birth, survival, and death
- to the present generation. These laws are:
-
- BIRTH:
- An unoccupied square becomes occupied if in the preceding generation
- exactly three of the eight neighboring squares were occupied
- (squares that touch horizontally, vertically or diagonally are said
- to be neighboring squares).
-
- SURVIVAL:
- An occupied square remains occupied if in the preceding generation
- two or three neighboring squares were occupied.
-
- DEATH:
- An occupied square becomes unoccupied if in the preceding generation
- fewer than two or more than three neighboring squares were occupied.
-
-
- MODIFICATION RECORD:
- FEB 18, 1981 - Modified for Paascal/Z by Raymond E. Penley.
- - Any external routines may be obtained from the
- Pascal/Z Users' Group.
- FEB 21, 1981 - Added escape from data entry portion.
- }
-
- CONST
-
- {The following cursor controls work with a terminal
- such as the Lear Siegler ADM3A, SOROC 120, Televideo.}
- lf=10; (* cursor down = ctrl/J *)
- uparrow=11; (* cursor up = ctrl/K *)
- bkspce=8; (* cursor back = ctrl/H *)
- ff=12; (* cursor fwd = ctrl/L *)
- space=32; (* ASCII space *)
- sub=26; (* ASCII clear screen code *)
- esc = 27; (* ASCII escape code *)
- maxboardsize = 22;
- widthmaxboard=77;
-
- TYPE state = (dead, stable, growing);
- neighbor = set of 0..8;
- boards = packed array [1..widthmaxboard,1..maxboardsize] of char;
-
- VAR survivepopulation:neighbor;
- boardstate :state;
- newboard,
- oldboard :boards;
- j :1..maxboardsize;
- i :1..widthmaxboard;
- firsttime :boolean;
- numberofneighbors:0..8;
- alivecount,
- boardsize,
- changecount,
- generation,
- maxgeneration,
- boardwidth :integer;
- left,right,
- up,down,
- horizoffset,
- vertoffset :-1..+1;
-
- {$M-}{ integer mult & divd error checking OFF }
- {$F-}{ floating point error checking OFF }
- {$R-}{ range checking OFF }
- {$S-}{ stack checking OFF }
-
- PROCEDURE GOTOXY(X,Y:INTEGER);
- BEGIN
- IF X<0 THEN X := 0;
- IF X>79 THEN X := 79;
- IF Y<0 THEN Y := 0;
- IF Y>23 THEN Y := 23;
- WRITE( CHR(27),'=',CHR(Y+32),CHR(X+32));
- END;
-
- PROCEDURE KEYIN(VAR C:CHAR); EXTERNAL;
-
- procedure clearscreen;
- begin
- write(chr(sub));
- end;
-
-
- procedure getanimals(VAR hit: boolean);
- var ch,
- escape,
- up,
- right,
- rght,
- left,
- down :char;
- begin
- escape := chr(esc);
- up := chr(uparrow);
- right := chr(space);
- rght := chr(ff);
- down := chr(lf);
- left := chr(bkspce);
- hit := false;
- repeat
- KEYIN(ch);
- (* read(keyboard,ch); *)
- if ( ch=escape ) then
- begin
- ch := 'D';
- hit := true;
- end
- else if ( ch=down ) then
- begin
- if ( (j+1)>boardsize ) then j := boardsize else j := j+1;
- gotoxy(i,j);
- end
- else if ( ch=up ) then
- begin
- if ( (j-1)<1 ) then j := 1 else j := j-1;
- gotoxy(i,j);
- end
- else if (ch=right) or (ch=rght) then
- begin
- if ( (i+1)>boardwidth ) then
- begin
- i := 1;
- if ( (j+1)>boardsize ) then j := boardsize else j := j+1;
- end
- else i := i+1;
- gotoxy(i,j);
- end
- else if ( ch=left ) then
- begin
- if ( (i-1)<1 ) then
- begin
- i := boardwidth;
- if ( (j-1)<1 ) then j := 1 else j := j-1;
- end
- else i := i-1;
- gotoxy(i,j);
- end
- else if ( ch='*' ) then
- begin
- write(ch);
- oldboard[i,j] := '*';
- alivecount := alivecount+1;
- if ( (i+1)>widthmaxboard ) then
- begin
- i := 1;
- if ( (j+1)>maxboardsize ) then
- j := maxboardsize
- else
- j := j+1;
- gotoxy(i,j);
- end
- else i := i+1;
- end;
- until (ch='d') or (ch='D');
- end; (* get animals *)
-
-
- Procedure PrintHeader;
- begin
- writeln('Generation #',generation:3, ' Population =',alivecount:3);
- end;{ of PrintHeader }
-
-
- procedure initialize;
- { Here is the input section. It initializes all necessary parameters
- and creates the initial board}
- label 1;
- const s1 = 'Please enter the ';
- var hit : boolean;
- begin
- 1:{ here if hit }
- generation := 0;
- If firsttime then
- clearscreen
- else
- gotoxy(0,0);
- writeln(s1, 'maximum number of generations');
- write (' you would like for this game: ->');
- readln(maxgeneration);
- write (s1, 'board width for this game: ->');
- readln(boardwidth);
- write (s1, 'board heighth for this game: ->');
- readln(boardsize);
- if ( boardsize>maxboardsize ) then
- boardsize := maxboardsize;
- if ( boardwidth>widthmaxboard ) then
- boardwidth := widthmaxboard;
- clearscreen;
- writeln;
- for j := 1 to boardsize do
- begin
- write(' ');
- for i := 1 to boardwidth do
- begin
- oldboard[i,j] := ' ';
- write('-');
- end;
- if ( j<boardsize ) then writeln;
- end;
- gotoxy(0,0);
- writeln('"*"=organism, cursor control keys move cursor,',
- ' D for done, ESC start over');
- alivecount := 0;
- i := 1;
- j := 1;
- gotoxy(i,j);
- getanimals(hit);
- clearscreen;
- If hit then goto 1;
- printheader;
- for j := 1 to boardsize do
- begin
- for i := 1 to boardwidth do
- write (oldboard[i,j]);
- if ( j<boardsize ) then writeln;
- end;
- end {initialize};
-
-
- procedure processboard;
- { The actual board processing begins here}
- begin
- {$C-}{ control-c cheking OFF }
- alivecount := 0;
- changecount := 0;
- for i := 1 to boardwidth do
- begin
- for j := 1 to boardsize do
- begin
- {first we must compute the number of neighbors for
- a cell at coordinate i,j We must make sure that the
- cell is not on an edge}
- if ( i>1 )
- then left := -1
- else left := 0;
- if ( i<boardwidth )
- then right := +1
- else right := 0;
- if ( j>1 )
- then up := -1
- else up := 0;
- if ( j<boardsize )
- then down := +1
- else down := 0;
- numberofneighbors := 0;
- for horizoffset := left to right do
- begin
- for vertoffset := up to down do
- if (oldboard[i+horizoffset,j+vertoffset] ='*') and
- ((horizoffset<>0) or (vertoffset<>0))
- then numberofneighbors := numberofneighbors+1;
- end;
- {The last test prevents counting a cell as a
- neighbor of itself.
- Now see which cells should be alive in the
- next generation.}
- newboard[i,j] := ' ';
- if ((oldboard[i,j]=' ') and (numberofneighbors = 3))
- or ((oldboard[i,j] = '*')
- and (numberofneighbors in survivepopulation))
- then begin
- newboard[i,j] := '*';
- alivecount := alivecount +1
- end;
- end {j loop};
- end{i loop}; {of the processing of each individual cell}
- end; {of processboard}
-
- {$C+}{ Control-C checking ON }
-
- procedure printgeneration;
- { We have now completed a new generation. Print it out
- and copy it back into the oldboard to get ready for the
- next cycle}
- begin
- generation := generation +1;
- clearscreen;
- PrintHeader;
- for j := 1 to boardsize do
- begin
- for i := 1 to boardwidth do
- begin
- write (newboard[i,j]);
- {see if anything has changed during this generation}
- if ( newboard[i,j]<>oldboard[i,j] ) then
- begin
- changecount := changecount+1;
- oldboard[i,j] := newboard[i,j]
- end
- end;
- if ( j<boardsize ) then writeln;
- end;
- {set a flag indicating the state of the board at the end of this
- generation}
- if ( alivecount=0 ) then
- boardstate := dead
- else
- if ( changecount=0 ) then
- boardstate := stable
- else boardstate := growing
- end {processboard};
-
- procedure printresults;
- { print why we stopped }
- begin
- case boardstate of
- dead :writeln('Colony died');
- stable :writeln('Colony is stable');
- growing :writeln('Maximum generation number has been exceeded')
- end {of case statement}
- end {printresults};
-
-
- begin{ MAIN PROGRAM }
- firsttime := true;
- While true do
- begin
- survivepopulation := [2,3];
- initialize;
- firsttime := false;
- repeat
- processboard;
- printgeneration;
- until (boardstate = dead)
- or (boardstate = stable)
- or (generation >= maxgeneration);
- printresults;
- end;
- end.{Game of Life}
-