--***************************************************************************** -- -- The Game of Life -- -- AUTHOR: Robert Walsh -- COAUTHOR: Mark Trisko -- CLASS: CSCI 375 -- DATE: September 14, 1995 -- -- Created as a small group project | CSCI 375 - St. Cloud State University -- --**************************************************************************** with TEXT_IO; package INTEGER_IO is new TEXT_IO.INTEGER_IO(INTEGER); with TEXT_IO; package FLOAT_IO is new TEXT_IO.FLOAT_IO(FLOAT); with TEXT_IO, INTEGER_IO, FLOAT_IO; use TEXT_IO, INTEGER_IO, FLOAT_IO; with sparse; use sparse; with Random; use Random; procedure GameLife is type IsOkay is (YES, NO); GSize, Generation, TermGen : INTEGER; Grid, Grid2 : S_MAT; GDense : FLOAT; EndProg : IsOkay := NO; procedure GetGridSize(n : out INTEGER) is -- WHAT: This prodedure prompts the user for an input between 1 and -- 10000 and prompts for re-entry when bounds are ignored. In -- the case of input error (ie: none numerical), the procedure -- return 40 as defualt. -- IN: None -- OUT: Value inputed by user or on error, 40. Okay : BOOLEAN := FALSE; -- Flags when an OK input is received Temp : INTEGER; -- temporarely holds grid size so comparisions can be -- performed on it. begin while not Okay loop PUT("Please enter the size of the grid [1-10000]: "); GET(Temp); NEW_LINE; if Temp>0 and then Temp<10001 then Okay := TRUE; -- negative numbers and 0 are definately not allowed. A grid --size of 10000 should suffice as an upper bound. else PUT_LINE("Size not allowed. Try Again."); end if; end loop; n := Temp; -- Assign output value as grid size input exception when others => PUT_LINE("* Input error * Grid size of 40 will be used"); Temp := 40; -- In case of input error, grid size defualts to 40 end GetGridSize; procedure InitGrid(Size : in INTEGER; IGGrid : in out S_MAT) is --WHAT: This procedure initializes a matrix by assigning 10% or less of -- its cells to bolean value LIFE. The procedure assures that at -- least one cell is set to LIFE. The procedure operates by -- selecting a random (X, Y) coordinate and assigning it LIFE. --IN: Size of the grid [INTEGER] with respect to the total number of -- columns or rows (they're equal cuz grid is a square). The -- actual grid (empty) is passed also to allow operations on it. --OUT: Grid with random # of cells equal to LIFE. X, Y : INTEGER; -- Arbitrary X, Y coordinates begin for L in 1..(RangeRand(Size*Size)) loop X := RangeRand(Size); -- Get a random X coordinate Y := RangeRand(Size); -- Get a random Y coordinate ASSIGN(IGGrid, X, Y, 1); -- Set (X,Y) to value 1 end loop; end InitGrid; function Density(DGrid : S_MAT; Size : in INTEGER) return FLOAT is --WHAT: This function returns the density of the grid by computing the -- ratio of non-empty cells and total cells. --IN: The grid [SPARSE_MATRIX] and Size of the grid [INTEGER] --OUT: The ratio [FLOAT]: non-empty cells/total cells begin return FLOAT(FLOAT(MATCOUNT(DGrid))/FLOAT((Size**2))); end Density; procedure GenerationX( Life1 : in S_MAT; Size: in Integer; Life2 : in out S_MAT) is --WHAT: This prodedure computes the each succeeding generation by -- the rule: SURVIVAL: if cell has 2 or 3 neighbors -- DEATH: when 20 and X+Xo<=Size) and -- checks grid bounds (Y+Yo>0 and Y+Yo<=Size) then Count := Count + RETRIEVE(Life1, X+Xo, Y+Yo); end if; Yo := Yo + 1; end loop; Xo := Xo + 1; end loop; Life := RETRIEVE(Life1, X, Y); if (Count=2 or Count=3) and Life=1 then ASSIGN(Life2, X, Y, 1); end if; if (Count=3 and Life/=1) then ASSIGN(Life2, X, Y, 1); end if; end loop; end loop; end GenerationX; procedure Start is --WHAT: This procedure displays the title of the program to alert user -- to its presense. --IN: None --OUT: None begin NEW_LINE(2); PUT_LINE("**********************"); PUT_LINE("** Game of Life **"); PUT_LINE("**********************"); NEW_LINE(2); end Start; procedure GenUpdate(Grid : in out S_MAT; Gen : in INTEGER; GDense : FLOAT) is --WHAT: Sends a display of the generation, population, and density to -- the screen. --IN: The Grid [S_MAT] generation (Gen) [INTEGER] and GDense -- are required. --OUT: None begin PUT("GENERATION: "); PUT(Gen, 3); PUT(" POPULATION: "); PUT(MATCOUNT(Grid), 7); PUT(" DENSITY: "); PUT(GDense, 1, 3, 0); NEW_LINE; end GenUpdate; procedure CheckUp(Grid : in out S_MAT; Generation, TermGen : in out INTEGER; GDense : in FLOAT; EndProg : in out IsOkay) is --WHAT: A bunch of operations that need to be executed each generation. -- First the Generation is updated. The state of the grid is -- displayed on the screen. A check is made against the x10th -- generation and if is; prompts user to end program or not. --IN: The Grid [SPARSE_MATRIX], Generation, TermGen [INTEGER] GDense -- [FLOAT] and EndProg are all used. --OUT: Generation is incremented by one. TermGen is incremented on -- multiple of 10 generations. The EndProg statue is changed at -- upon users input. Char : CHARACTER; begin Generation := Generation + 1; GenUpdate(Grid, Generation, GDense); -- Display status to user if Generation = TermGen then TermGen := TermGen + 10; -- Terminate after another 10? NEW_LINE; PUT("Would you like program to continue? "); GET(Char); NEW_LINE(2); -- An N here will end program if Char = 'N' or Char = 'n' then EndProg := YES; end if; end if; end CheckUp; begin Generation := 1; -- Generation count begins at 1 TermGen := 10; -- progress report given at generation 25 Start; InitRandom; GetGridSize(GSize); Create(Grid,GSize,GSize); Create(Grid2,GSize,GSize); InitGrid(GSize, Grid); GDense := Density(Grid, GSize); GenUpdate(Grid, Generation, GDense); while EndProg = NO loop GenerationX(Grid, GSize, Grid2); GDense := Density(Grid2, GSize); CheckUp(Grid2, Generation, TermGen, GDense, EndProg); if EndProg = NO then -- If coder decides to end on a odd generation GenerationX(Grid2, GSize, Grid); GDense := Density(Grid, GSize); CheckUp(Grid, Generation, TermGen, GDense, EndProg); end if; end loop; NEW_LINE; PUT_LINE("Program terminated"); NEW_LINE; end GameLife;