{PROGRAM AUTHOR: Mark Aldon Weiss PROGRAM DONATED TO PUBLIC DOMAIN} CONST MaxNumRows = 105; MaxNumCols = 92; MaxLengthRowString = 125; { MaxLengthRowString is greater than MaxNumCols to allow for spillover on } { input so that user may use repeat key to, say, type alot of noncreatures } { without worrying about typing exactly enough to fill the row. } TYPE Colony = Array[1..MaxNumRows,1..MaxNumCols] of Char; VAR again: Boolean; GenCount,NumOcc1st,CreatureCount,HowManyMore,i: Integer; creature,noncreature,how1st,HowRand,option,ch : Char; NumRows: 0..MaxNumRows; NumCols: 0..MaxNumCols; SpaceRequired: Integer; frac1st: Real; field: 1..2; GRID: Colony; PrintFormat: 1..3; RowString: String[MaxLengthRowString]; PROCEDURE HELP; Begin {HELP} Writeln; Writeln(' N#--type an N and then any positive integer; the next'); Writeln(' # generations are computed and displayed.'); Writeln(' S#--type an S and then any positive integer; the next'); Writeln(' # generations are computed and the last displayed.'); Writeln(' Q#--type a Q and any integer in order to QUIT the current'); Writeln(' grid. You will then be able to start a new one.') End; {HELP} PROCEDURE GetOptions; Begin {GetOptions} Writeln; Writeln(' You may have a maximum of ',MaxNumRows,' rows in your grid.'); Writeln(' How many rows do you want for your grid (remember,'); Write(' no creatures are allowed in the first or last row)? '); Readln(NumRows); Writeln; Writeln(' You may have a maximum of ',MaxNumCols,' columns in your grid.'); Writeln(' How many columns do you want for your grid (remember,'); Write(' no creatures are allowed in the first or last column)? '); Readln(NumCols); Writeln; Write(' Type the character you want to represent a creature -------> '); Readln(creature); Write(' Type the character you want to represent a NONcreature ----> '); Readln(noncreature); Writeln; Writeln(' While the terminal display will have no spaces between the grid'); Writeln(' characters, you may have a blank space between the grid characters'); Write(' on the printout. Do you want a blank separating characters? '); Readln(ch); Writeln; IF ch IN ['y','Y'] THEN Field := 2 ELSE Field := 1; SpaceRequired := NumCols * Field + 25; IF SpaceRequired <= 66 THEN PrintFormat := 1; IF (SpaceRequired > 66) AND (SpaceRequired <= 80) THEN PrintFormat := 2; IF (SpaceRequired > 80) AND (SpaceRequired <= 132) THEN PrintFormat := 3; IF SpaceRequired > 132 THEN Begin Field := 1; PrintFormat := 3; SpaceRequired := NumCols + 25; If SpaceRequired > 132 Then Begin Writeln(#7,' WARNING: Your grid will have too many columns to fit on'); Writeln(' one line of the printout. You will therefore get'); Writeln(' wrap-arounds, but your grid will still print.'); Writeln End End; REPEAT Writeln(' Do you want a random first generation (type r) or do you want to'); Write(' make your own first generation (type s)? '); Readln(how1st) UNTIL how1st IN ['r','R','s','S']; IF how1st IN ['r','R'] THEN Begin REPEAT Writeln(' Do you want BOTH the number and the placement of creatures to'); Writeln(' be random (type b) or only the placement of creatures to be'); Write(' random (type p)? '); Readln(HowRand) UNTIL HowRand IN ['b','B','p','P']; If HowRand In ['p','P'] Then Begin Writeln(' What fraction (between 0 & 1) of your first generation grid'); Write(' do you want to be occupied (i.e., have creatures)? '); Readln(frac1st); NumOcc1st := ROUND( frac1st * (NumRows-2) * (NumCols-2) ) End End End; {GetOptions} PROCEDURE PrintGrid; Var r,c,midpt: Integer; Begin {PrintGrid} IF GenCount = 1 THEN CreatureCount := NumOcc1st; midpt := NumRows DIV 2; FOR r := 1 to (midpt-1) DO Begin Write(lst,' '); For c := 1 to NumCols Do Write(lst,GRID[r,c]:Field); Writeln(lst) End; Write(lst,' '); For c := 1 to NumCols Do Write(lst,GRID[midpt,c]:Field); Writeln(lst,' GENERATION ',GenCount); Write(lst,' '); For c := 1 to NumCols Do Write(lst,GRID[midpt+1,c]:Field); Writeln(lst,' Frac. Occ. = ',CreatureCount/( (NumRows-2)*(NumCols-2) ):8:6); FOR r := (midpt+2) to NumRows DO Begin Write(lst,' '); For c := 1 to NumCols Do Write(lst,GRID[r,c]:Field); Writeln(lst) End End; {PrintGrid} PROCEDURE WriteGridToTerminal; Var r,c,midpt: Integer; Begin {WriteGridToTerminal} IF GenCount = 1 THEN CreatureCount := NumOcc1st; midpt := NumRows DIV 2; FOR r := 1 to (midpt-1) DO Begin Write(' '); For c := 1 to NumCols Do Write(GRID[r,c]); Writeln End; Write(' '); For c := 1 to NumCols Do Write(GRID[midpt,c]); Writeln(' GENERATION ',GenCount); Write(' '); For c := 1 to NumCols Do Write(GRID[midpt+1,c]); Writeln(' Frac. Occ. = ',CreatureCount/( (NumRows-2)*(NumCols-2) ):8:6); FOR r := (midpt+2) to NumRows DO Begin Write(' '); For c := 1 to NumCols Do Write(GRID[r,c]); Writeln End End; {WriteGridToTerminal} PROCEDURE FirstGen; Var c,r,midpt: Integer; ch,correction: char; Begin {FirstGen} FOR r := 1 to NumRows DO FOR c := 1 to NumCols DO GRID[r,c] := noncreature; IF how1st IN ['s','S'] THEN Begin NumOcc1st := 0; Writeln(' ':10,'C O L U M N'); Write(' ':10); FOR c := 2 to (NumCols-1) DO Write( (10+c) MOD 10 ); Writeln; FOR r := 2 to (NumRows-1) DO Begin Write(' row',r:3,': '); Readln(RowString); For c := 2 to (NumCols-1) Do Begin GRID[r,c] := RowString[c-1]; IF GRID[r,c] = creature THEN NumOcc1st := NumOcc1st + 1 End End; midpt := NumRows DIV 2; Writeln; Writeln; Writeln(' This is your first generation grid as it now stands:'); Writeln; Writeln(' ':10,'C O L U M N'); Write(' ':10); FOR c := 2 to (NumCols-1) DO Write( (10+c) MOD 10 ); Writeln; FOR r := 2 to (midpt-1) DO Begin Writeln; Write(' row',r:3,': '); For c := 2 to (NumCols-1) Do Write(GRID[r,c]) End; Writeln; Write(' row',midpt:3,': '); FOR c := 2 to (NumCols-1) Do Write(GRID[midpt,c]); Writeln(' GENERATION 1'); Write(' row',(midpt+1):3,': '); FOR c := 2 to (NumCols-1) Do Write(GRID[midpt+1,c]); Write(' Fraction Nonborder Occupied = '); Write(NumOcc1st/( (NumRows-2)*(NumCols-2) ):8:6); FOR r := (midpt+2) to (NumRows-1) DO Begin Writeln; Write(' row',r:3,': '); For c := 2 to (NumCols-1) Do Write(GRID[r,c]) End; Writeln; Writeln; Write(' Do you want to make any corrections? '); Readln(correction); IF correction IN ['y','Y'] THEN WHILE correction IN ['y','Y'] DO Begin Write(' Row of mistake -----> '); Readln(r); Write(' Column of mistake --> '); Readln(c); Write(' Desired creature or non-creature character'); Write(' for this location ----> '); Readln(ch); GRID[r,c] := ch; Write(' Any more corrections? '); Readln(correction) End End; IF how1st IN ['r','R'] THEN Begin IF HowRand IN ['b','B'] THEN NumOcc1st := ROUND( RANDOM*(NumRows-2)*(NumCols-2) ); CreatureCount := 0; WHILE CreatureCount < NumOcc1st DO {Place a creature randomly} Begin CreatureCount := CreatureCount + 1; REPEAT r := ROUND( ((NumRows-1)-2) * RANDOM + 2); c := ROUND( ((NumCols-1)-2) * RANDOM + 2) UNTIL GRID[r,c] <> creature; GRID[r,c] := creature; { The REPEAT loop is so that you don't put a creature where there } { already was one since this would not increase the number of ran- } { domly placed creatures. Once a random grid postion is found that } { is not already occupied, a creature is placed in that position. } { The assignments to r and c in the REPEAT loop may be confusing. } { Just keep in mind that for, say, an 11-row grid you want a random } { number from 2 to 10. The assignment accomplishes this. } End; WriteGridToTerminal End; PrintGrid End; {FirstGen} PROCEDURE NextGen; Var r,c,NumNeighbors,occupations: Integer; TempMat: Colony; MatNeighbors: Array[1..MaxNumRows,1..MaxNumCols] of Integer; Begin {NextGen} FOR r := 1 to NumRows DO FOR c := 1 to NumCols DO TempMat[r,c] := noncreature; FOR r := 2 to (NumRows-1) DO FOR c := 2 to (NumCols-1) DO Begin NumNeighbors := 0; IF GRID[r+1,c+1] = creature THEN NumNeighbors := NumNeighbors + 1; IF GRID[r+1,c ] = creature THEN NumNeighbors := NumNeighbors + 1; IF GRID[r+1,c-1] = creature THEN NumNeighbors := NumNeighbors + 1; IF GRID[r ,c+1] = creature THEN NumNeighbors := NumNeighbors + 1; IF GRID[r ,c-1] = creature THEN NumNeighbors := NumNeighbors + 1; IF GRID[r-1,c+1] = creature THEN NumNeighbors := NumNeighbors + 1; IF GRID[r-1,c ] = creature THEN NumNeighbors := NumNeighbors + 1; IF GRID[r-1,c-1] = creature THEN NumNeighbors := NumNeighbors + 1; MatNeighbors[r,c] := NumNeighbors End; FOR r := 2 to (NumRows-1) DO FOR c := 2 to (NumCols-1) DO IF (MatNeighbors[r,c]<>2) AND (MatNeighbors[r,c]<>3) THEN TempMat[r,c] := noncreature ELSE TempMat[r,c] := GRID[r,c]; FOR r := 2 to (NumRows-1) DO FOR c := 2 to (NumCols-1) DO IF GRID[r,c] = noncreature THEN Begin occupations := 0; IF GRID[r+1,c+1] = creature THEN occupations := occupations + 1; IF GRID[r+1,c ] = creature THEN occupations := occupations + 1; IF GRID[r+1,c-1] = creature THEN occupations := occupations + 1; IF GRID[r ,c+1] = creature THEN occupations := occupations + 1; IF GRID[r ,c-1] = creature THEN occupations := occupations + 1; IF GRID[r-1,c+1] = creature THEN occupations := occupations + 1; IF GRID[r-1,c ] = creature THEN occupations := occupations + 1; IF GRID[r-1,c-1] = creature THEN occupations := occupations + 1; IF occupations = 3 THEN TempMat[r,c] := creature End; CreatureCount := 0; FOR r := 1 to NumRows DO FOR c := 1 to NumCols DO Begin GRID[r,c] := TempMat[r,c]; IF GRID[r,c] = creature THEN CreatureCount := CreatureCount + 1 End End; {NextGen} BEGIN { M A I N P R O G R A M } Writeln; Writeln; Writeln(' This program is the game of life. It has a great many extra '); Writeln(' features that will become apparent as the program is executed.'); Writeln(' The rules of life are that a creature will survive in the next'); Writeln(' generation only if there are exactly 2 or 3 neighboring creatures.'); Writeln(' A creature is born in the next generation if there are exactly 3'); Writeln(' creatures surrounding the non-creature grid space. NO CREATURES'); Writeln(' ARE PERMITTED IN THE BORDER OF THE GRID.'); Writeln; Writeln(' Turn the printer off. Turn the knob on the printer to set a page'); Writeln(' so it''s at the top of a sheet. Turn the printer ON.'); Writeln; REPEAT Write(#7,' Did you follow the instructions? '); Readln(ch) UNTIL ch IN ['y','Y']; Writeln(lst,#27'C'#0#11#27'N'#3); { codes to Epson printer for length of page = 11 in., skip over perf. 3 lines } again := TRUE; WHILE again DO Begin GenCount := 1; GetOptions; CASE PrintFormat OF 1: Writeln(lst,#27'W'#1#15#27'2'#27'U'#0); 2: Writeln(lst,#27'W'#0#18#27'U'#0#27'2'); 3: IF Field = 1 THEN Writeln(lst,#15#27'U'#1#27'0'#27'W'#0) ELSE Writeln(lst,#15#27'U'#0#27'2'#27'W'#0) End; {of CASE} {These are various codes to the printer to turn on/off double width} {or compressed print or unidirectional printing or 8 lines per inch, etc.} Writeln; FirstGen; Writeln; REPEAT Writeln; Write(' Type N# S# Q# or H4(for help) ----> '); Readln(option,HowManyMore); IF option IN ['n','N'] THEN FOR i := 1 to HowManyMore DO Begin Writeln; Writeln(lst); GenCount := GenCount + 1; NextGen; WriteGridToTerminal; PrintGrid End; IF option IN ['s','S'] THEN Begin FOR i := 1 to HowManyMore DO Begin GenCount := GenCount + 1; NextGen End; Writeln; Writeln(lst); WriteGridToTerminal; PrintGrid End; IF option IN ['q','Q'] THEN Begin Writeln; Writeln End; IF option IN ['h','H'] THEN HELP UNTIL option IN ['q','Q']; Writeln; Write(' Do you want to start over with a new first generation? '); Readln(ch); IF ch IN ['y','Y'] THEN again := TRUE ELSE again := FAlSE End END. { M A I N P R O G R A M } .