/*----------------------------------------------------------------------
 | EVALUATE.C							940502
 |
 | Contains position evaluation functions.
 +----------------------------------------------------------------------*/


#include "var.h"


static Boolean  NoMoves(void);
static Boolean  PawnCanMove(BoardIndexType square);
static Boolean  KnightCanMove(BoardIndexType square);
static Boolean  BishopCanMove(BoardIndexType square);
static Boolean  RookCanMove(BoardIndexType square);
static Boolean  KingCanMove(BoardIndexType square);
static Boolean  CaptureMovesAvailable(CheckPieceType * piece);
static Boolean  PawnCaptureMovesAvailable(CheckPieceType * piece);
static Boolean  KnightCaptureMovesAvailable(CheckPieceType * piece);
static Boolean  BishopCaptureMovesAvailable(CheckPieceType * piece);
static Boolean  RookCaptureMovesAvailable(CheckPieceType * piece);
static Boolean  InterposingMovesAvailable(CheckPieceType * piece);
static Boolean  ToMovesAvailable(BoardIndexType to);
static Boolean  PawnToMovesAvailable(BoardIndexType to);
static Boolean  KnightToMovesAvailable(BoardIndexType to);
static Boolean  BishopToMovesAvailable(BoardIndexType to);
static Boolean  RookToMovesAvailable(BoardIndexType to);


/*----------------------------------------------------------------------
 | Evaluate							940502
 |
 | Evaluates a position. 'toMove' is the person who is to move.
 +----------------------------------------------------------------------*/
ValueType
Evaluate(Signed1 ttDepth, ValueType ttValue, Unsigned1 flag,
         Unsigned4 ttNodes)
{
    ValueType       value,
                    readValue;
    MoveType        readMove;
    Unsigned1       readFlag;
    Signed1         readDepth;
    Unsigned4       readNodes;

    if (ttDepth == -2) {
        GetMoveFromTransTable(readMove, readDepth, readValue, readFlag,
                              readNodes);
    } else {
        readDepth = ttDepth;
        readValue = ttValue;
        readFlag = flag;
        readNodes = ttNodes;
    }
    if (NoMoves()) {
        return (nrCheck ? -Mate + (nrGamePlies - startPly) : Draw);
    }
    if (nrCheck) {
        return (-Infinity);
    }
    value = material[toMove] + positionalValue[toMove] -
        material[!toMove] - positionalValue[!toMove];
    if (useTtValue && readDepth != -1) {
        if (keepMethod == BigAll) {
            nrExtraNodes += readNodes;
            nrTotalNodes += readNodes;
        }
        if ((readFlag == UpperBound && value > readValue) ||
            (readFlag == LowerBound && value < readValue) ||
            readFlag == Valid) {
            value = readValue;
        }
    }
    return (value);
}                               /* Evaluate */


/*----------------------------------------------------------------------
 | NoMoves.							940509
 |
 | Returns 'True' if no moves are available for color 'toMove'. Otherwise
 | 'False' is returned;
 +----------------------------------------------------------------------*/
static          Boolean
                NoMoves(void)
{
    PieceType      *pieceTable;
    Unsigned1       nr;
    SquareType      piece;
    Signed2         i;

    pieceTable = pieces[toMove];
    nr = nrPieces[toMove];

    SearchForPinsAndCheck();
    switch (nrCheck) {
    case 0:
        for (i = 0; i < nr; i++) {
            piece = pieceTable[i].type;
            if (IsPawn(piece) && PawnCanMove(pieceTable[i].square)) {
                return (False);
            } else if (IsKnight(piece) && !pinned[pieceTable[i].square] &&
                       KnightCanMove(pieceTable[i].square)) {
                return (False);
            } else if (IsKing(piece) && KingCanMove(pieceTable[i].square)) {
                return (False);
            } else {
                if (MovesDiagonal(piece) &&
                    BishopCanMove(pieceTable[i].square)) {
                    return (False);
                }
                if (MovesStraight(piece) &&
                    RookCanMove(pieceTable[i].square)) {
                    return (False);
                }
            }
        }                       /* for i */
        break;
    case 1:
        /* Capture check-giving piece, NOT with king */
        if (CaptureMovesAvailable(&(checkingPiece[0]))) {
            return (False);
        }
        /* Interpose piece */
        if (checkingPiece[0].dir &&
            kingSquare[toMove] + checkingPiece[0].dir !=
            checkingPiece[0].square &&
            InterposingMovesAvailable(&(checkingPiece[0]))) {
            return (False);
        }
    case 2:
        /* Move king away, including trying to capture (one of) the
         * check-giving piece(s) */
        if (KingCanMove(kingSquare[toMove])) {
            return (False);
        }
        break;
    default:
        printf("ERROR: %d times in check\n", nrCheck);
        exit(0);
    }                           /* switch */
    return (True);
}                               /* NoMoves */


/*----------------------------------------------------------------------
 | GeneratePawnMoves						940420
 |
 | Generates all legal pawn moves.
 +----------------------------------------------------------------------*/
static          Boolean
                PawnCanMove(BoardIndexType from)
{
    BoardIndexType  to;
    SquareType      piece;
    Unsigned1       dir;
    PieceType       attackingPiece;

    /* non-capture moves */
    if (!pinned[from] || pinned[from] == Up || pinned[from] == Down) {
        to = pawnMoveTable[toMove][from][0];
        if (IsEmpty(board[to])) {
            return (True);
        }
    }                           /* if not pinned */
    /* capture moves */
    for (dir = 0; dir < 2; dir++) {
        if (!pinned[from] || pinned[from] == pawnCaptureDir[toMove][dir] ||
            pinned[from] == -pawnCaptureDir[toMove][dir]) {
            to = pawnCaptureTable[toMove][from][dir];
            if (to == epSquare[nrGamePlies]) {
                /* remove pawns temporarily */
                board[from] = Empty;
                board[to + (toMove == White ? Down : Up)] = Empty;
                if (FindFirstPieceInDir((Unsigned1) MaxRookMoves,
                       rookTable[kingSquare[toMove]][2], &attackingPiece)) {
                    if (attackingPiece.type != (Rook | !toMove) &&
                        attackingPiece.type != (Queen | !toMove)) {
                        if (FindFirstPieceInDir((Unsigned1) MaxRookMoves,
                        rookTable[kingSquare[toMove]][3], &attackingPiece)) {
                            if (attackingPiece.type != (Rook | !toMove) &&
                                attackingPiece.type != (Queen | !toMove)) {
                                /* Put pawns back */
                                board[from] = Pawn | toMove;
                                board[to + (toMove == White ? Down : Up)] = Pawn | !toMove;
                                return (True);
                            }
                        }
                    }
                }
                /* Put pawns back */
                board[from] = Pawn | toMove;
                board[to + (toMove == White ? Down : Up)] = Pawn | !toMove;
            } else {
                piece = board[to];
                if (piece && !IsEdge(piece) && !IsColor(piece, toMove)) {
                    return (True);
                }               /* if enemy piece */
            }                   /* else */
        }                       /* if not pinned */
    }                           /* for dir */
    return (False);
}                               /* PawnCanMove */


/*----------------------------------------------------------------------
 | GenerateKnightMoves						940422
 |
 | Generates all legal knight moves.
 +----------------------------------------------------------------------*/
static          Boolean
                KnightCanMove(BoardIndexType from)
{
    Signed2         i;
    BoardIndexType  to;
    SquareType      piece;

    for (i = 0; i < MaxKnightMoves; i++) {
        to = knightTable[from][i];
        if (!to) {
            break;
        }
        piece = board[to];
        if (IsEmpty(piece)) {
            return (True);
        } else if (!IsEdge(piece) && !IsColor(piece, toMove)) {
            return (True);
        }
    }
    return (False);
}                               /* KnightCanMove */


/*----------------------------------------------------------------------
 | GenerateBishopMoves						940422
 |
 | Generates all legal bishop moves.
 +----------------------------------------------------------------------*/
static          Boolean
                BishopCanMove(BoardIndexType from)
{
    Signed2         i,
                    j;
    BoardIndexType  to;
    SquareType      piece;

    for (i = 0; i < 4; i++) {
        if (!pinned[from] || pinned[from] == bishopDir[i] ||
            pinned[from] == -bishopDir[i]) {
            for (j = 0; j < MaxBishopMoves; j++) {
                to = bishopTable[from][i][j];
                if (!to) {
                    break;
                }
                piece = board[to];
                if (IsEmpty(piece)) {
                    return (True);
                } else if (!IsEdge(piece) && !IsColor(piece, toMove)) {
                    return (True);
                } else {
                    break;
                }
            }                   /* for j */
        }                       /* if not pinned */
    }                           /* for i */
    return (False);
}                               /* BishopCanMove */


/*----------------------------------------------------------------------
 | GenerateRookMoves						940422
 |
 | Generates all legal rook moves.
 +----------------------------------------------------------------------*/
static          Boolean
                RookCanMove(BoardIndexType from)
{
    Signed2         i,
                    j;
    BoardIndexType  to;
    SquareType      piece;

    for (i = 0; i < 4; i++) {
        if (!pinned[from] || pinned[from] == rookDir[i] ||
            pinned[from] == -rookDir[i]) {
            for (j = 0; j < MaxRookMoves; j++) {
                to = rookTable[from][i][j];
                if (!to) {
                    break;
                }
                piece = board[to];
                if (IsEmpty(piece)) {
                    return (True);
                } else if (!IsEdge(piece) && !IsColor(piece, toMove)) {
                    return (True);
                } else {
                    break;
                }
            }                   /* for j */
        }                       /* if not pinned */
    }                           /* for i */
    return (False);
}                               /* RookCanMove */


/*----------------------------------------------------------------------
 | GenerateKingMoves						940422
 |
 | Generates all legal king moves.
 +----------------------------------------------------------------------*/
static          Boolean
                KingCanMove(BoardIndexType from)
{
    Signed2         i;
    BoardIndexType  to;
    BoardIndexType  square2,
                    square3,
                    square4,
                    square5,
                    square6;
    SquareType      piece;

    /* Remove king temporarily in view of Attacked() */
    board[kingSquare[toMove]] = Empty;
    for (i = 0; i < 4; i++) {
        to = rookTable[from][i][0];
        if (!to) {
            continue;
        }
        piece = board[to];
        if (IsEmpty(piece)) {
            if (!IsCheckingDir(rookDir[i]) &&
                !IsCheckingDir(-rookDir[i]) &&
                !Attacked(to, (SquareType) ! toMove)) {
                board[kingSquare[toMove]] = King | toMove;
                return (True);
            }
        } else if (!IsEdge(piece) && !IsColor(piece, toMove)) {
            if (!IsCheckingDir(-rookDir[i]) &&
                !Attacked(to, (SquareType) ! toMove)) {
                board[kingSquare[toMove]] = King | toMove;
                return (True);
            }
        }
    }
    for (i = 0; i < 4; i++) {
        to = bishopTable[from][i][0];
        if (!to) {
            continue;
        }
        piece = board[to];
        if (IsEmpty(piece)) {
            if (!IsCheckingDir(bishopDir[i]) &&
                !IsCheckingDir(-bishopDir[i]) &&
                !Attacked(to, (SquareType) ! toMove)) {
                board[kingSquare[toMove]] = King | toMove;
                return (True);
            }
        } else if (!IsEdge(piece) && !IsColor(piece, toMove)) {
            if (!IsCheckingDir(-bishopDir[i]) &&
                !Attacked(to, (SquareType) ! toMove)) {
                board[kingSquare[toMove]] = King | toMove;
                return (True);
            }
        }
    }
    /* Castling */
    if (!nrCheck) {
        if (IsWhite(toMove)) {
            square2 = F1;
            square3 = G1;
            square4 = D1;
            square5 = C1;
            square6 = B1;
        } else {
            square2 = F8;
            square3 = G8;
            square4 = D8;
            square5 = C8;
            square6 = B8;
        }
        if (ShortCastlingPossible() &&
            IsEmpty(board[square2]) && IsEmpty(board[square3]) &&
            !Attacked(square2, (SquareType) ! toMove) &&
            !Attacked(square3, (SquareType) ! toMove)) {
            board[kingSquare[toMove]] = King | toMove;
            return (True);
        }
        if (LongCastlingPossible() &&
            IsEmpty(board[square4]) && IsEmpty(board[square5]) &&
            IsEmpty(board[square6]) &&
            !Attacked(square4, (SquareType) ! toMove) &&
            !Attacked(square5, (SquareType) ! toMove) &&
            !Attacked(square6, (SquareType) ! toMove)) {
            board[kingSquare[toMove]] = King | toMove;
            return (True);
        }
    }                           /* if not in check */
    board[kingSquare[toMove]] = King | toMove;
    return (False);
}                               /* GenerateKingMoves */


/*----------------------------------------------------------------------
 | GenerateCaptureMoves						940428
 |
 | Generate moves for color 'toMove', trying to disable check by
 | capturing the check-giving piece.
 | NOTE: no king capture moves are generated because they are generated
 | later in GenerateKingMoves().
 +----------------------------------------------------------------------*/
static          Boolean
                CaptureMovesAvailable(CheckPieceType * piece)
{
    if (PawnCaptureMovesAvailable(piece)) {
        return (True);
    }
    if (KnightCaptureMovesAvailable(piece)) {
        return (True);
    }
    if (BishopCaptureMovesAvailable(piece)) {
        return (True);
    }
    return (RookCaptureMovesAvailable(piece));
}                               /* CaptureMovesAvailable */


/*----------------------------------------------------------------------
 | GeneratePawnCaptureMoves					940428
 |
 | Generate pawn moves for color 'toMove', trying to disable check by
 | capturing the check-giving piece.
 +----------------------------------------------------------------------*/
static          Boolean
                PawnCaptureMovesAvailable(CheckPieceType * piece)
{
    Signed2         dir;
    BoardIndexType  from,
                    to;

    to = piece->square;
    /* Normal capture */
    for (dir = 0; dir < 2; dir++) {
        if (pawnCaptureDir[!toMove][dir] == -piece->dir) {
            continue;
        }
        from = pawnCaptureTable[!toMove][to][dir];
        if (from && board[from] == (Pawn | toMove) && (!pinned[from] ||
                             pinned[from] == pawnCaptureDir[!toMove][dir] ||
                           pinned[from] == -pawnCaptureDir[!toMove][dir])) {
            return (True);
        }
    }                           /* for dir */

    /* En passant */
    dir = toMove == White ? Up : Down;
    if (epSquare[nrGamePlies] == to + dir) {
        from = to + Right;
        if (from && board[from] == (Pawn | toMove) && (!pinned[from] ||
             pinned[from] == dir + Right || pinned[from] == -dir - Right)) {
            return (True);
        }                       /* if not pinned */
        from = to + Left;
        if (from && board[from] == (Pawn | toMove) && (!pinned[from] ||
               pinned[from] == dir + Left || pinned[from] == -dir - Left)) {
            return (True);
        }                       /* if not pinned */
    }                           /* if */
    return (False);
}                               /* PawnCaptureMovesAvailable */


/*----------------------------------------------------------------------
 | GenerateKnightCaptureMoves					940428
 |
 | Generate knight moves for color 'toMove', trying to disable check by
 | capturing the check-giving piece.
 +----------------------------------------------------------------------*/
static          Boolean
                KnightCaptureMovesAvailable(CheckPieceType * piece)
{
    Signed2         i;
    BoardIndexType  from,
                    to;

    to = piece->square;
    for (i = 0; i < MaxKnightMoves; i++) {
        if (knightDir[i] == -piece->dir) {
            continue;
        }
        from = knightTable[to][i];
        if (!from) {
            break;
        }
        if (board[from] == (Knight | toMove) && !pinned[from]) {
            return (True);
        }
    }
    return (False);
}                               /* KnightCaptureMovesAvailable */


/*----------------------------------------------------------------------
 | GenerateBishopCaptureMoves					940428
 |
 | Generate bishop moves for color 'toMove', trying to disable check by
 | capturing the check-giving piece.
 +----------------------------------------------------------------------*/
static          Boolean
                BishopCaptureMovesAvailable(CheckPieceType * piece)
{
    Signed2         i,
                    j;
    BoardIndexType  from,
                    to;

    to = piece->square;
    for (i = 0; i < 4; i++) {
        if (bishopDir[i] == -piece->dir) {
            continue;
        }
        for (j = 0; j < MaxBishopMoves; j++) {
            from = bishopTable[to][i][j];
            if (!from) {
                break;
            }
            if (IsEmpty(board[from])) {
                continue;
            }
            if ((board[from] == (Bishop | toMove) || board[from] == (Queen | toMove)) &&
                (!pinned[from] || pinned[from] == bishopDir[i] ||
                 pinned[from] == -bishopDir[i])) {
                return (True);
            } else {
                break;
            }
        }                       /* for j */
    }                           /* for i */
    return (False);
}                               /* BishopCaptureMovesAvailable */


/*----------------------------------------------------------------------
 | GenerateRookCaptureMoves					940428
 |
 | Generate rook moves for color 'toMove', trying to disable check by
 | capturing the check-giving piece.
 +----------------------------------------------------------------------*/
static          Boolean
                RookCaptureMovesAvailable(CheckPieceType * piece)
{
    Signed2         i,
                    j;
    BoardIndexType  from,
                    to;

    to = piece->square;
    for (i = 0; i < 4; i++) {
        if (rookDir[i] == -piece->dir) {
            continue;
        }
        for (j = 0; j < MaxRookMoves; j++) {
            from = rookTable[to][i][j];
            if (!from) {
                break;
            }
            if (IsEmpty(board[from])) {
                continue;
            }
            if ((board[from] == (Rook | toMove) || board[from] == (Queen | toMove)) &&
                (!pinned[from] || pinned[from] == rookDir[i] ||
                 pinned[from] == -rookDir[i])) {
                return (True);
            } else {
                break;
            }
        }                       /* for j */
    }                           /* for i */
    return (False);
}                               /* RookCaptureMovesAvailable */


/*----------------------------------------------------------------------
 | GenerateInterposingMoves					940428
 |
 | Generate moves for color 'toMove' to disable check by interposing
 | a piece.
 +----------------------------------------------------------------------*/
static          Boolean
                InterposingMovesAvailable(CheckPieceType * piece)
{
    BoardIndexType  to;
    DirectionType   dir;

    dir = piece->dir;
    for (to = kingSquare[toMove] + dir; to != piece->square; to += dir) {
        if (ToMovesAvailable(to)) {
            return (True);
        }
    }                           /* for square */
    return (False);
}                               /* InterposingMovesAvailable */


/*----------------------------------------------------------------------
 | GenerateToMoves						940428
 |
 | Generates moves for color 'toMove' to empty square 'to'.
 | NOTE: no king moves are generated.
 +----------------------------------------------------------------------*/
static          Boolean
                ToMovesAvailable(BoardIndexType to)
{
    if (PawnToMovesAvailable(to)) {
        return (True);
    }
    if (KnightToMovesAvailable(to)) {
        return (True);
    }
    if (BishopToMovesAvailable(to)) {
        return (True);
    }
    return (RookToMovesAvailable(to));
}                               /* ToMovesAvailable */


/*----------------------------------------------------------------------
 | GeneratePawnToMoves						940428
 |
 | Generates pawn moves for color 'toMove' to empty square 'to'.
 +----------------------------------------------------------------------*/
static          Boolean
                PawnToMovesAvailable(BoardIndexType to)
{
    Signed2         dir;
    BoardIndexType  from;

    for (dir = 0; dir < 2; dir++) {
        from = pawnMoveTable[!toMove][to][dir];
        if (from && board[from] == (Pawn | toMove) && (!pinned[from] ||
                              pinned[from] == Up || pinned[from] == Down)) {
            return (True);
        }
    }                           /* for dir */
    return (False);
}                               /* PawnToMovesAvailable */


/*----------------------------------------------------------------------
 | GenerateKnightToMoves						940428
 |
 | Generates knight moves for color 'toMove' to empty square 'to'.
 +----------------------------------------------------------------------*/
static          Boolean
                KnightToMovesAvailable(BoardIndexType to)
{
    Signed2         i;
    BoardIndexType  from;

    for (i = 0; i < MaxKnightMoves; i++) {
        from = knightTable[to][i];
        if (!from) {
            break;
        }
        if (board[from] == (Knight | toMove) && !pinned[from]) {
            return (True);
        }
    }
    return (False);
}                               /* KnightToMovesAvailable */


/*----------------------------------------------------------------------
 | GenerateBishopToMoves					940428
 |
 | Generates bishop moves for color 'toMove' to empty square 'to'.
 +----------------------------------------------------------------------*/
static          Boolean
                BishopToMovesAvailable(BoardIndexType to)
{
    Signed2         i,
                    j;
    BoardIndexType  from;

    for (i = 0; i < 4; i++) {
        for (j = 0; j < MaxBishopMoves; j++) {
            from = bishopTable[to][i][j];
            if (!from) {
                break;
            }
            if (IsEmpty(board[from])) {
                continue;
            }
            if ((board[from] == (Bishop | toMove) || board[from] == (Queen | toMove)) &&
                (!pinned[from] || pinned[from] == bishopDir[i] ||
                 pinned[from] == -bishopDir[i])) {
                return (True);
            } else {
                break;
            }
        }                       /* for j */
    }                           /* for i */
    return (False);
}                               /* BishopToMovesAvailable */


/*----------------------------------------------------------------------
 | GenerateRookToMoves						940428
 |
 | Generates rook moves for color 'toMove' to empty square 'to'.
 +----------------------------------------------------------------------*/
static          Boolean
                RookToMovesAvailable(BoardIndexType to)
{
    Signed2         i,
                    j;
    BoardIndexType  from;

    for (i = 0; i < 4; i++) {
        for (j = 0; j < MaxRookMoves; j++) {
            from = rookTable[to][i][j];
            if (!from) {
                break;
            }
            if (IsEmpty(board[from])) {
                continue;
            }
            if ((board[from] == (Rook | toMove) || board[from] == (Queen | toMove)) &&
                (!pinned[from] || pinned[from] == rookDir[i] ||
                 pinned[from] == -rookDir[i])) {
                return (True);
            } else {
                break;
            }
        }                       /* for j */
    }                           /* for i */
    return (False);
}                               /* RookToMovesAvailable */
