/*----------------------------------------------------------------------
 | QUIES.C							940513
 |
 | Contains all quiescence-search functions.
 +----------------------------------------------------------------------*/


#include "var.h"


static void     GenerateQuiesMoves(MoveType ** list, Unsigned1 * nrMoves);
static void     GeneratePawnQuiesMoves(BoardIndexType from, MoveType * list,
                                                       Unsigned1 * nrMoves);
static void     GenerateKnightQuiesMoves(BoardIndexType from, MoveType * list,
                                                       Unsigned1 * nrMoves);
static void     GenerateBishopQuiesMoves(BoardIndexType from, MoveType * list,
                                                       Unsigned1 * nrMoves);
static void     GenerateRookQuiesMoves(BoardIndexType from, MoveType * list,
                                                       Unsigned1 * nrMoves);
static void     GenerateKingQuiesMoves(BoardIndexType from, MoveType * list,
                                                       Unsigned1 * nrMoves);


/*----------------------------------------------------------------------
 | Quiescence.							940509
 |
 | Quiescence search.
 +----------------------------------------------------------------------*/
ValueType
Quiescence(ValueType alpha, ValueType beta, PathType ** bestPath,
           Signed1 ttDepth, ValueType ttValue, Unsigned1 flag,
           Unsigned4 ttNodes)
{
    ValueType       bestValue,
                    value;
    Unsigned1       nrMoves;
    MoveType       *moveList;
    PathType       *tempPath;
    Signed2         i;
    MoveType        refMove;

    bestValue = Evaluate(ttDepth, ttValue, flag, ttNodes);
    if (bestValue >= beta) {
        ++nrLeafNodes;
        ++nrTotalNodes;
        FreePath(*bestPath);
        *bestPath = NULL;
        return (bestValue);
    }
    if (bestValue > alpha) {
        alpha = bestValue;
    }
    GenerateQuiesMoves(&moveList, &nrMoves);
    if (nrMoves == 0) {         /* (stale)mate already recognized in
                                 * Evaluate() */
        ++nrLeafNodes;
        ++nrTotalNodes;
        FreePath(*bestPath);
        *bestPath = NULL;
        return (bestValue);
    }
    ++nrInternalNodes;
    ++nrQuiesNodes;
    ++nrTotalNodes;

    /* Try refutation table move first */
    if (useRefTable && *bestPath != NULL) {
        refMove = (*bestPath)->move;
        DoMove(&refMove);
        value = -Quiescence(-beta, -alpha, &((*bestPath)->next), -2, 0, 0, 0);
        UndoMove();
        if (value <= bestValue) {
            FreePath(*bestPath);
            *bestPath = NULL;
        } else {
            bestValue = value;
            if (bestValue >= beta) {
                goto BetaCutOff;
            }
            if (bestValue > alpha) {
                alpha = bestValue;
            }
        }
    } else {
        refMove.from = 0;       /* no refutation table move */
        FreePath(*bestPath);
        *bestPath = NULL;
    }

    /* Construct heap */
    for (i = nrMoves / 2 - 1; i > 0; i--) {
        SiftDown(moveList, (Unsigned1) i, (Unsigned1) (nrMoves - 1));
    }
    for (i = nrMoves - 1; i >= 0; i--) {
        if (i != 0) {           /* Put best move above in list */
            SiftDown(moveList, (Unsigned1) 0, (Unsigned1) i);
        }
        if (EqualMoves(&(moveList[0]), &refMove)) {
            goto Next;
        }
        DoMove(&(moveList[0]));
        tempPath = NULL;
        value = -Quiescence(-beta, -alpha, &tempPath, -2, 0, 0, 0);
        UndoMove();
        if (value > bestValue) {
            bestValue = value;
            FreePath(*bestPath);
            AllocatePathMove(*bestPath);
            SPrintMove((*bestPath)->moveString, moveList[0]);
            (*bestPath)->move = moveList[0];
            (*bestPath)->next = tempPath;
            if (bestValue >= beta) {
                goto BetaCutOff;
            }
            if (bestValue > alpha) {
                alpha = bestValue;
            }
        } else {
            FreePath(tempPath);
        }
Next:
        if (i != 0) {
            moveList[0] = moveList[i];
        }
    }                           /* for */
BetaCutOff:
    FreeMoveList(moveList);
    return (bestValue);
}                               /* Quiescence */


/*----------------------------------------------------------------------
 | GenerateQuiesMoves						940513
 |
 | Generates all legal quiescence moves.
 +----------------------------------------------------------------------*/
static void     GenerateQuiesMoves(MoveType ** moveList, Unsigned1 * nrMoves)
{
    PieceType      *pieceTable;
    Unsigned1       nr;
    SquareType      piece;
    Signed2         i;
    MoveType        list[MaxMoves];

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

    *nrMoves = 0;
    /* SearchForPinsAndCheck() already done in Evaluate() */
    switch (nrCheck) {
    case 0:
        for (i = 0; i < nr; i++) {
            piece = pieceTable[i].type;
            if (IsPawn(piece)) {
                GeneratePawnQuiesMoves(pieceTable[i].square, list, nrMoves);
            } else if (IsKnight(piece) && !pinned[pieceTable[i].square]) {
                GenerateKnightQuiesMoves(pieceTable[i].square, list, nrMoves);
            } else if (IsKing(piece)) {
                GenerateKingQuiesMoves(pieceTable[i].square, list, nrMoves);
            } else {
                if (MovesDiagonal(piece)) {
                    GenerateBishopQuiesMoves(pieceTable[i].square, list, nrMoves);
                }
                if (MovesStraight(piece)) {
                    GenerateRookQuiesMoves(pieceTable[i].square, list, nrMoves);
                }
            }
        }                       /* for i */
        break;
    case 1:
        /* Capture check-giving piece, NOT with king */
        GenerateCaptureMoves(&(checkingPiece[0]), list, nrMoves);
        /* Interpose piece */
        if (checkingPiece[0].dir &&
            kingSquare[toMove] + checkingPiece[0].dir !=
            checkingPiece[0].square) {
            GenerateInterposingMoves(&(checkingPiece[0]), list, nrMoves);
        }
    case 2:
        /* Move king away, including trying to capture (one of) the
         * check-giving piece(s) */
        GenerateKingMoves(kingSquare[toMove], list, nrMoves);
        break;
    default:
        printf("ERROR: %d times in check\n", nrCheck);
        exit(0);
    }                           /* switch */
    if (*nrMoves) {
        AllocateMoveList(*moveList, *nrMoves);
        memcpy(*moveList, list, *nrMoves * sizeof(MoveType));
    }
/*  HeapSort( *moveList, *nrMoves );
   qsort( *moveList, *nrMoves, sizeof( MoveType ), CompareMoves ); */
}                               /* GenerateQuiesMoves */


/*----------------------------------------------------------------------
 | GeneratePawnQuiesMoves					940513
 |
 | Generates all legal pawn quiescence moves.
 +----------------------------------------------------------------------*/
static void     GeneratePawnQuiesMoves(BoardIndexType from, MoveType * list,
                                                       Unsigned1 * nrMoves)
{
    BoardIndexType  to;
    SquareType      piece;
    Unsigned1       dir;
    PieceType       attackingPiece;

    /* promotion moves */
    if (!pinned[from] || pinned[from] == Up || pinned[from] == Down) {
        to = pawnMoveTable[toMove][from][0];
        if (IsEmpty(board[to]) && OnSeventhRank(toMove, from)) {
            PutMoveInTable(from, to, 0, Queen | toMove, Promotion, list,
                           *nrMoves);
            PutMoveInTable(from, to, 0, Knight | toMove, Promotion, list,
                           *nrMoves);
            PutMoveInTable(from, to, 0, Rook | toMove, Promotion, list,
                           *nrMoves);
            PutMoveInTable(from, to, 0, Bishop | toMove, Promotion, list,
                           *nrMoves);
        }                       /* if promotion move */
    }                           /* 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]) {
                if (Rank(kingSquare[toMove]) != (toMove == White ? 5 : 4)) {
                    PutMoveInTable(from, to, Pawn | !toMove, 0,
                                   EnPassant | Capture, list, *nrMoves);
                } else {
                    /* remove pawns temporarily */
                    board[from] = Empty;
                    board[to + (toMove == White ? Down : Up)] = Empty;
                    if (!FindFirstPieceInDir((Unsigned1) MaxRookMoves,
                       rookTable[kingSquare[toMove]][2], &attackingPiece) ||
                        (attackingPiece.type != (Rook | !toMove) &&
                         attackingPiece.type != (Queen | !toMove))) {
                        if (!FindFirstPieceInDir((Unsigned1) MaxRookMoves,
                        rookTable[kingSquare[toMove]][3], &attackingPiece) ||
                            (attackingPiece.type != (Rook | !toMove) &&
                             attackingPiece.type != (Queen | !toMove))) {
                            PutMoveInTable(from, to, Pawn | !toMove, 0,
                                       EnPassant | Capture, list, *nrMoves);
                        }
                    }
                    /* Put pawns back */
                    board[from] = Pawn | toMove;
                    board[to + (toMove == White ? Down : Up)] = Pawn | !toMove;
                }
            } else {            /* no en-passant move */
                piece = board[to];
                if (piece && !IsEdge(piece) && !IsColor(piece, toMove)) {
                    if (OnSeventhRank(toMove, from)) {
                        PutMoveInTable(from, to, piece, Queen | toMove,
                                       Promotion | Capture, list, *nrMoves);
                        PutMoveInTable(from, to, piece, Knight | toMove,
                                       Promotion | Capture, list, *nrMoves);
                        PutMoveInTable(from, to, piece, Rook | toMove,
                                       Promotion | Capture, list, *nrMoves);
                        PutMoveInTable(from, to, piece, Bishop | toMove,
                                       Promotion | Capture, list, *nrMoves);
                    } else {
                        PutMoveInTable(from, to, piece, 0, Capture, list, *nrMoves);
                    }
                }               /* if enemy piece */
            }                   /* else */
        }                       /* if not pinned */
    }                           /* for dir */
}                               /* GeneratePawnQuiesMoves */


/*----------------------------------------------------------------------
 | GenerateKnightQuiesMoves					940513
 |
 | Generates all legal knight quiescence moves.
 +----------------------------------------------------------------------*/
static void     GenerateKnightQuiesMoves(BoardIndexType from, MoveType * list,
                                                         Unsigned1 * nrMoves)
{
    Signed2         i;
    BoardIndexType  to;
    SquareType      piece;

    for (i = 0; i < MaxKnightMoves; i++) {
        to = knightTable[from][i];
        if (!to) {
            break;
        }
        piece = board[to];
        /* capture moves only */
        if (!IsEmpty(piece) && !IsEdge(piece) && !IsColor(piece, toMove)) {
            PutMoveInTable(from, to, piece, 0, Capture, list, *nrMoves);
        }
    }
}                               /* GenerateKnightQuiesMoves */


/*----------------------------------------------------------------------
 | GenerateBishopQuiesMoves					940513
 |
 | Generates all legal bishop quiescence moves.
 +----------------------------------------------------------------------*/
static void     GenerateBishopQuiesMoves(BoardIndexType from, MoveType * list,
                                                         Unsigned1 * nrMoves)
{
    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)) {
                    continue;
                }
                /* capture moves only */
                if (!IsEdge(piece) && !IsColor(piece, toMove)) {
                    PutMoveInTable(from, to, piece, 0, Capture, list, *nrMoves);
                    break;
                } else {
                    break;
                }
            }                   /* for j */
        }                       /* if not pinned */
    }                           /* for i */
}                               /* GenerateBishopQuiesMoves */


/*----------------------------------------------------------------------
 | GenerateRookQuiesMoves					940513
 |
 | Generates all legal quiescence rook moves.
 +----------------------------------------------------------------------*/
static void     GenerateRookQuiesMoves(BoardIndexType from, MoveType * list,
                                                       Unsigned1 * nrMoves)
{
    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)) {
                    continue;
                }
                /* capture moves only */
                if (!IsEdge(piece) && !IsColor(piece, toMove)) {
                    PutMoveInTable(from, to, piece, 0, Capture, list, *nrMoves);
                    break;
                } else {
                    break;
                }
            }                   /* for j */
        }                       /* if not pinned */
    }                           /* for i */
}                               /* GenerateRookQuiesMoves */


/*----------------------------------------------------------------------
 | GenerateKingQuiesMoves					940513
 |
 | Generates all legal king quiescence moves.
 +----------------------------------------------------------------------*/
static void     GenerateKingQuiesMoves(BoardIndexType from, MoveType * list,
                                                       Unsigned1 * nrMoves)
{
    Signed2         i;
    BoardIndexType  to;
    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];
        /* capture moves only */
        if (!IsEmpty(piece) && !IsEdge(piece) && !IsColor(piece, toMove)) {
            if (!IsCheckingDir(-rookDir[i]) &&
                !Attacked(to, (SquareType) ! toMove)) {
                PutMoveInTable(from, to, piece, 0, Capture, list, *nrMoves);
            }
        }
    }
    for (i = 0; i < 4; i++) {
        to = bishopTable[from][i][0];
        if (!to) {
            continue;
        }
        piece = board[to];
        /* capture moves only */
        if (!IsEmpty(piece) && !IsEdge(piece) && !IsColor(piece, toMove)) {
            if (!IsCheckingDir(-bishopDir[i]) &&
                !Attacked(to, (SquareType) ! toMove)) {
                PutMoveInTable(from, to, piece, 0, Capture, list, *nrMoves);
            }
        }
    }
    board[kingSquare[toMove]] = King | toMove;
}                               /* GenerateKingQuiesMoves */
