IM204 Coursework 2: Noughts and Crosses


!---------------------------------------------------------------------------
! IM204 Coursework 2: Noughts and Crosses -  Eamonn Martin - ID: 96/D59682
!---------------------------------------------------------------------------

! Cell states
data symbols == space ++ nought ++ cross;

! Grid structure
type state == symbols;
type row   == list (state);
type grid  == list (row);

! Return the unoccupied-cell state
dec unoccupied : state;
--- unoccupied <= space;

!---------------------------------------------------------------------------
! Part 1 - List all grids possible after adding a symbol to a grid
!---------------------------------------------------------------------------

! Return the number of items in a list
dec count : list (alpha) -> num ;
--- count ( [] ) <= 0;
--- count ( n :: m ) <= 1 + count(m);

! Return row wih state s at position i (if i is within row)
dec getrow : row # num # state -> row;
--- getrow ( [], i, s ) <= [];
--- getrow ( n :: m, i, s ) <=
    (if (i=0) then [s] else [n]) <> getrow(m, i-1, s);

! Return grid with position i set to state s
dec getgrid : grid # num # state -> grid;
--- getgrid ( [], i, s ) <= [];
--- getgrid ( n :: m, i, s ) <=
    [getrow( n, i, s )] <> getgrid(m, i-count(n), s);

! Return a grid for each space-cell in row set to state s
dec cellgrids : grid # num # state # row -> list (grid);
--- cellgrids ( g, i, s, [] ) <= [];
--- cellgrids ( g, i, s, n :: m ) <=
    if (n /= unoccupied) then therest
    else [getgrid(g, i, s)] <> therest
    where therest == cellgrids(g, i+1, s, m);

! Return a grid for each space-cell in grid set to state s
dec getgrids : grid # num # state # grid -> list (grid);
--- getgrids ( g, i, s, [] ) <= [];
--- getgrids ( g, i, s, n :: m ) <=
    cellgrids( g, i, s, n ) <> getgrids(g, i+count(n), s, m);

! Return all grids possible after adding state s to grid
dec nextgrids : grid # state -> list (grid);
--- nextgrids ( g, s ) <= getgrids(g, 0, s, g);


!---------------------------------------------------------------------------
! Part 2 - Score each possible grid and list those with the highest score
!---------------------------------------------------------------------------

dec rowstate : row # num -> state;
--- rowstate ( [], i ) <= unoccupied;
--- rowstate ( n :: m, i ) <=
    if (i=0) then n else rowstate(m, i-1);

dec cellstate : grid # num # num -> state;
--- cellstate ( [], x, y ) <= unoccupied;
--- cellstate ( n :: m, x, y ) <=
    if (y=0) then rowstate(n, x) else cellstate(m, x, y-1);

! Return the value to player s of cell x,y in grid g
dec cell : grid # num # num # state -> num;
--- cell ( g, x, y, s ) <=
    if (v = unoccupied) then 0
    else if (v = s) then 2 else 1
    where v == cellstate(g, x, y);

dec cellvalue : grid # num # num # num # state -> num;
--- cellvalue ( g, x, y, z, s ) <=
    cell(g,x-z,y-z,s) + cell(g,x,y-z,s) + cell(g,x+z,y-z,s) +
    cell(g,x-z,y  ,s)           +         cell(g,x+z,y  ,s) +
    cell(g,x-z,y+z,s) + cell(g,x,y+z,s) + cell(g,x+z,y+z,s) ;

dec cellscore : grid # num # num # state # state -> num;
--- cellscore ( g, x, y, s, c ) <=
    if (c = unoccupied) then 0
    else if (c = s) then v else (0-v)
    where v == cellvalue(g, x, y, 1, s) +
               cellvalue(g, x, y, 2, s) ;

dec rowscore : grid # num # num # state # row -> num;
--- rowscore ( g, x, y, s, [] ) <= 0;
--- rowscore ( g, x, y, s, n :: m ) <=
    cellscore(g, x, y, s, n) + rowscore(g, x+1, y, s, m);

dec gridscore : grid # num # state # grid -> num;
--- gridscore ( g, y, s, [] ) <= 0;
--- gridscore ( g, y, s, n :: m ) <=
    rowscore(g, 0, y, s, n) + gridscore(g, y+1, s, m);

dec bestmoves : list (grid) # state # num # list (grid) -> list (grid);
--- bestmoves ( [], s, max, g ) <= g;
--- bestmoves ( n :: m, s, max, g ) <=
    if (score < max) then bestmoves(m, s, max, g)
    else if (score > max) then bestmoves(m, s, score, [n])
    else bestmoves(m, s, max, g <> [n])
    where score == gridscore(n, 0, s, n);

dec nextmoves : grid # state -> list (grid);
--- nextmoves ( g, s) <=
    bestmoves(nextgrids(g, s), s, 0-99, []);


!---------------------------------------------------------------------------

! Test grids
dec g0, g1, g2, g3 : grid;

! Starting grid
--- g0 <= [[cross,nought,cross],[cross,space,space],[space,nought,nought]];

! Possible next moves
--- g1 <= [[cross,nought,cross],[cross,cross,space],[space,nought,nought]];
--- g2 <= [[cross,nought,cross],[cross,space,cross],[space,nought,nought]];
--- g3 <= [[cross,nought,cross],[cross,space,space],[cross,nought,nought]];

! Grid scores for each move
dec test1, test2, test3 : num;
--- test1 <= gridscore(g1, 0, cross, g1);
--- test2 <= gridscore(g2, 0, cross, g2);
--- test3 <= gridscore(g3, 0, cross, g3);

! Shorthand
dec o, x, . : state;
--- o <= nought;
--- x <= cross;
--- . <= space;

! END

Go To: IM204: Declarative Programming