/* GNU Chess 5.0 - quiesce.c - quiescence search code
   Copyright (c) 1999-2002 Free Software Foundation, Inc.

   GNU Chess is based on the two research programs 
   Cobalt by Chua Kong-Sian and Gazebo by Stuart Cracraft.

   GNU Chess is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   GNU Chess is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with GNU Chess; see the file COPYING.  If not, write to
   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.

   Contact Info: 
   bug-gnu-chess@gnu.org
   cracraft@ai.mit.edu, cracraft@stanfordalumni.org, cracraft@earthlink.net
*/
/*
 *
 */

#include <stdio.h>
#include "util.h"
#include "move.h"
#include "ttable.h"
#include "eval.h"
#include "search.h"
#include "movelist.h"
#include "searchstats.h"
#include "searchdata.h"
#include "searchparams.h"
#include "sort.h"
#include "swap.h"
#include "genmove.h"

int Quiesce (board_t *board, 
	     searchparams_t *searchparams,
	     searchdata_t *searchdata, 
	     searchstats_t *searchstats, 
	     uint8_t ply, 
	     int alpha, 
	     int beta,
	     int depth,
	     int *best_move_out)
/**************************************************************************
 *
 *  Our quiescent search.  This quiescent search is able to recognize
 *  mates.
 *
 **************************************************************************/
{
    uint8_t side, xside;
    int best,  score, savealpha, pat;
    leaf *p, *pbest;
    undo_t undo[1];
    int leafnode=true;
    int skip_stalemate_check=false;
    int best_move;
    int ret;
    int movecount=0;
    pickstate_t pickstate[1];

    best_move=NOMOVE;
    *best_move_out=NOMOVE;

    searchstats->QuiesCnt++;

    // emergency exit

    if(ply>=MAXPLYDEPTH){
	return board->in_check?alpha:Evaluate(board, 
					      searchparams,
					      searchdata, 
					      searchstats, 
					      alpha,
					      beta);
    }



    if (EvaluateDraw (board)){
	return (DRAWSCORE);
    }

    side = board->side;
    xside = 1^side;
    pat=best=-INFIN;
    searchdata->InChk[ply] = board->in_check;
    PickStateInit(pickstate);

    savealpha = alpha;
    pbest = NULL;

    if(!board->in_check){
	pat=best = Evaluate (board, searchparams, searchdata, searchstats, alpha, beta);
    }
    if (best >= beta){
	goto done;
    }

    alpha = MAX(best, alpha);

    while(true){
	
	if(board->in_check){
	    ret=PhasePick1(board,searchdata,pickstate,&p,ply,depth);
	}else{
	    ret=PhasePickQuiesce(board,searchdata,pickstate,&p,ply,depth);
	}
	 
	if(!ret){
	    break;
	}

	/*	swapoff=SwapOff (board,p->move);*/


	MoveMakeS (board, &p->move, undo);
	if (board->xin_check){
	    MoveUnMakeS (board, undo);
	    continue;
	}

	// delta pruning
	if (!searchdata->InChk[ply]){
	    if( p->score<0 ||  (!board->in_check && pat+p->score< alpha-search.DeltaMargin)){
		MoveUnMakeS (board, undo);
		best=MAX(best,pat+p->score+search.DeltaMargin/2);
		continue;
	    }
	}


	movecount++;
	score = -Quiesce (board, 
			  searchparams,
			  searchdata, 
			  searchstats, 
			  ply+1, 
			  -beta, 
			  -alpha,
			  depth-1,
			  &best_move);
	leafnode=false;
	MoveUnMakeS (board, undo);
	if (score > best) {
	    best = score;
	    pbest = p;
	    *best_move_out=p->move;
	    if (best >= beta){
		goto done;
	    }
	    alpha = MAX (alpha, best);
	}
    }
    if(board->in_check && movecount==0){
	return (-MATE+(ply+1)-2);
    }
 done:

    if(DRAWSCORE<=best && best<=alpha){
	skip_stalemate_check=true;
    }
    if(DRAWSCORE>=best && best>=beta){
	skip_stalemate_check=true;
    }
    if(!skip_stalemate_check && leafnode && board->pmaterial[side] <= ValueR && GenStalemateCheck(board)){
    	return DRAWSCORE;
    }
    ASSERT(best>=-MATE-1);
    ASSERT(best<=MATE+1);


    return (best);
}
 
