IM204 Coursework 1: The Game Of Life
! ----------------------------------------------------------------------------
! IM204: Declarative Programming Lecturer: S.Danicic
! Coursework 1 The Game of Life Submission #2
! ----------------------------------------------------------------------------
! Eamonn Martin - BSc (hons) Computing ID: 96/D59682
! ----------------------------------------------------------------------------
! Executable Functions:
! generate - returns the next generation of a grid.
! gennum - returns a specific generation number:
! gennum(grid, 1) = generate(grid)
! genseq - returns a sequence of generations:
! genseq(grid, 1) = [ generate(grid) ]
! The grid is a list of lists of alphas. The actual values for the occupied
! and unoccupied states of each alpha-cell are determined by the cellstate
! function, which is defined to return true (occupied) or false (unoccupied).
! There may be any number of rows and columns in the grid but it must be a
! rectangle (ie. the same number of elements in each row).
! If the truval-constant 'wrap' is true, the edge (and corner) cells are
! considered to be neighbours of cells at the opposite edge.
! ----------------------------------------------------------------------------
! Return the number of items in a list
dec count : list (alpha) -> num ;
--- count ( [] ) <= 0;
--- count ( n :: m ) <= 1 + count(m);
! Return true if n is within the range 0..r-1
infix inrange : 8 ;
dec inrange : num # num -> truval ;
--- n inrange r <= if (n < 0) or (n >= r) then false else true;
! Grid-wrap is enabled if wrap is true
dec wrap : truval ;
--- wrap <= true;
! Define a generic grid structure
type state == alpha;
type row == list (state);
type grid == list (row);
! Define the cell state-values
dec cellstate : truval -> state ;
--- cellstate ( s ) <= if s then true else false;
! Return state-values for occupied and unoccupied cells
dec occupied, unoccupied : state ;
--- occupied <= cellstate(true);
--- unoccupied <= cellstate(false);
! Return 1 if cell-value is occupied, otherwise 0
dec cellvalue : state -> num ;
--- cellvalue ( s ) <= if (s = occupied) then 1 else 0;
! Return a cell-value for a cell in a row (1 or 0)
dec _element : num # row -> num ;
--- _element ( x, [] ) <= 0;
--- _element ( x, n :: m ) <=
if (x > 0) then _element(x-1, m) else cellvalue(n);
! Bound element index within the number of row-elements
dec element : num # row -> num ;
--- element ( x, [] ) <= 0;
--- element ( x, l ) <=
if not (wrap or (x inrange count(l))) then 0
else _element(if wrap then x mod count(l) else x, l);
! Return the value of cell x,y in a grid
dec _cell : num # num # grid -> num ;
--- _cell ( x, y, [] ) <= 0;
--- _cell ( x, y, n :: m ) <=
if (y < 1) then element(x, n) else _cell(x, y-1, m);
! Bound cell-row index within the number of grid-rows
dec cell : num # num # grid -> num ;
--- cell ( x, y, [] ) <= 0;
--- cell ( x, y, l ) <=
if not (wrap or (y inrange count(l))) then 0
else _cell(x, if wrap then y mod count(l) else y, l);
! Return the number of neighbours of a cell
dec neighbours : num # num # grid -> num ;
--- neighbours ( x, y, [] ) <= 0;
--- neighbours ( x, y, l ) <=
cell(x-1,y-1,l) + cell(x,y-1,l) + cell(x+1,y-1,l) +
cell(x-1,y ,l) + cell(x+1,y ,l) +
cell(x-1,y+1,l) + cell(x,y+1,l) + cell(x+1,y+1,l) ;
! Return the new state of a cell in state with num neighbours
dec isalive : state # num -> state;
--- isalive ( s, n ) <=
if ((s /= occupied) and (n = 3)) then occupied
else if ((s = occupied) and (n > 1) and (n < 4)) then occupied
else unoccupied;
! Generate the cells for a row
dec gencells : num # num # grid # row -> row ;
--- gencells ( x, y, l, [] ) <= [];
--- gencells ( x, y, l, n :: m ) <=
[isalive(n, neighbours(x, y, l))] <> gencells(x+1, y, l, m);
! Generate the rows for the grid
dec genrows : num # grid # grid -> grid ;
--- genrows ( y, l, [] ) <= [];
--- genrows ( y, l, n :: m ) <=
[ gencells(0, y, l, n) ] <> genrows(y+1, l, m);
! ----------------------------------------------------------------------------
! Generate the next generation
dec generate : grid -> grid ;
--- generate ( [] ) <= [];
--- generate ( l ) <= genrows(0, l, l);
! Generate a specific generation number
dec gennum : grid # num -> grid ;
--- gennum ( [], n ) <= [];
--- gennum ( l, n ) <=
if (n < 1) then l else gennum(generate(l), n-1);
! Generate a sequence of generations
dec genseq : grid # num -> list (grid) ;
--- genseq ( [], n ) <= [];
--- genseq ( l, n ) <=
if (n < 1) then []
else [ generate(l) ] <> genseq(generate(l), n-1);
! ----------------------------------------------------------------------------
! Test Data
dec testgrid : grid ;
--- testgrid <= [[unoccupied, occupied, occupied, occupied,unoccupied],
[unoccupied, occupied,unoccupied, occupied,unoccupied],
[unoccupied,unoccupied, occupied,unoccupied,unoccupied],
[unoccupied, occupied,unoccupied, occupied,unoccupied],
[unoccupied, occupied, occupied, occupied,unoccupied]];
! Test Functions
dec testseq : list (grid) ;
--- testseq <= genseq(testgrid, 4);
dec testnum : list (grid) ;
--- testnum <= genseq(gennum(testgrid, 2), 2);
! Shorthand
dec t, f : truval ;
--- t <= true;
--- f <= false;
! END
Go To: IM204: Declarative Programming