Example #1
0
static void pv_fill(const mv_t pv[], board_t * board) {

   int move;
   int trans_move, trans_depth, trans_min_value, trans_max_value;
   undo_t undo[1];

   ASSERT(pv!=NULL);
   ASSERT(board!=NULL);

   ASSERT(UseTrans);

   move = *pv;

   if (move != MoveNone && move != MoveNull) {

      move_do(board,move,undo);
      pv_fill(pv+1,board);
      move_undo(board,move,undo);

      trans_move = move;
      trans_depth = -127; // HACK
      trans_min_value = -ValueInf;
      trans_max_value = +ValueInf;

      trans_store(Trans,board->key,trans_move,trans_depth,trans_min_value,trans_max_value);
   }
}
Example #2
0
static void parse_position(char string[]) {

   const char * fen;
   char * moves;
   const char * ptr;
   char move_string[256];
   int move;
   undo_t undo[1];

   // init

   fen = strstr(string,"fen ");
   moves = strstr(string,"moves ");

   // start position

   if (fen != NULL) { // "fen" present

      if (moves != NULL) { // "moves" present
         ASSERT(moves>fen);
         moves[-1] = '\0'; // dirty, but so is UCI
      }

      board_from_fen(SearchInput->board,fen+4); // CHANGE ME

   } else {

      // HACK: assumes startpos

      board_from_fen(SearchInput->board,StartFen);
   }

   // moves

   if (moves != NULL) { // "moves" present

      ptr = moves + 6;

      while (*ptr != '\0') {

         move_string[0] = *ptr++;
         move_string[1] = *ptr++;
         move_string[2] = *ptr++;
         move_string[3] = *ptr++;

         if (*ptr == '\0' || *ptr == ' ') {
            move_string[4] = '\0';
         } else { // promote
            move_string[4] = *ptr++;
            move_string[5] = '\0';
         }

         move = move_from_string(move_string,SearchInput->board);

         move_do(SearchInput->board,move,undo);

         while (*ptr == ' ') ptr++;
      }
   }
}
bool pseudo_is_legal(int move, board_t * board) {

    int me, opp;
    int from, to;
    int piece;
    bool legal;
    int king;
    undo_t undo[1];

    ASSERT(move_is_ok(move));
    ASSERT(board!=NULL);

    // init

    me = board->turn;
    opp = COLOUR_OPP(me);

    from = MOVE_FROM(move);
    to = MOVE_TO(move);

    piece = board->square[from];
    ASSERT(COLOUR_IS(piece,me));

    // slow test for en-passant captures

    if (MOVE_IS_EN_PASSANT(move)) {

        move_do(board,move,undo);
        legal = !IS_IN_CHECK(board,me);
        move_undo(board,move,undo);

        return legal;
    }

    // king moves (including castle)

    if (PIECE_IS_KING(piece)) {

        legal = !is_attacked(board,to,opp);

        if (DEBUG) {
            ASSERT(board->square[from]==piece);
            board->square[from] = Empty;
            ASSERT(legal==!is_attacked(board,to,opp));
            board->square[from] = piece;
        }

        return legal;
    }

    // pins

    if (is_pinned(board,from,me)) {
        king = KING_POS(board,me);
        return DELTA_INC_LINE(king-to) == DELTA_INC_LINE(king-from); // does not discover the line
    }

    return true;
}
Example #4
0
void TEngine::AddMove(mv_t move)
{
   undo_t undo;
   move_do(&Board,move,&undo);
   char move_str[6];
   strcat(move_history," ");
   move_to_string(move,move_str,6);
   strcat(move_history,move_str);
   move_history_len++;
}
Example #5
0
static void add_check(list_t * list, int move, board_t * board) {

    undo_t undo[1];

    ASSERT(list!=NULL);
    ASSERT(move_is_ok(move));
    ASSERT(board!=NULL);

    move_do(board,move,undo);
    if (IS_IN_CHECK(board,board->turn)) LIST_ADD(list,move);
    move_undo(board,move,undo);
}
bool pseudo_is_legal(int move, const board_t * board) {

   board_t new_board[1];

   ASSERT(move_is_ok(move));
   ASSERT(board_is_ok(board));

   ASSERT(move_is_pseudo(move,board));

   board_copy(new_board,board);
   move_do(new_board,move);

   return !is_in_check(new_board,colour_opp(new_board->turn));
}
Example #7
0
bool move_is_check(int move, board_t * board) {

    undo_t undo[1];
    bool check;
    int me, opp, king;
    int from, to, piece;

    ASSERT(move_is_ok(move));
    ASSERT(board!=NULL);

    // slow test for complex moves

    if (MOVE_IS_SPECIAL(move)) {

        move_do(board,move,undo);
        check = IS_IN_CHECK(board,board->turn);
        move_undo(board,move,undo);

        return check;
    }

    // init

    me = board->turn;
    opp = COLOUR_OPP(me);
    king = KING_POS(board,opp);

    from = MOVE_FROM(move);
    to = MOVE_TO(move);
    piece = board->square[from];
    ASSERT(COLOUR_IS(piece,me));

    // direct check

    if (PIECE_ATTACK(board,piece,to,king)) return true;

    // indirect check

    if (is_pinned(board,from,opp)
            && DELTA_INC_LINE(king-to) != DELTA_INC_LINE(king-from)) {
        return true;
    }

    return false;
}
Example #8
0
void game_goto(game_t * game, int pos) {

   int i;

   ASSERT(game!=NULL);
   ASSERT(pos>=0&&pos<=game->size);

   if (pos < game->pos) { // going backward => replay the whole game
      board_copy(game->board,game->start_board);
      game->pos = 0;
   }

   for (i = game->pos; i < pos; i++) move_do(game->board,game->move[i]);
   ASSERT(i==pos);

   game->pos = pos;

   game_update(game);
}
Example #9
0
bool line_to_san(const move_t line[], const board_t * board, char string[], int size) {

	board_t new_board[1];
	int pos;
	int move;
	char move_string[256];

	ASSERT(line_is_ok(line));
	ASSERT(board_is_ok(board));
	ASSERT(string!=NULL);
	ASSERT(size>=StringSize);

	// init
	string[0]='\0';
	if (size < StringSize) return false;
//    return false;
	board_copy(new_board,board);
	pos = 0;

	// loop

	while ((move = *line++) != MoveNone) {
		if (pos != 0) {
			if (pos >= size) return false;
			string[pos++] = ' ';
		}
		if (!move_is_legal(move,new_board)
			|| !move_to_san(move,new_board,&string[pos],size-pos)) {
				if (Strict || UseDebug) {
					move_to_can(move,new_board,move_string,sizeof(move_string));
					my_log("POLYGLOT ILLEGAL MOVE IN LINE %s\n",move_string);
					board_disp(new_board);
					if (Strict) my_fatal("line_to_san(): illegal move\n");
				}
				break;
		}
		pos += (int)strlen(&string[pos]);
		move_do(new_board,move);
	}
	if (pos >= size) return false;
	string[pos] = '\0';
	return true;
}
Example #10
0
void game_add_move(game_t * game, int move) {

   ASSERT(game!=NULL);
   ASSERT(move_is_ok(move));

   ASSERT(move_is_legal(move,game->board));

   if (game->pos >= GameSize) my_fatal("game_add_move(): game overflow\n");

   game->move[game->pos] = move;
   game->key[game->pos] = game->board->key;

   move_do(game->board,move);
   game->pos++;

   game->size = game->pos; // truncate game, HACK: before calling game_is_ok() in game_update()

   game_update(game);
}
Example #11
0
static void perft(const board_t * board, int depth) {

   int me;
   list_t list[1];
   int i, move;
   board_t new_board[1];

   ASSERT(board_is_ok(board));
   ASSERT(depth_is_ok(depth));

   ASSERT(!is_in_check(board,colour_opp(board->turn)));

   // init

   NodeNb++;

   // leaf

   if (depth == 0) {
      LeafNb++;
      return;
   }

   // more init

   me = board->turn;

   // move loop

   gen_moves(list,board);

   for (i = 0; i < list_size(list); i++) {

      move = list_move(list,i);

      board_copy(new_board,board);
      move_do(new_board,move);

      if (!is_in_check(new_board,me)) perft(new_board,depth-1);
   }
}
Example #12
0
void game_get_board(const game_t * game, board_t * board, int pos) {

   int start;
   int i;

   ASSERT(game!=NULL);
   ASSERT(board!=NULL);
   ASSERT(pos==-1||(pos>=0&&pos<=game->size)); // HACK

   if (pos < 0) pos = game->pos;

   if (pos >= game->pos) { // forward from current position
      start = game->pos;
      board_copy(board,game->board);
   } else { // backward => replay the whole game
      start = 0;
      board_copy(board,game->start_board);
   }

   for (i = start; i < pos; i++) move_do(board,game->move[i]);
}
Example #13
0
bool game_is_ok(const game_t * game) {

   board_t board[1];
   int pos, move;

   if (game == NULL) return false;

   if (game->size < 0 || game->size > GameSize) return false;
   if (game->pos < 0 || game->pos > game->size) return false;

   // optional heavy DEBUG mode

   if (!UseSlowDebug) return true;

   if (!board_is_ok(game->start_board)) return false;

   board_copy(board,game->start_board);

   for (pos = 0; pos <= game->size; pos++) {

      if (pos == game->pos) {
         if (!board_equal(game->board,board)) return false;
      }

      if (pos >= game->size) break;

      if (game->key[pos] != board->key) return false;

      move = game->move[pos];
      if (!move_is_legal(move,board))
          ;

      move_do(board,move);
   }

   if (game->status != game_comp_status(game)) return false;

   return true;
}
Example #14
0
bool line_to_can(const move_t line[], const board_t * board, char string[], int size) {

   board_t new_board[1];
   int pos;
   int move;

   ASSERT(line_is_ok(line));
   ASSERT(board_is_ok(board));
   ASSERT(string!=NULL);
   ASSERT(size>=StringSize);

   // init

   if (size < StringSize) return false;

   board_copy(new_board,board);
   pos = 0;

   // loop

   while ((move = *line++) != MoveNone) {

      if (pos != 0) {
         if (pos >= size) return false;
         string[pos++] = ' ';
      }

      if (!move_to_can(move,new_board,&string[pos],size-pos)) return false;
      pos += (int)strlen(&string[pos]);

      move_do(new_board,move);
   }

   if (pos >= size) return false;
   string[pos] = '\0';

   return true;
}
Example #15
0
void game_disp(const game_t * game) {

   board_t board[1];
   int i, move;

   ASSERT(game_is_ok(game));

   board_copy(board,game->start_board);

   board_disp(board);

   for (i = 0; i < game->pos; i++) {

      move = game->move[i];
      move_disp(move,board);

      move_do(board,move);
   }

   my_log("POLYGLOT\n");

   board_disp(board);
}
Example #16
0
bool line_from_can (move_t line[], const board_t * board, const char string[], int size) {

   int pos;
   char new_string[StringSize], *p;
   int move;
   board_t new_board[1];

   ASSERT(line!=NULL);
   ASSERT(board_is_ok(board));
   ASSERT(string!=NULL);
   ASSERT(size>=LineSize);

   // init

   pos = 0;
   board_copy(new_board,board);

   // loop

   strcpy(new_string,string); // HACK

   for (p = strtok(new_string," "); p != NULL; p = strtok(NULL," ")) {
      move = move_from_can(p,new_board);
      ASSERT(move!=MoveNone);
      ASSERT(move_is_legal(move,new_board));
      if (move == MoveNone || !move_is_legal(move,new_board)) break; // HACK: ignore illegal moves
      if (pos >= size) return false;
      line[pos++] = move;

      move_do(new_board,move);
   }

   if (pos >= size) return false;
   line[pos] = MoveNone;

   return true;
}
Example #17
0
void TEngine::Output()
{
  board_t backup_board;
  board_copy(&backup_board,&Board);
  bool flag = false;

  char move_str[6] = "";
  if (LastMove)
     move_to_string(&Board,LastMove,move_str,6);

  MainForm->edLastMove->Text = move_str;
  char buf[10000];
  char *next_line = buf;

  if (Process->Get(buf)) {
    while (next_line[0] != 0) {
      char *cur_line = next_line;
      char *end;
      end = strstr(cur_line,"\r\n");
      if (end) {
        end[0] = 0;
        end[1] = 0;
        if (end[-1] == '\r')
          end[-1] = 0;
        next_line = end + 2;
        if (flag && Board.square[75] == 66) {
           int k; k++;
        }
        ParseLine(cur_line);
        if (flag && Board.square[75] == 66) {
           int k; k++;
        }
      }
      else
        break;
    }
    MainForm->Memo->Lines->Clear();
    for (int i=0; i<MainForm->MultiPV; i++) {
       AnsiString s;
       s += PV[i].score;
       s += " ";
       undo_t last_move_undo;
       if (LastMove)
         move_do(&Board,LastMove,&last_move_undo);
       int cnt = 0;
       ASSERT(PV[i].pv_len>=0);
       for (int j=0; j<PV[i].pv_len; j++) {
          char move_s[6];
          //move_to_string(&Board,PV[i].moves[j],move_s,6);
          move_to_string(PV[i].moves[j],move_s,8);
          s += move_s;
          s += " ";
          /*
          move_do(&Board,PV[i].moves[j],&PV[i].undo[j]);
          cnt++;
          */
       }
       /*
       for (int j=PV[i].pv_len-1; j>=0; j--) {
         move_undo(&Board,PV[i].moves[j],&PV[i].undo[j]);
         cnt--;
       }
       if (cnt) {
          int k; k++;
       }
       */
       if (LastMove)
         move_undo(&Board,LastMove,&last_move_undo);
       MainForm->Memo->Lines->Append(s);
    }
  }
}
Example #18
0
static int full_search(board_t * board, int alpha, int beta, int depth, int height, mv_t pv[], int node_type, bool extended, int ThreadId) {

   bool in_check;
   bool single_reply;
   bool good_cap;
   int trans_move, trans_depth, trans_flags, trans_value;
   int old_alpha;
   int value, best_value;
   int move, best_move;
   int new_depth;
   int played_nb;
   int i;
   int opt_value;
   bool reduced, cap_extended;
   attack_t attack[1];
   sort_t sort[1];
   undo_t undo[1];
   mv_t new_pv[HeightMax];
   mv_t played[256];
   int FutilityMargin;
   int probe_score, probe_depth;
   int newHistoryValue;
   int threshold;
   int reduction;
   int last_move;
   int quiet_move_count;
   entry_t * found_entry;
      
   ASSERT(board!=NULL);
   ASSERT(range_is_ok(alpha,beta));
   ASSERT(depth_is_ok(depth));
   ASSERT(height_is_ok(height));
   ASSERT(pv!=NULL);
   ASSERT(node_type==NodePV||node_type==NodeCut||node_type==NodeAll);

   ASSERT(board_is_legal(board));

   // horizon?

   if (depth <= 0){
	   if (node_type == NodePV)
			SearchCurrent[ThreadId]->CheckDepth = 1 - SearchCurrent[ThreadId]->CheckNb - 1;
	   else
			SearchCurrent[ThreadId]->CheckDepth = 1 - SearchCurrent[ThreadId]->CheckNb;
	   return full_quiescence(board,alpha,beta,0,height,pv,ThreadId);
   }

   // init

   SearchCurrent[ThreadId]->node_nb++;
   SearchInfo[ThreadId]->check_nb--;
   PV_CLEAR(pv);

   if (height > SearchCurrent[ThreadId]->max_depth) SearchCurrent[ThreadId]->max_depth = height;

   if (SearchInfo[ThreadId]->check_nb <= 0) {
      SearchInfo[ThreadId]->check_nb += SearchInfo[ThreadId]->check_inc;
      search_check(ThreadId);
   }

    // draw?

	if (board_is_repetition(board)) return ValueDraw;

		/*
		Interior node recognizer from scorpio by Daniel Shawul
		-> dont probe at the leaves as this will slow down search
	    For 4/3 pieces probe there also.
		-> After captures and pawn moves assume exact score and cutoff tree,
	    because we are making progress. Note this is not done only for speed.
		-> if we are far from root (depth / 2), assume exact score and cutoff tree
	*/

//	if (egbb_is_loaded && board->piece_nb <= 5){ 
//		probe_depth = (2 * SearchCurrent[ThreadId]->act_iteration) / 3;
//		if ((board->piece_nb <=4 || height <= probe_depth)
//           && (height >= probe_depth 
//		         || board->cap_sq != SquareNone || PIECE_IS_PAWN(board->moving_piece))
//			  ) {
//		
//            if (probe_bitbases(board, probe_score)){
//                if (probe_score < 0 && board_is_mate(board)) return VALUE_MATE(height);            
//                probe_score = value_from_trans(probe_score,height);

//			/*	trans_move = MoveNone;
//				trans_depth = depth;
//				trans_flags = TransUnknown;
//				if (probe_score > alpha) trans_flags |= TransLower;
//				if (probe_score < beta) trans_flags |= TransUpper;
//   			    trans_store(Trans,board->key,trans_move,trans_depth,trans_flags,probe_score);*/
//				return probe_score;
//			}
//		}
//	}


	if (recog_draw(board,ThreadId)) return ValueDraw;

   // mate-distance pruning

   if (UseDistancePruning) {

      // lower bound

      value = VALUE_MATE(height+2); // does not work if the current position is mate
      if (value > alpha && board_is_mate(board)) value = VALUE_MATE(height);

      if (value > alpha) {
         alpha = value;
         if (value >= beta) return value;
      }

      // upper bound

      value = -VALUE_MATE(height+1);

      if (value < beta) {
         beta = value;
         if (value <= alpha) return value;
      }
   }

   // transposition table

   trans_move = MoveNone;

   if (UseTrans && depth >= TransDepth) {

      if (trans_retrieve(Trans,&found_entry,board->key,&trans_move,&trans_depth,&trans_flags,&trans_value)) {

         // trans_move is now updated
/*		  if (found_entry->depth != trans_depth){
			  found_entry->depth = trans_depth;
		  }*/
          
		  if (node_type != NodePV /*|| ThreadId > 0*/) {

            if (UseMateValues) {

            if (trans_depth < depth) {
				   if (trans_value < -ValueEvalInf && TRANS_IS_UPPER(trans_flags)) {
					  trans_depth = depth;
					  trans_flags = TransUpper;
				   } else if (trans_value > +ValueEvalInf && TRANS_IS_LOWER(trans_flags)) {
					  trans_depth = depth;
					  trans_flags = TransLower;
				   }
			   }

				if (trans_depth >= depth) {

				   trans_value = value_from_trans(trans_value,height);

				   if ((UseExact && TRANS_IS_EXACT(trans_flags))
					|| (TRANS_IS_LOWER(trans_flags) && trans_value >= beta)
					|| (TRANS_IS_UPPER(trans_flags) && trans_value <= alpha)) {
						return trans_value;
				   } 

				 /*  if (TRANS_IS_EXACT(trans_flags))
					   return trans_value;
				   if (TRANS_IS_LOWER(trans_flags)) {
						if (trans_value >= beta)
							return trans_value;
						if (trans_value > alpha)
							alpha = trans_value;
					}
					if (TRANS_IS_UPPER(trans_flags)) {
						if (trans_value <= alpha)
							return trans_value;
						if (trans_value < beta)
							beta = trans_value;
					} */
				}
			}
		 }
	  }
   }

   // height limit

   if (height >= HeightMax-1) return eval(board, alpha, beta, ThreadId);

   // more init

   old_alpha = alpha;
   best_value = ValueNone;
   best_move = MoveNone;
   played_nb = 0;
   last_move = SearchCurrent[ThreadId]->last_move;
   
   attack_set(attack,board);
   in_check = ATTACK_IN_CHECK(attack);

   // null-move pruning

   if (UseNull && depth >= NullDepth && node_type != NodePV
   && !(trans_move != MoveNone && TRANS_IS_UPPER(trans_flags) && trans_depth >= depth - NullReduction - depth/4 && trans_value < beta)) { 
   // if hash table tells us we are < beta, the null move search probably wastes time
   // bugfix 25-3-2013 (trans_move condition added) was LOS ~90%, + 10 elo. Probably not nearly that good but it's a bugfix...)

      if (!in_check
       && !value_is_mate(beta)
       && do_null(board)
       && (!UseNullEval || depth <= NullReduction+1 || eval(board,alpha, beta, ThreadId) >= beta)) {

         // null-move search
		 
        //  if (depth < 11)
		 new_depth = depth - NullReduction - depth/4; // JD: from Stockfish, 10 elo better
		     
		// else
		//	new_depth = depth - NullReduction - 2;
		 //new_depth = depth - R_adpt(board->piece_size[board->turn]+board->pawn_size[board->turn],depth,NullReduction) - 1;
		 
	     move_do_null(board,undo);
	     SearchCurrent[ThreadId]->last_move = MoveNone; // refutation table
         value = -full_search(board,-beta,-beta+1,new_depth,height+1,new_pv,NODE_OPP(node_type),false,ThreadId);
         move_undo_null(board,undo);

         // pruning

         if (value >= beta) {

            if (value > +ValueEvalInf) value = +ValueEvalInf; // do not return unproven mates
            ASSERT(!value_is_mate(value));

            // pv_cat(pv,new_pv,MoveNull);

            best_move = MoveNone;
            best_value = value;
            goto cut;
         }
	  }
   }
    
   // Razoring: idea by Tord Romstad (Glaurung), fixed by Jerry Donald
   
   if (node_type != NodePV && !in_check && trans_move == MoveNone && depth <= 3){ 
        threshold = beta - RazorMargin - (depth-1)*39; // Values from Protector (Raimund Heid)
        if (eval(board,threshold-1, threshold, ThreadId) < threshold){
		   value = full_quiescence(board,threshold-1,threshold,0,height,pv,ThreadId); 
           if (value < threshold) // corrected - was < beta which is too risky at depth > 1
               return value;
        }
   }


   // Internal Iterative Deepening
   
   if (UseIID && depth >= IIDDepth && node_type == NodePV && trans_move == MoveNone) {

	  new_depth = MIN(depth - IIDReduction,depth/2);
      ASSERT(new_depth>0);

      value = full_search(board,alpha,beta,new_depth,height,new_pv,node_type,false,ThreadId);
      if (value <= alpha) value = full_search(board,-ValueInf,beta,new_depth,height,new_pv,node_type,false,ThreadId);

      trans_move = new_pv[0];
   }

   // move generation

   sort_init(sort,board,attack,depth,height,trans_move,last_move,ThreadId);

   single_reply = false;
   if (in_check && LIST_SIZE(sort->list) == 1) single_reply = true; // HACK

   // move loop

   opt_value = +ValueInf;
   good_cap = true;
   quiet_move_count = 0;
   
   while ((move=sort_next(sort,ThreadId)) != MoveNone) {

	  // extensions

      new_depth = full_new_depth(depth,move,board,single_reply,node_type==NodePV, height, extended, &cap_extended, ThreadId);
      
      // history pruning

      value = sort->value; // history score
	  if (!in_check && depth <= 6 && node_type != NodePV 
		  && new_depth < depth && value < 2 * HistoryValue / (depth + depth % 2) /*2*/ 
		  && played_nb >= 1+depth && !move_is_dangerous(move,board)){ 
			continue;
	  }

	  // futility pruning

	  if (UseFutility && node_type != NodePV && depth <= 5) {
		  
         if (!in_check && new_depth < depth&& !move_is_tactical(move,board) && !move_is_dangerous(move,board)) {

            ASSERT(!move_is_check(move,board));
            
            // move count based pruning (added by Jerry Donald: ~+20 elo!)
            
            if (quiet_move_count >= MoveCountLimit[depth])continue;
            
            quiet_move_count++;

            // optimistic evaluation (Chris Formula)

            if (opt_value == +ValueInf) {
				if (depth>=2){
					FutilityMargin = FutilityMargin2 + (depth % 2) * 100;
				}
				else{
					FutilityMargin = FutilityMargin1;
				}
				opt_value = eval(board,alpha-FutilityMargin,alpha,ThreadId) + FutilityMargin;
				ASSERT(opt_value<+ValueInf);
            }

            value = opt_value;

            // pruning

            if (value <= alpha) {

               if (value > best_value) {
                  best_value = value;
                  PV_CLEAR(pv);
               }

               continue;
            }
         }
      } 
      
      // Late Move Reductions
	  
	  // init	  
	  reduced = false;
	  reduction = 0;

      // lookup reduction      
	  if (UseHistory) {
			if (!in_check && new_depth < depth && played_nb >= HistoryMoveNb
				&& depth >= HistoryDepth && !move_is_dangerous(move,board)) {
                         
					if (good_cap && !move_is_tactical(move,board)){
						good_cap = false;
					}
					
					if (!good_cap){
                        reduction = (node_type == NodePV ? quietPvMoveReduction[depth<64 ? depth: 63][played_nb<64? played_nb: 63]:
                                     quietMoveReduction[depth<64 ? depth: 63][played_nb<64? played_nb: 63]);
                        
						// reduced bad captures less
						if (move_is_tactical(move,board)) reduction = reduction / 2; // bad captures
						
						// set reduction flag
						if (reduction > 0)  reduced = true;
                    }
			}
	  }

	  // recursive search

	  move_do(board,move,undo);
	  
	  SearchCurrent[ThreadId]->last_move = move;

      if (node_type != NodePV || best_value == ValueNone) { // first move or non-pv
		 value = -full_search(board,-beta,-alpha,new_depth-reduction,height+1,new_pv,NODE_OPP(node_type),cap_extended,ThreadId);
         
         // The move was reduced and fails high; so we research with full depth
         if (reduced && value >= beta){
		        value = -full_search(board,-beta,-alpha,new_depth,height+1,new_pv,NODE_OPP(node_type),cap_extended,ThreadId);

         }
         
      } else { // other moves (all PV children)
      
		 value = -full_search(board,-alpha-1,-alpha,new_depth-reduction,height+1,new_pv,NodeCut,cap_extended,ThreadId);
         
         // In case of fail high:
               
         // If reduced then we try a research with node_type = NodePV
         if (value > alpha && reduced){  // && value < beta
			value = -full_search(board,-beta,-alpha,new_depth-reduction,height+1,new_pv,NodePV,cap_extended,ThreadId);
		    
            // Still fails high! We research to full depth
            if (reduced && value >= beta){	
		        value = -full_search(board,-beta,-alpha,new_depth,height+1,new_pv,NodePV,cap_extended,ThreadId);
            }
         
         // If not reduced we research as a PV node   
         } else if (value > alpha){	
		    value = -full_search(board,-beta,-alpha,new_depth,height+1,new_pv,NodePV,cap_extended,ThreadId);
         }
      }

      move_undo(board,move,undo);

      played[played_nb++] = move;
	  
      if (value > best_value) {
         best_value = value;
         pv_cat(pv,new_pv,move);
         if (value > alpha) {
            alpha = value;
            best_move = move;
			if (value >= beta){ 
				goto cut;
			}
         }
      }

      if (node_type == NodeCut) node_type = NodeAll;
   }

   // ALL node

   if (best_value == ValueNone) { // no legal move
      if (in_check) {
         ASSERT(board_is_mate(board));
         return VALUE_MATE(height);
      } else {
         ASSERT(board_is_stalemate(board));
         return ValueDraw;
      }
   }

cut:

   ASSERT(value_is_ok(best_value));

   // move ordering

   if (best_move != MoveNone) {

      good_move(best_move,board,depth,height,ThreadId);

      if (best_value >= beta && !move_is_tactical(best_move,board)) { // check is 204b and d, e
         
         // refutation table ~5 elo
         if (last_move != MoveNull && last_move != MoveNone)refutation_update(best_move, last_move, board, ThreadId);

		 ASSERT(played_nb>0&&played[played_nb-1]==best_move);

	 	 for (i = 0; i < played_nb-1; i++) {
			move = played[i];
			ASSERT(move!=best_move);
			history_bad(move,board,ThreadId);
			bad_move(move,board,depth,height,ThreadId); // added JD ~ 5 elo
		 }

		 history_good(best_move,board,ThreadId);
		
      }
   }

   // transposition table

   if (UseTrans && depth >= TransDepth) {

      trans_move = best_move;
      trans_depth = depth;
      trans_flags = TransUnknown;
      if (best_value > old_alpha) trans_flags |= TransLower;
      if (best_value < beta) trans_flags |= TransUpper;
      trans_value = value_to_trans(best_value,height);

      trans_store(Trans,board->key,trans_move,trans_depth,trans_flags,trans_value);

   }

   return best_value;
}
Example #19
0
static int parse_bestmove(uci_t * uci, const char string[]) {

   parse_t parse[1];
   char command[StringSize];
   char option[StringSize];
   char argument[StringSize];
   board_t board[1];

   ASSERT(uci_is_ok(uci));
   ASSERT(string!=NULL);

   // init

   strcpy(command,"bestmove");

   parse_open(parse,string);
   parse_add_keyword(parse,"ponder");

   // bestmove

   if (!parse_get_string(parse,argument,StringSize)) {
      my_fatal("parse_bestmove(): missing argument\n");
   }

   uci->best_move = move_from_can(argument,uci->board);
   if (uci->best_move == MoveNone) my_fatal("parse_bestmove(): not a move \"%s\"\n",argument);

   ASSERT(uci->best_move!=MoveNone);
   ASSERT(move_is_legal(uci->best_move,uci->board));

   // loop

   while (parse_get_word(parse,option,StringSize)) {

      parse_get_string(parse,argument,StringSize);

      if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);

      if (false) {

      } else if (my_string_equal(option,"ponder")) {

         ASSERT(!my_string_empty(argument));

         board_copy(board,uci->board);
         move_do(board,uci->best_move);

         uci->ponder_move = move_from_can(argument,board);
         // if (uci->ponder_move == MoveNone) my_fatal("parse_bestmove(): not a move \"%s\"\n",argument);

         ASSERT(uci->ponder_move!=MoveNone);
         ASSERT(move_is_legal(uci->ponder_move,board));

      } else {

         my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);
      }
   }

   parse_close(parse);

   return EVENT_MOVE;
}
Example #20
0
static int full_root(list_t * list, board_t * board, int alpha, int beta, int depth, int height, int search_type) {

   int old_alpha;
   int value, best_value[MultiPVMax];
   int i, move, j;
   int new_depth;
   undo_t undo[1];
   mv_t new_pv[HeightMax];
   bool found;

   ASSERT(list_is_ok(list));
   ASSERT(board_is_ok(board));
   ASSERT(range_is_ok(alpha,beta));
   ASSERT(depth_is_ok(depth));
   ASSERT(height_is_ok(height));
   ASSERT(search_type==SearchNormal||search_type==SearchShort);

   ASSERT(list==SearchRoot->list);
   ASSERT(!LIST_IS_EMPTY(list));
   ASSERT(board==SearchCurrent->board);
   ASSERT(board_is_legal(board));
   ASSERT(depth>=1);

   // init

   SearchStack[height].best_move = MoveNone;
   SearchStack[height].move = MoveNone;
   SearchStack[height].threat_move = MoveNone;
   SearchStack[height].reduced = false;

   SearchCurrent->node_nb++;
   SearchInfo->check_nb--;

   if (SearchCurrent->multipv == 0)
	  for (i = 0; i < LIST_SIZE(list); i++) list->value[i] = ValueNone;

   old_alpha = alpha;
   best_value[SearchCurrent->multipv] = ValueNone;

   // move loop

   for (i = 0; i < LIST_SIZE(list); i++) {

      move = LIST_MOVE(list,i);

	  if (SearchCurrent->multipv > 0){
		  found = false;
		  for (j = 0; j < SearchCurrent->multipv; j++){
			  if (SearchBest[j].pv[0] == move){
				  found = true;
				  break;
			  }
		  }
		  if (found == true)
				continue;
	  }
	  SearchStack[height].move = move;

      SearchRoot->depth = depth;
      SearchRoot->move = move;
      SearchRoot->move_pos = i;
      SearchRoot->move_nb = LIST_SIZE(list);

      search_update_root();

      new_depth = full_new_depth(depth,move,board,board_is_check(board)&&LIST_SIZE(list)==1,false,true, height);

      move_do(board,move,undo);

      if (search_type == SearchShort || best_value[SearchCurrent->multipv] == ValueNone) { // first move
         value = -full_search(board,-beta,-alpha,new_depth,height+1,new_pv,NodePV);
		 if (value <= alpha){ // research
			 old_alpha = -ValueInf;
			 value = -full_search(board,-beta,ValueInf,new_depth,height+1,new_pv,NodePV);
		 }
		 else if (value >= beta){ // research
			 value = -full_search(board,-ValueInf,-alpha,new_depth,height+1,new_pv,NodePV);
		 }
			  
      } else { // other moves
         value = -full_search(board,-alpha-1,-alpha,new_depth,height+1,new_pv,NodeCut);
         if (value > alpha) { // && value < beta
            SearchRoot->change = true;
            SearchRoot->easy = false;
            SearchRoot->flag = false;
            search_update_root();
            value = -full_search(board,-beta,-alpha,new_depth,height+1,new_pv,NodePV);
         }
      }

      move_undo(board,move,undo);

      if (value <= alpha) { // upper bound
         list->value[i] = old_alpha;
      } else if (value >= beta) { // lower bound
         list->value[i] = beta;
      } else { // alpha < value < beta => exact value
         list->value[i] = value;
      }

      if (value > best_value[SearchCurrent->multipv] && (best_value[SearchCurrent->multipv] == ValueNone || value > alpha)) {

         SearchBest[SearchCurrent->multipv].move = move;
		 SearchStack[height].best_move = move;
         SearchBest[SearchCurrent->multipv].value = value;
         if (value <= alpha) { // upper bound
            SearchBest[SearchCurrent->multipv].flags = SearchUpper;
         } else if (value >= beta) { // lower bound
            SearchBest[SearchCurrent->multipv].flags = SearchLower;
         } else { // alpha < value < beta => exact value
            SearchBest[SearchCurrent->multipv].flags = SearchExact;
         }
         SearchBest[SearchCurrent->multipv].depth = depth;
         pv_cat(SearchBest[SearchCurrent->multipv].pv,new_pv,move);

         search_update_best();
      }

      if (value > best_value[SearchCurrent->multipv]) {
         best_value[SearchCurrent->multipv] = value;
         if (value > alpha) {
            if (search_type == SearchNormal) alpha = value;
            if (value >= beta) break;
         }
      }
   }

   ASSERT(value_is_ok(best_value));

   list_sort(list);

   ASSERT(SearchBest->move==LIST_MOVE(list,0));
   ASSERT(SearchBest->value==best_value);

   if (UseTrans && best_value[SearchCurrent->multipv] > old_alpha && best_value[SearchCurrent->multipv] < beta) {
      pv_fill(SearchBest[SearchCurrent->multipv].pv,board);
   }

   return best_value[SearchCurrent->multipv];
}
Example #21
0
static void search_update() {

   int move;
   int move_nb;
   board_t board[1];

   ASSERT(!Uci->searching);

   // launch a new search if needed

   if (State->state == THINK || State->state == PONDER || State->state == ANALYSE) {

      // opening book

      if (State->state == THINK && option_get_bool("Book")) {

         game_get_board(Game,Uci->board);

         move = book_move(Uci->board,option_get_bool("BookRandom"));

         if (move != MoveNone && move_is_legal(move,Uci->board)) {

            my_log("POLYGLOT *BOOK MOVE*\n");

            search_clear(); // clears Uci->ponder_move
            Uci->best_move = move;

            board_copy(board,Uci->board);
            move_do(board,move);
            Uci->ponder_move = book_move(board,false); // expected move = best book move

            Uci->best_pv[0] = Uci->best_move;
            Uci->best_pv[1] = Uci->ponder_move; // can be MoveNone
            Uci->best_pv[2] = MoveNone;

            comp_move(Uci->best_move);

            return;
         }
      }

      // engine search

      my_log("POLYGLOT START SEARCH\n");

      // options

      uci_send_option(Uci,"UCI_Chess960","%s",option_get_bool("Chess960")?"true":"false");

      if (option_get_int("UCIVersion") >= 2) {
         uci_send_option(Uci,"UCI_Opponent","none none %s %s",(XB->computer)?"computer":"human",XB->name);
         uci_send_option(Uci,"UCI_AnalyseMode","%s",(XB->analyse)?"true":"false");
      }

      uci_send_option(Uci,"Ponder","%s",ponder()?"true":"false");

      // position

      move = (State->state == PONDER) ? State->exp_move : MoveNone;
      send_board(move); // updates Uci->board global variable

      // search

      if (State->state == THINK || State->state == PONDER) {

         engine_send_queue(Engine,"go");

         if (XB->time_limit) {

            // fixed time per move

            engine_send_queue(Engine," movetime %.0f",XB->time_max*1000.0);

         } else {

            // time controls

            if (colour_is_white(Uci->board->turn)) {
               engine_send_queue(Engine," wtime %.0f btime %.0f",XB->my_time*1000.0,XB->opp_time*1000.0);
            } else {
               engine_send_queue(Engine," wtime %.0f btime %.0f",XB->opp_time*1000.0,XB->my_time*1000.0);
            }

            if (XB->inc != 0.0) engine_send_queue(Engine," winc %.0f binc %.0f",XB->inc*1000.0,XB->inc*1000.0);

            if (XB->mps != 0) {

               move_nb = XB->mps - (Uci->board->move_nb % XB->mps);
               ASSERT(move_nb>=1&&move_nb<=XB->mps);

               engine_send_queue(Engine," movestogo %d",move_nb);
            }
         }

         if (XB->depth_limit) engine_send_queue(Engine," depth %d",XB->depth_max);

         if (State->state == PONDER) engine_send_queue(Engine," ponder");

         engine_send(Engine,""); // newline

      } else if (State->state == ANALYSE) {

         engine_send(Engine,"go infinite");

      } else {

         ASSERT(false);
      }

      // init search info

      ASSERT(!Uci->searching);

      search_clear();

      Uci->searching = true;
      Uci->pending_nb++;
   }
}
Example #22
0
static void send_board(int extra_move) {

   char fen[256];
   int start, end;
   board_t board[1];
   int pos;
   int move;
   char string[256];

   ASSERT(extra_move==MoveNone||move_is_ok(extra_move));

   ASSERT(!Uci->searching);

   // init

   game_get_board(Game,Uci->board);
   if (extra_move != MoveNone) move_do(Uci->board,extra_move);

   board_to_fen(Uci->board,fen,256);
   my_log("POLYGLOT FEN %s\n",fen);

   ASSERT(board_can_play(Uci->board));

   // more init

   start = 0;
   end = game_pos(Game);
   ASSERT(end>=start);

   // position

   game_get_board(Game,board,start);
   board_to_fen(board,string,256);

   engine_send_queue(Engine,"position");

   if (my_string_equal(string,StartFen)) {
      engine_send_queue(Engine," startpos");
   } else {
      engine_send_queue(Engine," fen %s",string);
   }

   // move list

   if (end > start || extra_move != MoveNone) engine_send_queue(Engine," moves");

   for (pos = start; pos < end; pos++) { // game moves

      move = game_move(Game,pos);

      move_to_can(move,board,string,256);
      engine_send_queue(Engine," %s",string);

      move_do(board,move);
   }

   if (extra_move != MoveNone) { // move to ponder on
      move_to_can(extra_move,board,string,256);
      engine_send_queue(Engine," %s",string);
   }

   // end

   engine_send(Engine,""); // newline
}
Example #23
0
static int full_quiescence(board_t * board, int alpha, int beta, int depth, int height, mv_t pv[]) {

   bool in_check;
   int old_alpha;
   int value, best_value;
   int best_move;
   int move;
   int opt_value;
   attack_t attack[1];
   sort_t sort[1];
   undo_t undo[1];
   mv_t new_pv[HeightMax];
   int cd;

   ASSERT(board!=NULL);
   ASSERT(range_is_ok(alpha,beta));
   ASSERT(depth_is_ok(depth));
   ASSERT(height_is_ok(height));
   ASSERT(pv!=NULL);

   ASSERT(board_is_legal(board));
   ASSERT(depth<=0);

   // init

   SearchStack[height].best_move = MoveNone;
   SearchStack[height].move = MoveNone;
   SearchStack[height].threat_move = MoveNone;
   SearchStack[height].reduced = false;

   SearchCurrent->node_nb++;
   SearchInfo->check_nb--;
   PV_CLEAR(pv);

   if (height > SearchCurrent->max_depth) SearchCurrent->max_depth = height;

   if (SearchInfo->check_nb <= 0) {
      SearchInfo->check_nb += SearchInfo->check_inc;
      search_check();
   }

   // draw?

   if (board_is_repetition(board) || recog_draw(board)) return ValueDraw;

   // mate-distance pruning

   if (UseDistancePruning) {

      // lower bound

      value = VALUE_MATE(height+2); // does not work if the current position is mate
      if (value > alpha && board_is_mate(board)) value = VALUE_MATE(height);

      if (value > alpha) {
         alpha = value;
         if (value >= beta) return value;
      }

      // upper bound

      value = -VALUE_MATE(height+1);

      if (value < beta) {
         beta = value;
         if (value <= alpha) return value;
      }
   }

   // more init

   attack_set(attack,board);
   in_check = ATTACK_IN_CHECK(attack);

   if (in_check) {
      ASSERT(depth<0);
      depth++; // in-check extension
   }

   // height limit

   if (height >= HeightMax-1) return eval(board, alpha, beta);

   // more init

   old_alpha = alpha;
   best_value = ValueNone;
   best_move = MoveNone;

   /* if (UseDelta) */ opt_value = +ValueInf;

   if (!in_check) {

      // lone-king stalemate?

      if (simple_stalemate(board)) return ValueDraw;

      // stand pat

      value = eval(board, alpha, beta);

      ASSERT(value>best_value);
      best_value = value;
      if (value > alpha) {
         alpha = value;
         if (value >= beta) goto cut;
      }

      if (UseDelta) {
         opt_value = value + DeltaMargin;
         ASSERT(opt_value<+ValueInf);
      }
   }

   // move loop

/*    cd = CheckDepth;
   if(cd < 0 && board->piece_size[board->turn] <= 5)
	   cd++; */

   sort_init_qs(sort,board,attack, depth>=CheckDepth /* depth>=cd */);

   while ((move=sort_next_qs(sort)) != MoveNone) {

	  SearchStack[height].move = move;

      // delta pruning

      if (UseDelta && beta == old_alpha+1) {

         if (!in_check && !move_is_check(move,board) && !capture_is_dangerous(move,board)) {

            ASSERT(move_is_tactical(move,board));

            // optimistic evaluation

            value = opt_value;

            int to = MOVE_TO(move);
            int capture = board->square[to];

            if (capture != Empty) {
               value += VALUE_PIECE(capture);
            } else if (MOVE_IS_EN_PASSANT(move)) {
               value += ValuePawn;
            }

            if (MOVE_IS_PROMOTE(move)) value += ValueQueen - ValuePawn;

            // pruning

            if (value <= alpha) {

               if (value > best_value) {
                  best_value = value;
                  PV_CLEAR(pv);
               }

               continue;
            }
         }
      }

      move_do(board,move,undo);
      value = -full_quiescence(board,-beta,-alpha,depth-1,height+1,new_pv);
      move_undo(board,move,undo);

      if (value > best_value) {
         best_value = value;
         pv_cat(pv,new_pv,move);
         if (value > alpha) {
            alpha = value;
            best_move = move;
			SearchStack[height].best_move = move;
            if (value >= beta) goto cut;
         }
      }
   }

   // ALL node

   if (best_value == ValueNone) { // no legal move
      ASSERT(board_is_mate(board));
      return VALUE_MATE(height);
   }

cut:

   ASSERT(value_is_ok(best_value));

   return best_value;
}
Example #24
0
void TEngine::ParseLine(char *line)
{
  char *cur_word = get_cur_word_str(&line);
  if (!string_equal(cur_word,"info"))
    return;
  bool pv_mode = false;
  int pv_num = 0;
  undo_t undo;
  if (LastMove)
    move_do(&Board,LastMove,&undo);

  bool pv_exists = false;

  while (line) {
      cur_word = get_cur_word_str(&line);
      switch (strlen(cur_word)) {
         case 2:
           if (string_equal(cur_word,"pv")) {
              PV[pv_num].pv_len = 0;
              pv_mode = true;
              pv_exists = true;
              break;
           }
           break;
         case 3:
           if (string_equal(cur_word,"nps")) {
              get_cur_word_int(&line);
              break;
           }
           break;
         case 4:
           if (string_equal(cur_word,"time")) {
              get_cur_word_int(&line);
              break;
           }
           if (pv_mode) {
             int pv_len = PV[pv_num].pv_len;
             mv_t m = move_from_string(cur_word,&Board);
             PV[pv_num].moves[pv_len] = m;
             move_do(&Board,m,&PV[pv_num].undo[pv_len]);
             PV[pv_num].pv_len++;
           }
           break;
         case 5:
           if (string_equal(cur_word,"depth")) {
              get_cur_word_int(&line);
              break;
           }
           if (string_equal(cur_word,"nodes")) {
              get_cur_word_int(&line);
              break;
           }
           if (string_equal(cur_word,"score")) {
              cur_word = get_cur_word_str(&line);
              if (string_equal(cur_word,"cp")) {
                 int score = get_cur_word_int(&line);
                 if (Board.turn == Black)
                   score = -score;
                 float f = score;
                 f /= 100;
                 sprintf(PV[pv_num].score,"(%-.2f)",f);
                 break;
              }
              if (string_equal(cur_word,"mate")) {
                 cur_word = get_cur_word_str(&line);
                 strcpy(PV[pv_num].score,"mate ");
                 strcat(PV[pv_num].score,cur_word);
                 break;
              }
              if (string_equal(cur_word,"lowerbound")) {
                 cur_word = get_cur_word_str(&line);
                 strcpy(PV[pv_num].score,"lowerbound ");
                 strcat(PV[pv_num].score,cur_word);
                 break;
              }
              if (string_equal(cur_word,"upperbound")) {
                 cur_word = get_cur_word_str(&line);
                 strcpy(PV[pv_num].score,"upperbound ");
                 strcat(PV[pv_num].score,cur_word);
                 break;
              }
              break;
           }
           if (pv_mode) {
             int pv_len = PV[pv_num].pv_len;
             mv_t m = move_from_string(cur_word,&Board);
             PV[pv_num].moves[pv_len] = m;
             move_do(&Board,m,&PV[pv_num].undo[pv_len]);
             PV[pv_num].pv_len++;
           }
           break;
         case 6:
           if (string_equal(cur_word,"tbhits")) {
               get_cur_word_int(&line);
               break;
           }
           if (string_equal(cur_word,"string"))
               return;
           break;
         case 7:
           if (string_equal(cur_word,"multipv")) {
               pv_num = get_cur_word_int(&line) - 1;
               if (pv_num > pv_cur_cnt)
                 pv_cur_cnt = pv_num;
               break;
           }
           if (string_equal(cur_word,"cpuload")) {
               get_cur_word_int(&line);
               break;
           }
           break;
         case 8:
           if (string_equal(cur_word,"seldepth")) {
               get_cur_word_int(&line);
               break;
           }
           if (string_equal(cur_word,"currmove")) {
               get_cur_word_str(&line);
               break;
           }
           if (string_equal(cur_word,"hashfull")) {
               get_cur_word_int(&line);
               break;
           }
           break;
         case 14:
           if (string_equal(cur_word,"currmovenumber")) {
               get_cur_word_int(&line);
               break;
           }
      }
  }

  if (pv_exists)
    for (int i=PV[pv_num].pv_len-1; i>=0; i--)
      move_undo(&Board,PV[pv_num].moves[i],&PV[pv_num].undo[i]);

  if (LastMove)
    move_undo(&Board,LastMove,&undo);
}
Example #25
0
static int full_search(board_t * board, int alpha, int beta, int depth, int height, mv_t pv[], int node_type) {

   bool in_check;
   bool single_reply;
   bool mate_threat;
   int trans_move, trans_depth, trans_min_depth, trans_max_depth, trans_min_value, trans_max_value;
   int min_value, max_value;
   int old_alpha;
   int value, best_value;
   int move, best_move;
   int new_depth;
   int played_nb;
   int i;
   int opt_value;
   bool reduced;
   int mb;
   attack_t attack[1];
   sort_t sort[1];
   undo_t undo[1];
   mv_t new_pv[HeightMax];
   mv_t played[256];
   int FutilityMargin;

   ASSERT(board!=NULL);
   ASSERT(range_is_ok(alpha,beta));
   ASSERT(depth_is_ok(depth));
   ASSERT(height_is_ok(height));
   ASSERT(pv!=NULL);
   ASSERT(node_type==NodePV||node_type==NodeCut||node_type==NodeAll);

   ASSERT(board_is_legal(board));

   // horizon?

   if (depth <= 0){
	   if (node_type == NodePV)
			CheckDepth = 1 - CheckNb - 1;
	   else
			CheckDepth = 1 - CheckNb;
	   return full_quiescence(board,alpha,beta,0,height,pv);
   }

   // init

   SearchStack[height].best_move = MoveNone;
   SearchStack[height].move = MoveNone;
   SearchStack[height].threat_move = MoveNone;
   SearchStack[height].reduced = false;
   mate_threat = false;

   SearchCurrent->node_nb++;
   SearchInfo->check_nb--;
   PV_CLEAR(pv);

   if (height > SearchCurrent->max_depth) SearchCurrent->max_depth = height;

   if (SearchInfo->check_nb <= 0) {
      SearchInfo->check_nb += SearchInfo->check_inc;
      search_check();
   }

   // draw?

   if (board_is_repetition(board) || recog_draw(board)) return ValueDraw;

   // mate-distance pruning

   if (UseDistancePruning) {

      // lower bound

      value = VALUE_MATE(height+2); // does not work if the current position is mate
      if (value > alpha && board_is_mate(board)) value = VALUE_MATE(height);

      if (value > alpha) {
         alpha = value;
         if (value >= beta) return value;
      }

      // upper bound

      value = -VALUE_MATE(height+1);

      if (value < beta) {
         beta = value;
         if (value <= alpha) return value;
      }
   }

   // transposition table

   trans_move = MoveNone;

   if (UseTrans && depth >= TransDepth) {

      if (trans_retrieve(Trans,board->key,&trans_move,&trans_min_depth,&trans_max_depth,&trans_min_value,&trans_max_value)) {

         // trans_move is now updated

         if (node_type != NodePV) {

            if (UseMateValues) {

               if (trans_min_value > +ValueEvalInf && trans_min_depth < depth) {
                  trans_min_depth = depth;
               }

               if (trans_max_value < -ValueEvalInf && trans_max_depth < depth) {
                  trans_max_depth = depth;
               }
            }

            min_value = -ValueInf;

            if (DEPTH_MATCH(trans_min_depth,depth)) {
               min_value = value_from_trans(trans_min_value,height);
               if (min_value >= beta) return min_value;
            }

            max_value = +ValueInf;

            if (DEPTH_MATCH(trans_max_depth,depth)) {
               max_value = value_from_trans(trans_max_value,height);
               if (max_value <= alpha) return max_value;
            }

            if (min_value == max_value) return min_value; // exact match
         }
      }
   }

   // height limit

   if (height >= HeightMax-1) return eval(board, alpha, beta);

   // more init

   old_alpha = alpha;
   best_value = ValueNone;
   best_move = MoveNone;
   played_nb = 0;

   attack_set(attack,board);
   in_check = ATTACK_IN_CHECK(attack);

   // null-move pruning

   if (UseNull && depth >= NullDepth && node_type != NodePV) {

      if (!in_check
       && !value_is_mate(beta)
       && do_null(board)
       && (!UseNullEval || depth <= NullReduction+1 || eval(board,alpha, beta) >= beta)) {

         // null-move search
		 
         new_depth = depth - NullReduction - 1;
		 //new_depth = depth - R_adpt(board->piece_size[board->turn]+board->pawn_size[board->turn],depth,NullReduction) - 1;
		 
	     move_do_null(board,undo);
         value = -full_search(board,-beta,-beta+1,new_depth,height+1,new_pv,NODE_OPP(node_type));
         move_undo_null(board,undo);

         // verification search

         if (UseVer && depth > VerReduction) {

            if (value >= beta && (!UseVerEndgame || do_ver(board))) {

               new_depth = depth - VerReduction;
               ASSERT(new_depth>0);

               value = full_no_null(board,alpha,beta,new_depth,height,new_pv,NodeCut,trans_move,&move);

               if (value >= beta) {
                  ASSERT(move==new_pv[0]);
                  played[played_nb++] = move;
                  best_move = move;
				  SearchStack[height].move = move;
				  SearchStack[height].best_move = move;
                  best_value = value;
                  pv_copy(pv,new_pv);
                  goto cut;
               }
            }
         }

         // pruning

         if (value >= beta) {

            if (value > +ValueEvalInf) value = +ValueEvalInf; // do not return unproven mates
            ASSERT(!value_is_mate(value));

            // pv_cat(pv,new_pv,MoveNull);

            best_move = MoveNone;
            best_value = value;
            goto cut;
         }
		 SearchStack[height].threat_move = SearchStack[height+1].best_move;
	/*	 if (SearchStack[height-1].reduced){ // Idea by Tord Romstad 
				if (MOVE_FROM(SearchStack[height+1].best_move) == MOVE_TO(SearchStack[height-1].move))
					return alpha-1; */
		    	/* if(((MOVE_TO(SearchStack[height - 2].threat_move) == MOVE_FROM(SearchStack[height - 2].move))
					&& (MOVE_TO(SearchStack[height].threat_move) == MOVE_TO(SearchStack[height - 2].move)))
				  ||
				  ((MOVE_TO(SearchStack[height - 2].threat_move) != MOVE_FROM(SearchStack[height - 2].move))
		            && (MOVE_TO(SearchStack[height].threat_move) == MOVE_TO(SearchStack[height - 2].threat_move))))
			        return alpha-1; */
	//	 }
	  }
   }

   // mate threat 
/*   mate_threat = false;
   if (value <= VALUE_MATE(height+2)){ 
			mate_threat = true;
   } */

   // Internal Iterative Deepening
   
   if (UseIID && depth >= IIDDepth && node_type == NodePV && trans_move == MoveNone) {

      // new_depth = depth - IIDReduction;
	  new_depth = MIN(depth - IIDReduction,depth/2);
      ASSERT(new_depth>0);

      value = full_search(board,alpha,beta,new_depth,height,new_pv,node_type);
      if (value <= alpha) value = full_search(board,-ValueInf,beta,new_depth,height,new_pv,node_type);

      trans_move = new_pv[0];
   }

   // move generation

   sort_init(sort,board,attack,depth,height,trans_move);

   single_reply = false;
   if (in_check && LIST_SIZE(sort->list) == 1) single_reply = true; // HACK

   // move loop

   opt_value = +ValueInf;

   while ((move=sort_next(sort)) != MoveNone) {

	  SearchStack[height].move = move;

	  // history_tried(move,board);
	  
      // extensions

      new_depth = full_new_depth(depth,move,board,single_reply,mate_threat,node_type==NodePV, height);
	  
      // futility pruning

	  if (UseFutility && depth <= 2 && node_type != NodePV) {
		  
         if (!in_check && new_depth < depth && !move_is_tactical(move,board) && !move_is_dangerous(move,board)) {

            ASSERT(!move_is_check(move,board));

            // optimistic evaluation

            if (opt_value == +ValueInf) {
				if (depth==2){
					FutilityMargin = FutilityMargin2;
				}
				else{
					FutilityMargin = FutilityMargin1;
				}
				opt_value = eval(board,alpha,beta) + FutilityMargin;
				ASSERT(opt_value<+ValueInf);
            }

            value = opt_value;

            // pruning

            if (value <= alpha) {

               if (value > best_value) {
                  best_value = value;
                  PV_CLEAR(pv);
               }

               continue;
            }
         }
      } 

	  // history pruning

/*      reduced = false;

      if (UseHistory && depth >= HistoryDepth && node_type != NodePV) {
         if (!in_check && played_nb >= HistoryMoveNb && new_depth < depth) {
            ASSERT(best_value!=ValueNone);
            ASSERT(played_nb>0);
            ASSERT(sort->pos>0&&move==LIST_MOVE(sort->list,sort->pos-1));
            if (history_reduction(move,board) == true) {
               ASSERT(value>=0&&value<16384);
               ASSERT(move!=trans_move);
               ASSERT(!move_is_tactical(move,board));
               ASSERT(!move_is_check(move,board));
               new_depth--;
               reduced = true;
            }
         }
      } */

	  // history pruning

      reduced = false;
	  value = sort->value; // history score
      if (!in_check && depth < SearchCurrent->max_extensions / 2 && node_type != NodePV && new_depth < depth && value < HistoryValue / depth) 
		  continue;


      if (UseHistory && depth >= HistoryDepth && node_type != NodePV) {
         if (!in_check && played_nb >= HistoryMoveNb && new_depth < depth) {
            ASSERT(best_value!=ValueNone);
            ASSERT(played_nb>0);
            ASSERT(sort->pos>0&&move==LIST_MOVE(sort->list,sort->pos-1));
            value = sort->value; // history score
            if (value < HistoryValue) {
               ASSERT(value>=0&&value<16384);
               ASSERT(move!=trans_move);
               ASSERT(!move_is_tactical(move,board));
               ASSERT(!move_is_check(move,board));
               new_depth--;
               reduced = true;
			   if (UseExtendedHistory && value < HistoryValue / 2 && depth >= 8){
				   new_depth--;
				   
			   }
            }
         }
      }   

	  SearchStack[height].reduced = reduced;

      // recursive search

	  move_do(board,move,undo);

      if (node_type != NodePV || best_value == ValueNone) { // first move
		 value = -full_search(board,-beta,-alpha,new_depth,height+1,new_pv,NODE_OPP(node_type));
      } else { // other moves
		 value = -full_search(board,-alpha-1,-alpha,new_depth,height+1,new_pv,NodeCut);
         if (value > alpha) { // && value < beta
			value = -full_search(board,-beta,-alpha,new_depth,height+1,new_pv,NodePV);
         }
      }

      // history-pruning re-search

	  if (HistoryReSearch && reduced && value > alpha /* was >= beta */) {

         ASSERT(node_type!=NodePV);

		 //history_very_bad(move,board);
		 SearchStack[height].reduced = false;
         new_depth++;
         ASSERT(new_depth==depth-1);
		 
         value = -full_search(board,-beta,-alpha,new_depth,height+1,new_pv,NODE_OPP(node_type));
      } 

      move_undo(board,move,undo);

      played[played_nb++] = move;

      if (value > best_value) {
         best_value = value;
         pv_cat(pv,new_pv,move);
         if (value > alpha) {
            alpha = value;
            best_move = move;
			SearchStack[height].best_move = move;
            if (value >= beta){ 
				// history_success(move,board);
				goto cut;
			}
         }
      }

      if (node_type == NodeCut) node_type = NodeAll;
   }

   // ALL node

   if (best_value == ValueNone) { // no legal move
      if (in_check) {
         ASSERT(board_is_mate(board));
         return VALUE_MATE(height);
      } else {
         ASSERT(board_is_stalemate(board));
         return ValueDraw;
      }
   }

cut:

   ASSERT(value_is_ok(best_value));

   // move ordering

   if (best_move != MoveNone) {

      good_move(best_move,board,depth,height);

      if (best_value >= beta && !move_is_tactical(best_move,board)) {

		 ASSERT(played_nb>0&&played[played_nb-1]==best_move);

         for (i = 0; i < played_nb-1; i++) {
            move = played[i];
            ASSERT(move!=best_move);
            history_bad(move,board);
         }

         history_good(best_move,board);
      }
   }

   // transposition table

   if (UseTrans && depth >= TransDepth) {

      trans_move = best_move;
      trans_depth = depth;
      trans_min_value = (best_value > old_alpha) ? value_to_trans(best_value,height) : -ValueInf;
      trans_max_value = (best_value < beta)      ? value_to_trans(best_value,height) : +ValueInf;

      trans_store(Trans,board->key,trans_move,trans_depth,trans_min_value,trans_max_value);
   }

   return best_value;
}
Example #26
0
int main(int argc, char *argv[])
	{
	precompute();
#ifdef USE_HASH
	hash_init();
#endif
	// load_endgames();
//	load_bitbases();
	if (argc == 2 && !strcmp(argv[1], "nobook"))
		{
		printf("Skipping opening book\n");
		}
	else if (argc == 2 && !strcmp(argv[1], "makebook"))
		{
		load_opening_book(1);
		opening_book_grow(0);
		return 0;
		}
	else if (argc == 2 && !strcmp(argv[1], "showbook"))
		{
		load_opening_book(1);
		opening_book_grow(1);
		return 0;
		}
	else
		load_opening_book(2);
	new_game();

	int ply;

	int i, j, k;

	FILE * input;
	FILE * output;

	char command[80] = "";
	char buffer[4100] = "";


/*	if (argc == 2 && !strcmp(argv[1], "files"))
		{
		printf("Using files for I/O\n");
		input = fopen("input.txt", "r+");
		output = fopen("output.txt", "w");
		}
	else */
		{
		input = stdin;
		output = stdout;
		}

	if (argc == 2 && !strcmp(argv[1], "bitbases"))
		{
		bitbase_report();
		return 0;
		}

	if (argc == 7 && !strcmp(argv[1], "position"))
		{
		i = bitbase_test(
			atoi(argv[2])
			,atoi(argv[3])
			,atoi(argv[4])
			,atoi(argv[5])
			,atoi(argv[6])
			);
		printf("%s\n", i ? "is a win for black" : "not a win for black");

		int pieces[MAX_BDB_PIECES];
		int total_pieces = 0;

		for (i = 0; i < atoi(argv[2]); ++i) pieces[total_pieces++] = 0;
		for (i = 0; i < atoi(argv[3]); ++i) pieces[total_pieces++] = 1;
		for (i = 0; i < atoi(argv[4]); ++i) pieces[total_pieces++] = 2;
		for (i = 0; i < atoi(argv[5]); ++i) pieces[total_pieces++] = 3;

		position_decode(atoi(argv[6]), pieces, total_pieces);

		print_board(0);

		return 0;
		}

	if (argc == 2 && !strcmp(argv[1], "sanity"))
		{
		sanity_checks();
		memory_report();
		return 0;
		}

	if (argc == 2 && !strcmp(argv[1], "perft"))
		{
		iterative_performance_test();
#ifdef SORT_STATISTIC
	for (i = 0; i < 5; ++i)
		printf("Returns at sort level %d: %d\n"
			, i
			, sort_statistic[i]);
#endif
		return 0;
		}

	if (argc >= 4 && !strcmp(argv[1], "pdn"))
		{
		ply = 0;

		FILE * pdn;

		pdn = fopen(argv[3], "a+");
		if (!pdn)
			{
			printf("error: fopen \"%s\" for append/create\n", argv[3]);
			// printf("err: %d - %s\n", errno, strerror(errno));
			// getcwd(buffer, sizeof(buffer));
			// printf("pwd: %s\n", buffer);
			return 1;
			}
		while (!feof(pdn)) // fixme: this loader sux...
			{
			if (!fgets(buffer, 4096, pdn))
				break;

			//if (!buffer || feof(pdn))
			//	break;

			i = 0;
			while (j = load_move_from_pdn(buffer, command, &i))
				{
				generate_moves(0, 0);
				k = find_move(0, command);
				if (k < 0 || k >= move_counter[0])
					{
					fprintf(output, "error invalid move from pdn (%s)\n"
						, command);
					for (k = 0; k < move_counter[0]; ++k)
						{
						fprintf(output, "move %d ",k);
						print_move(&moves[0][k], 0);
						fprintf(output, "\n");
						}
					}
				else
					{
					++ply;
					//fprintf(output, "executing move at index %d: ", k);
					if (!strcmp(argv[2], "show") || !strcmp(argv[2], "step"))
						{
						if (ply % 2 == 1)
							printf("%3d. ", (ply+1) / 2);
						print_move(&moves[0][k], 0);
						if (ply % 2 == 0)
							{
							printf("\n");
							//print_board(0);
							}
						else
							printf(" ");
						if (!strcmp(argv[2], "step") && ply % 2 == 0)
							{
							print_board(0);
							getc(stdin);
							}
						}
					//fprintf(output, "\n");
					move_do(&moves[0][k], 0);
					move_list_push(&moves[0][k]);
					}
				}
			if (feof(pdn))
				break;
			}
		fclose(pdn);

		if (!strcmp(argv[2], "play"))
			{
			pdn = fopen(argv[3], "a");
			if (!pdn)
				{
				printf("error: fopen \"%s\" for append\n", argv[3]);
				return 1;
				}

			if (argc >= 5 && strcmp(argv[4], "hint") && strcmp(argv[4], "move"))
				{
				generate_moves(0, 0);
				i = find_move(0, argv[4]);
				if (i < 0 || i >= move_counter[0])
					{
					print_moves(0);
					i = -1;
					}
				else
					{
					move_do(&moves[0][i], 0);
					move_list_push(&moves[0][i]);
					fprintf(pdn, "%s ", argv[4]);
					if (moves[0][i].same_player_square != -1)
						i = -1;
					}
				}

			if (i != -1)
				{
				if (argc >= 6)
					strength = atoi(argv[5]);
				if (argc >= 7)
					thinking_time = atoi(argv[6]);

				if (strength == 1)
					thinking_time = 1;

				if (!strcmp(argv[4], "hint"))
					bestmove(0, 0);
				else
					while (bestmove(pdn, 1));
				}

			fclose(pdn);
			fprintf(output, "boardok ");
			for (i = 0; i < 64; ++i)
				fprintf(output, "%d", board[i]);
			fprintf(output, " %d", state.tactical_square);
			fprintf(output, " %d", state.side_to_move);
			fprintf(output, " %d", state.this_piece_must_take);
			fprintf(output, "\n");
			}
		else
			{
			print_board(0);
//debug_moves = 1;
			generate_moves(0, 0);
			if (!strcmp(argv[2], "show"))
				print_moves(0);
			}

		if (!strcmp(argv[2], "load"))
			{
			printf("PDN loaded\n");
			command[0] = 0;
			buffer[0] = 0;
			}
		else
			return 0;
		}

	for (;;)
		{
		fscanf(input, "%20s", command);

		if (parse(command, "quit"))
			break;
		else if (parse(command, "gnt"))
			fprintf(output, "id name GNTredux\nid author QuakePhil\ngntok\n");
		else if (parse(command, "new"))
			new_game();
		else if (parse(command, "flipside"))
			state.side_to_move ^= 1;
		else if (parse(command, "flipkings"))
			{
			for (i = 0; i < 64; ++i) if (initial_board[i] != 4)
				{
				if (initial_board[i] < 2)
					initial_board[i] += 2;
				else
					initial_board[i] -= 2;
				}
			new_game();
			}
		else if (parse(command, "flipboardonly"))
			{ // fixme: need to re-do materials here?
			int temp[64];
			int flip_piece[5] = {1,0,3,2,4};
			j = 64;
			for (i = 0; i < 64; ++i)
				temp[--j] = flip_piece[board[i]];
			for (i = 0; i < 64; ++i)
				board[i] = temp[i];
			state.side_to_move ^= 1;
			}
		else if (parse(command, "rand"))
			rand_board();
		else if (parse(command, "think"))
			{
			bestmove(0, 0);
			}
		else if (parse(command, "go"))
			{
			bestmove(0, 1);
			}
		else if (parse(command, "perft"))
			{
			iterative_performance_test();
			}
		else if (parse(command, "ping"))
			{
			fprintf(output, "pong %.6lf\n", timer());
			}
		else if (parse(command, "pboard"))
			print_board(0);
		else if (parse(command, "board"))
			{
			fprintf(output, "boardok ");
			for (i = 0; i < 64; ++i)
				fprintf(output, "%d", board[i]);
			fprintf(output, " %d", state.tactical_square);
			fprintf(output, " %d", state.side_to_move);
			fprintf(output, " %d", state.this_piece_must_take);
			fprintf(output, "\n");
			}
		else if (parse(command, "time"))
			{
			fscanf(input, "%d", &thinking_time);
			printf("Think time limit set to: %d seconds\n", thinking_time);
			}
		else if (parse(command, "pdn"))
			{
			fscanf(input, "%20s", buffer);
			generate_moves(0, 0);
			i = find_move(0, buffer);
			if (i < 0 || i >= move_counter[0])
				fprintf(output, "error invalid move\n");
			else
				{
				move_do(&moves[0][i], 0);
				move_list_push(&moves[0][i]);
				//fprintf(output, "executing move at index %d: ", i);
				//print_move(&moves[0][i], 0);
				//fprintf(output, "\n");
				fprintf(output, "done\n");
				}
			}
		else if (parse(command, "do") || parse(command, "toggle"))
			{
			fscanf(input, "%d", &i);
			fprintf(output, "executing move %d\n", i);
			generate_moves(0, 0);
			if (i < 0)
				fprintf(output, "error move can't be negative\n");
			else if (i >= move_counter[0])
				fprintf(output, "error no such move\n");
			else
				{
				move_do(&moves[0][i], 0);
				move_list_push(&moves[0][i]);

				if (parse(command, "toggle"))
					{
					print_board(0);
					fprintf(output, "undoing move %d\n", i);
					move_undo(&moves[0][i], 0);
					print_board(0);
					}
				}
			fprintf(output, "done\n");
			}
		else if (parse(command, "list"))
			{
			print_move_list();
			}
		else if (parse(command, "pbook"))
			{
			print_book();
			}
		else if (parse(command, "moves"))
			{
			generate_moves(0, 0);
			for (i = 0; i < move_counter[0]; ++i)
				{
				fprintf(output, "move %d ",i);
				print_move(&moves[0][i], 1);
				fprintf(output, "\n");
				}
			fprintf(output, "movesok\n");
			}
		else // if (!strcmp(command, "help"))
			{
			// fprintf(output, "?\n");
			}

		fflush(output);
		}

#ifdef HASH_STATISTIC
	printf("Hash saves:      %d\n", hash_saves);
	printf("Hash collisions: %d\n", hash_collisions);
	printf("Hash probes:     %d\n", hash_probes);
	printf("Hash hits:       %d\n", hash_hits);
#endif

#ifdef SORT_STATISTIC
	for (i = 0; i < 5; ++i)
		printf("Returns at sort level %d: %d\n"
			, i
			, sort_statistic[i]);
#endif

	fclose(output);
	fclose(input);

	return 0;
	}
Example #27
0
static int full_no_null(board_t * board, int alpha, int beta, int depth, int height, mv_t pv[], int node_type, int trans_move, int * best_move) {

   int value, best_value;
   int move;
   int new_depth;
   attack_t attack[1];
   sort_t sort[1];
   undo_t undo[1];
   mv_t new_pv[HeightMax];

   ASSERT(board!=NULL);
   ASSERT(range_is_ok(alpha,beta));
   ASSERT(depth_is_ok(depth));
   ASSERT(height_is_ok(height));
   ASSERT(pv!=NULL);
   ASSERT(node_type==NodePV||node_type==NodeCut||node_type==NodeAll);
   ASSERT(trans_move==MoveNone||move_is_ok(trans_move));
   ASSERT(best_move!=NULL);

   ASSERT(board_is_legal(board));
   ASSERT(!board_is_check(board));
   ASSERT(depth>=1);

   // init

   SearchStack[height].best_move = MoveNone;
   SearchStack[height].move = MoveNone;
   SearchStack[height].threat_move = MoveNone;
   SearchStack[height].reduced = false;

   SearchCurrent->node_nb++;
   SearchInfo->check_nb--;
   PV_CLEAR(pv);

   if (height > SearchCurrent->max_depth) SearchCurrent->max_depth = height;

   if (SearchInfo->check_nb <= 0) {
      SearchInfo->check_nb += SearchInfo->check_inc;
      search_check();
   }

   attack_set(attack,board);
   ASSERT(!ATTACK_IN_CHECK(attack));

   *best_move = MoveNone;
   best_value = ValueNone;

   // move loop

   sort_init(sort,board,attack,depth,height,trans_move);

   while ((move=sort_next(sort)) != MoveNone) {

	  SearchStack[height].move = move;

      new_depth = full_new_depth(depth,move,board,false,false,false,height);

      move_do(board,move,undo);
      value = -full_search(board,-beta,-alpha,new_depth,height+1,new_pv,NODE_OPP(node_type));
      move_undo(board,move,undo);

      if (value > best_value) {
         best_value = value;
         pv_cat(pv,new_pv,move);
         if (value > alpha) {
            alpha = value;
            *best_move = move;
			SearchStack[height].best_move = move;
            if (value >= beta) goto cut;
         }
      }
   }

   // ALL node

   if (best_value == ValueNone) { // no legal move => stalemate
      ASSERT(board_is_stalemate(board));
      best_value = ValueDraw;
   }

cut:

   ASSERT(value_is_ok(best_value));

   return best_value;
}
Example #28
0
static void search_update() {

   int move;
   int move_nb;
   board_t board[1];

   ASSERT(!Uci->searching);



   
   // launch a new search if needed

   

   if (State->state == THINK || State->state == PONDER || State->state == ANALYSE) {

      // [VdB] moved up as we need the move number

       game_get_board(Game,Uci->board);

      // opening book

       if (State->state == THINK &&
           option_get_bool(Option,"Book") &&
           Uci->board->move_nb<option_get_int(Option,"BookDepth")
           ) {


         move = book_move(Uci->board,option_get_bool(Option,"BookRandom"));

         if (move != MoveNone && move_is_legal(move,Uci->board)) {

            my_log("POLYGLOT *BOOK MOVE*\n");

            search_clear(); // clears Uci->ponder_move
            Uci->best_move = move;

            board_copy(board,Uci->board);
            move_do(board,move);
            Uci->ponder_move = book_move(board,FALSE); // expected move = best book move

            Uci->best_pv[0] = Uci->best_move;
            Uci->best_pv[1] = Uci->ponder_move; // can be MoveNone
            Uci->best_pv[2] = MoveNone;

            comp_move(Uci->best_move);

            return;
         }
      }

      // engine search

      my_log("POLYGLOT START SEARCH\n");

      // options

      uci_send_option(Uci,"UCI_3Check","%s",
                      option_get_bool(Option,"3Check")?"true":"false");
      uci_send_option(Uci,"UCI_Chess960","%s",
                      option_get_bool(Option,"Chess960")?"true":"false");
      uci_send_option(Uci,"UCI_Atomic","%s",
                      option_get_bool(Option,"Atomic")?"true":"false");
      uci_send_option(Uci,"UCI_Horde","%s",
                      option_get_bool(Option,"Horde")?"true":"false");

      if (option_get_int(Option,"UCIVersion") >= 2) {
         uci_send_option(Uci,"UCI_Opponent","none none %s %s",(XB->computer)?"computer":"human",XB->name);
         uci_send_option(Uci,"UCI_AnalyseMode","%s",(XB->analyse)?"true":"false");
      }

      uci_send_option(Uci,"Ponder","%s",ponder()?"true":"false");

      // position

      move = (State->state == PONDER) ? State->exp_move : MoveNone;
      send_board(move); // updates Uci->board global variable

      // search

      if (State->state == THINK || State->state == PONDER) {

         engine_send_queue(Engine,"go");

         if (XB->time_limit) {

            // fixed time per move
             
             if(XB->node_rate > 0){
                 engine_send_queue(Engine,
                                   " nodes %.0f",
                                   XB->time_max*((double)XB->node_rate));
             }else{
		 double computed_time;
		 double st_fudge;
		 st_fudge=(double) option_get_int(Option,"STFudge");
		 my_log("POLYGLOT Giving engine %.0fmsec extra time.\n",st_fudge);
		 computed_time=XB->time_max*1000.0-st_fudge;
		 if(computed_time< 1.0){
		     computed_time=1.0;
		 }
                 engine_send_queue(Engine,
                                   " movetime %.0f",
                                   computed_time);
             }

         } else {

            // time controls

                 if(XB->node_rate > 0) {
                     double time;
                     move_nb = 40;
                     if (XB->mps != 0){
                         move_nb = XB->mps - (Uci->board->move_nb % XB->mps);
                     }
                     time = XB->my_time / move_nb;
                     if(XB->inc != 0){
                         time += XB->inc;
                     }
                     if(time > XB->my_time){
                         time = XB->my_time;
                     }
                     engine_send_queue(Engine,
                                       " nodes %.0f",
                                       time*XB->node_rate);
                 } else {
                     
                     if (colour_is_white(Uci->board->turn)) {
                         engine_send_queue(Engine,
                                           " wtime %.0f btime %.0f",
                                           XB->my_time*1000.0,XB->opp_time*1000.0);
                     } else {
                         engine_send_queue(Engine,
                                           " wtime %.0f btime %.0f",
                                           XB->opp_time*1000.0,XB->my_time*1000.0);
                     }
                     
                     if (XB->inc != 0.0){
                         engine_send_queue(Engine,
                                           " winc %.0f binc %.0f",
                                           XB->inc*1000.0,XB->inc*1000.0);
                     }
                     if (XB->mps != 0) {

                         move_nb = XB->mps - (Uci->board->move_nb % XB->mps);
                         ASSERT(move_nb>=1&&move_nb<=XB->mps);
                         
                         engine_send_queue(Engine," movestogo %d",move_nb);
                     }
                 }
         }
         if (XB->depth_limit) engine_send_queue(Engine," depth %d",XB->depth_max);

         if (State->state == PONDER) engine_send_queue(Engine," ponder");

         engine_send(Engine,""); // newline

      } else if (State->state == ANALYSE) {

         engine_send(Engine,"go infinite");

      } else {

         ASSERT(FALSE);
      }

      // init search info

      ASSERT(!Uci->searching);

      search_clear();

      Uci->searching = TRUE;
      Uci->pending_nb++;
   }
}
Example #29
0
bool TEngine::SearchPos(board_t * Board, TFindPos * fp, mv_t pv[], bool full)
{
   //------------------------
   if (Eval(Board,fp)) {
     pv[0] = 0;
     return true;
   }
   //-----------------------
   if (LastMove) {
      undo_t undo;
      move_do(Board,LastMove,&undo);
      bool eval = Eval(Board,fp);
      if (Eval(Board,fp)) {
         move_undo(Board,LastMove, &undo);
         pv[0] = LastMove;
         pv[1] = 0;
         return true;
      }
      list_t list;
      gen_legal_moves(&list,Board);
      for (int i=0; i<LIST_SIZE(&list); i++) {
         undo_t undo2;
         mv_t move2 = LIST_MOVE(&list,i);
         move_do(Board,move2,&undo2);
         bool eval = Eval(Board,fp);
         move_undo(Board,move2, &undo2);
         if (eval) {
             move_undo(Board,LastMove, &undo);
             pv[0] = LastMove;
             pv[1] = move2;
             pv[2] = 0;
             return true;;
         }
      }
      move_undo(Board,LastMove,&undo);
   }
   //----------------------------------------------------
   list_t list;
   gen_legal_moves(&list,Board);
   //----------------------------------------------------
   for (int i=0; i<LIST_SIZE(&list); i++) {
      undo_t undo;
      mv_t move = LIST_MOVE(&list,i);
      move_do(Board,move,&undo);
      bool eval = Eval(Board,fp);
      move_undo(Board,move,&undo);
      if (eval) {
         pv[0] = move;
         pv[1] = 0;
         return true;
      }
   }
   //------------------------------------------------------
   if (full) {
     for (int i=0; i<LIST_SIZE(&list); i++) {
        undo_t undo;
        mv_t move = LIST_MOVE(&list,i);
        move_do(Board,move,&undo);
        list_t list2;
        gen_legal_moves(&list2,Board);
        for (int j=0; j<LIST_SIZE(&list2); j++) {
           undo_t undo2;
           mv_t move2 = LIST_MOVE(&list2,j);
           move_do(Board,move2,&undo2);
           /*
           char s_move[6], s_move2[6];
           move_to_string(move,s_move,6);
           move_to_string(move2,s_move2,6);
           */
           bool eval = Eval(Board,fp);
           move_undo(Board,move2,&undo2);
           if (eval) {
              pv[0] = move;
              pv[1] = move2;
              pv[2] = 0;
              move_undo(Board,move,&undo);
              return true;
          }
        }
        move_undo(Board,move,&undo);
     }
   }
   //-------------------------------------------------------
   return false;
}
Example #30
0
static int full_quiescence(board_t * board, int alpha, int beta, int depth, int height, mv_t pv[], int ThreadId) {

   bool in_check;
   int old_alpha;
   int value, best_value;
   int best_move;
   int move;
   int opt_value;
   attack_t attack[1];
   sort_t sort[1];
   undo_t undo[1];
   mv_t new_pv[HeightMax];
   int probe_score, probe_depth;  
   int trans_move, trans_depth, trans_flags, trans_value;
   entry_t * found_entry;

   ASSERT(board!=NULL);
   ASSERT(range_is_ok(alpha,beta));
   ASSERT(depth_is_ok(depth));
   ASSERT(height_is_ok(height));
   ASSERT(pv!=NULL);

   ASSERT(board_is_legal(board));
   ASSERT(depth<=0);

   // init

   SearchCurrent[ThreadId]->node_nb++;
   SearchInfo[ThreadId]->check_nb--;
   PV_CLEAR(pv);

   if (height > SearchCurrent[ThreadId]->max_depth) SearchCurrent[ThreadId]->max_depth = height;

   if (SearchInfo[ThreadId]->check_nb <= 0) {
      SearchInfo[ThreadId]->check_nb += SearchInfo[ThreadId]->check_inc;
      search_check(ThreadId);
   }

   // draw?

   if (board_is_repetition(board)) return ValueDraw;

	/*
		Interior node recognizer from scorpio by Daniel Shawul
		-> dont probe at the leaves as this will slow down search
	    For 4/3 pieces probe there also.
		-> After captures and pawn moves assume exact score and cutoff tree,
	    because we are making progress. Note this is not done only for speed.
		-> if we are far from root (depth / 2), assume exact score and cutoff tree
	*/

/*	if (egbb_is_loaded && board->piece_nb <= 4){ 
		if (probe_bitbases(board, probe_score)){
			probe_score = value_from_trans(probe_score,height);
			return probe_score;
		}
	}*/

	if (recog_draw(board,ThreadId)) return ValueDraw;

   // mate-distance pruning

   if (UseDistancePruning) {

      // lower bound

      value = VALUE_MATE(height+2); // does not work if the current position is mate
      if (value > alpha && board_is_mate(board)) value = VALUE_MATE(height);

      if (value > alpha) {
         alpha = value;
         if (value >= beta) return value;
      }

      // upper bound

      value = -VALUE_MATE(height+1);

      if (value < beta) {
         beta = value;
         if (value <= alpha) return value;
      }
   }
   
   // transposition table: added by Jerry Donald, about +20 elo self-play
   // new in Toga II 4.0: accept hash hits in PV ~ +3 elo
   
   trans_move = MoveNone;
   
   if (UseTrans) { 

      if (trans_retrieve(Trans,&found_entry,board->key,&trans_move,&trans_depth,&trans_flags,&trans_value)) {

		 trans_value = value_from_trans(trans_value,height);

	 	 if ((UseExact && trans_value != ValueNone && TRANS_IS_EXACT(trans_flags)) 
		 	 || (TRANS_IS_LOWER(trans_flags) && trans_value >= beta)
			 || (TRANS_IS_UPPER(trans_flags) && trans_value <= alpha)) {
			 return trans_value;
		 } 
	  }
   }

   // more init

   attack_set(attack,board);
   in_check = ATTACK_IN_CHECK(attack);

   if (in_check) {
      ASSERT(depth<0);
      depth++; // in-check extension
   }

   // height limit

   if (height >= HeightMax-1) return eval(board, alpha, beta, ThreadId);

   // more init

   old_alpha = alpha;
   best_value = ValueNone;
   best_move = MoveNone;

   /* if (UseDelta) */ opt_value = +ValueInf;

   if (!in_check) {

      // lone-king stalemate?

      if (simple_stalemate(board)) return ValueDraw;

      // stand pat

      value = eval(board, alpha, beta, ThreadId);

      ASSERT(value>best_value);
      best_value = value;
      if (value > alpha) {
         alpha = value;
         if (value >= beta) goto cut;
      }

      if (UseDelta) {
         opt_value = value + DeltaMargin;
         ASSERT(opt_value<+ValueInf);
      }
   }

   // move loop

/*    cd = CheckDepth;
   if(cd < 0 && board->piece_size[board->turn] <= 5)
	   cd++; */

   sort_init_qs(sort,board,attack, depth>=SearchCurrent[ThreadId]->CheckDepth /* depth>=cd */);

   while ((move=sort_next_qs(sort)) != MoveNone) {

	  // delta pruning

      if (UseDelta && beta == old_alpha+1) { // i.e. non-PV

         if (!in_check && !move_is_check(move,board) && !capture_is_dangerous(move,board)) {

            ASSERT(move_is_tactical(move,board));

            // optimistic evaluation

            value = opt_value;

            int to = MOVE_TO(move);
            int capture = board->square[to];

            if (capture != Empty) {
               value += VALUE_PIECE(capture);
            } else if (MOVE_IS_EN_PASSANT(move)) {
               value += ValuePawn;
            }

            if (MOVE_IS_PROMOTE(move)) value += ValueQueen - ValuePawn;

            // pruning

            if (value <= alpha) {

               if (value > best_value) {
                  best_value = value;
                  PV_CLEAR(pv);
               }

               continue;
            }
         }
      }

      move_do(board,move,undo);
      value = -full_quiescence(board,-beta,-alpha,depth-1,height+1,new_pv,ThreadId);
      move_undo(board,move,undo);

      if (value > best_value) {
         best_value = value;
         pv_cat(pv,new_pv,move);
         if (value > alpha) {
            alpha = value;
            best_move = move;
			if (value >= beta) goto cut;
         }
      }
   }

   // ALL node

   if (best_value == ValueNone) { // no legal move
      ASSERT(board_is_mate(board));
      return VALUE_MATE(height);
   }

cut:
    
   // store result in hash table (JD)
    
   if (UseTrans) {

      trans_move = best_move;
      trans_depth = 0;
      trans_flags = TransUnknown;
      if (best_value > old_alpha) trans_flags |= TransLower;
      if (best_value < beta) trans_flags |= TransUpper;
      trans_value = value_to_trans(best_value,height);

      trans_store(Trans,board->key,trans_move,trans_depth,trans_flags,trans_value);

   }

   ASSERT(value_is_ok(best_value));

   return best_value;
}