module Logic.GameState;

import Stdlib.Prelude open;
import Logic.Extra open;
import Logic.Board open;

type Error :=
  | --- no error occurred
    noError : Error
  | --- a non-fatal error occurred
    continue : String  Error
  | --- a fatal occurred
    terminate : String  Error;

type GameState :=
  mkGameState@{
    board : Board;
    player : Symbol;
    error : Error;
  };

--- Textual representation of a ;GameState;
showGameState (state : GameState) : String := showBoard (GameState.board state);

--- initial ;GameState;
beginState : GameState :=
  mkGameState@{
    board :=
      mkBoard
        (map
          (map empty)
          ((1 :: 2 :: 3 :: nil)
            :: (4 :: 5 :: 6 :: nil)
            :: (7 :: 8 :: 9 :: nil)
            :: nil));
    player := X;
    error := noError;
  };

--- ;true; if some player has won the game
won (state : GameState) : Bool :=
  let
    squares := Board.squares (GameState.board state);
  in any full (diagonals squares ++ rows squares ++ columns squares);

--- ;true; if there is a draw
draw (state : GameState) : Bool :=
  let
    squares := Board.squares (GameState.board state);
  in isEmpty (possibleMoves (flatten squares));