int main (int argc, char *argv[])
{
    struct sortstate *sortp;
    char *linep, *tdirbuf;
    char *tmpdir = "/tmp";
    int  mem     = 128;
    int  par     = 1;


    for (;;) {
        int option_index = 0;
        int c;
        static struct option long_options[] = {
            {"tmpdir",   required_argument, 0, 'd'},
            {"mem",      required_argument, 0, 'm'},
            {"parallel", required_argument, 0, 'p'},
            {0, 0, 0, 0}
        };

        c = getopt_long(argc, argv, "t:",
                        long_options, &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'd':
            tmpdir = optarg;
            break;
        case 'm':
            mem = atol (optarg);
            break;
        case 'p':
            par = atol (optarg);
            break;
        default:
            printf("?? getopt returned character code 0%o ??\n", c);
        }
    }

    if (optind < argc)          error (argv[0], "Excess argument");

    if (mem < 1 || mem > 2048) error (argv[0], "Invalid --mem value");

    if (par < 1 || par > 16)   error (argv[0], "Invalid --par value");

    tdirbuf = malloc (strlen (tmpdir) + 16);
    sprintf (tdirbuf, "%s/sort-XXXXXX", tmpdir);

    linep = (char *)sort_init (&sortp, par, mem *1024 * 1024, stdin, tdirbuf, NULL);

    while (linep) {
        fputs (linep, stdout);
        linep = (char *)sort_nextline (sortp);
    }

    return 0;
}
Example #2
0
void search() {

   int move;
   int depth;
   int i;
   bool search_ready;

     
   for (i = 0; i < MultiPVMax; i++){
	  save_multipv[SearchCurrent->multipv].mate = 0;
	  save_multipv[SearchCurrent->multipv].depth = 0;
	  save_multipv[SearchCurrent->multipv].max_depth = 0;
	  save_multipv[SearchCurrent->multipv].value = 0;
	  save_multipv[SearchCurrent->multipv].time = 0;
	  save_multipv[SearchCurrent->multipv].node_nb = 0;
	  strcpy(save_multipv[SearchCurrent->multipv].pv_string,""); 
   }
  
   SearchInput->multipv = option_get_int("MultiPV")-1;
   SearchCurrent->multipv = 0;
   
   
   ASSERT(board_is_ok(SearchInput->board));

   // opening book

   if (option_get_bool("OwnBook") && !SearchInput->infinite) {

      move = book_move(SearchInput->board);

      if (move != MoveNone) {

         // play book move

         SearchBest[SearchCurrent->multipv].move = move;
         SearchBest[SearchCurrent->multipv].value = 1;
         SearchBest[SearchCurrent->multipv].flags = SearchExact;
         SearchBest[SearchCurrent->multipv].depth = 1;
         SearchBest[SearchCurrent->multipv].pv[0] = move;
         SearchBest[SearchCurrent->multipv].pv[1] = MoveNone;

         search_update_best();

         return;
      }
   }

   // SearchInput

   gen_legal_moves(SearchInput->list,SearchInput->board);

   if (LIST_SIZE(SearchInput->list) < SearchInput->multipv+1){ 
	  SearchInput->multipv = LIST_SIZE(SearchInput->list)-1;
   }

   if (LIST_SIZE(SearchInput->list) <= 1) {
      SearchInput->depth_is_limited = true;
      SearchInput->depth_limit = 4; // was 1
   }

   // SearchInfo

   if (setjmp(SearchInfo->buf) != 0) {
      ASSERT(SearchInfo->can_stop);
      ASSERT(SearchBest->move!=MoveNone);
      search_update_current();
      return;
   }

   // SearchRoot

   list_copy(SearchRoot->list,SearchInput->list);

   // SearchCurrent

   board_copy(SearchCurrent->board,SearchInput->board);
   my_timer_reset(SearchCurrent->timer);
   my_timer_start(SearchCurrent->timer);

   // init

   trans_inc_date(Trans);

   sort_init();
   search_full_init(SearchRoot->list,SearchCurrent->board);

   // analyze game for evaluation
   
   if (SearchCurrent->board->piece_size[White] < 3 && SearchCurrent->board->piece_size[Black] < 3){
	   trans_endgame = true;
   }
   else{
	   trans_endgame = false;
   }

   
   // iterative deepening

   search_ready = false;

   for (depth = 1; depth < DepthMax; depth++) {
	   for (SearchCurrent->multipv = 0; SearchCurrent->multipv <= SearchInput->multipv; SearchCurrent->multipv++){

		  if (DispDepthStart && SearchCurrent->multipv == 0) send("info depth %d",depth);

		  SearchCurrent->max_extensions = depth * 10;
		  SearchRoot->bad_1 = false;
		  SearchRoot->change = false;

		  board_copy(SearchCurrent->board,SearchInput->board);

		  if (UseShortSearch && depth <= ShortSearchDepth) {
			 search_full_root(SearchRoot->list,SearchCurrent->board,depth,SearchShort);
		  } else {
			 search_full_root(SearchRoot->list,SearchCurrent->board,depth,SearchNormal);
		  }

		  search_update_current();

		  if (DispDepthEnd && SearchCurrent->multipv == SearchInput->multipv) {
			 send("info depth %d seldepth %d time %.0f nodes " S64_FORMAT " nps %.0f",depth,SearchCurrent->max_depth,SearchCurrent->time*1000.0,SearchCurrent->node_nb,SearchCurrent->speed);
		  }

		  // update search info

		  if (depth >= 1) SearchInfo->can_stop = true;

		  if (depth == 1
		   && LIST_SIZE(SearchRoot->list) >= 2
		   && LIST_VALUE(SearchRoot->list,0) >= LIST_VALUE(SearchRoot->list,1) + EasyThreshold) {
			 SearchRoot->easy = true;
		  }

		  if (depth > 1) {
			 SearchRoot->bad_2 = SearchRoot->bad_1;
			 SearchRoot->bad_1 = false;
			 ASSERT(SearchRoot->bad_2==(SearchBest->value<=SearchRoot->last_value-BadThreshold));
		  }

		  SearchRoot->last_value = SearchBest[SearchCurrent->multipv].value;

		  // stop search?

		  if (SearchInput->depth_is_limited && SearchCurrent->multipv >= SearchInput->multipv
		   && depth >= SearchInput->depth_limit) {
			 SearchRoot->flag = true;
		  }

		  if (SearchInput->time_is_limited
		   && SearchCurrent->time * 2 >= SearchInput->time_limit_1
		   && !SearchRoot->bad_2) {
			 SearchRoot->flag = true;
		  }

		  if (SearchInput->time_is_limited
		   && SearchCurrent->time >= SearchInput->time_limit_1 * EasyRatio
		   && SearchRoot->easy) {
			 ASSERT(!SearchRoot->bad_2);
			 ASSERT(!SearchRoot->change);
			 SearchRoot->flag = true;
		  }

		  if (SearchInput->time_is_limited
		   && SearchCurrent->time >= SearchInput->time_limit_1 * EarlyRatio
		   && !SearchRoot->bad_2
		   && !SearchRoot->change) {
			 SearchRoot->flag = true;
		  }

		  if (SearchInfo->can_stop 
		   && (SearchInfo->stop || (SearchRoot->flag && !SearchInput->infinite))) {
			  search_ready = true;
			  break;
		  }
	   }
	   if (search_ready)
		   break;
   }
}
Example #3
0
void lslinit_process (void)
  /*@globals undef g_symtab; @*/
  /*@modifies g_symtab, internalState, fileSystem; @*/
{
  /*
  ** Open init file provided by user, or use the default LCL init file 
  */
  
  cstring larchpath = context_getLarchPath ();
  inputStream initstream = inputStream_undefined;

  setCodePoint ();

  if (inputStream_isUndefined (s_initFile))
    {
      s_initFile = inputStream_create (cstring_makeLiteral (INITFILENAME), 
				       cstring_makeLiteralTemp (LCLINIT_SUFFIX),
				       FALSE);
      
      if (!inputStream_getPath (larchpath, s_initFile))
	{
	  lldiagmsg (message ("Continuing without LCL init file: %s",
			      inputStream_fileName (s_initFile)));
	}
      else 
	{
	  if (!inputStream_open (s_initFile))
	    {
	      lldiagmsg (message ("Continuing without LCL init file: %s",
				  inputStream_fileName (s_initFile)));
	    }
	}
    }
  else 
    {
      if (!inputStream_open (s_initFile))
	{
	  lldiagmsg (message ("Continuing without LCL init file: %s",
			      inputStream_fileName (s_initFile)));
	}
    }

  /* Initialize checker */

  lsymbol_initMod ();
  LCLSynTableInit ();

  setCodePoint ();

  LCLSynTableReset ();
  LCLTokenTableInit ();

  setCodePoint ();

  LCLScanLineInit ();
  setCodePoint ();
  LCLScanLineReset ();
  setCodePoint ();
  LCLScanInit ();

  setCodePoint ();

  /* need this to initialize LCL checker */

  llassert (inputStream_isDefined (s_initFile));      
  if (inputStream_isOpen (s_initFile))
    {
      setCodePoint ();

      LCLScanReset (s_initFile);
      lclinit_initMod ();
      lclinit_reset ();

      setCodePoint ();
      lclinit_process ();
      lclinit_cleanup ();

      setCodePoint ();
      check (inputStream_close (s_initFile));
    }
  
  /* Initialize LSL init files, for parsing LSL signatures from LSL */
  
  initstream = inputStream_create (cstring_makeLiteral ("lslinit.lsi"), 
				    cstring_makeLiteralTemp (".lsi"),
				    FALSE);
  
  if (!inputStream_getPath (larchpath, initstream))
    {
      lldiagmsg (message ("Continuing without LSL init file: %s",
			  inputStream_fileName (initstream)));
    }
  else 
    {
      if (!inputStream_open (initstream))
	{
	  lldiagmsg (message ("Continuing without LSL init file: %s",
			      inputStream_fileName (initstream)));
	}
    }
      
  setCodePoint ();
  lsynTableInit ();
  lsynTableReset ();

  setCodePoint ();
  ltokenTableInit ();

  setCodePoint ();
  lscanLineInit ();
  lscanLineReset ();
  LSLScanInit ();

  if (inputStream_isOpen (initstream))
    {
      setCodePoint ();
      LSLScanReset (initstream);
      lslinit_initProcessInitFile ();
      lslinit_processInitFile ();
      check (inputStream_close (initstream));
    }
      
  inputStream_free (initstream);
  
  if (lclHadError ())
    {
      lclplainerror 
	(cstring_makeLiteral ("LSL init file error.  Attempting to continue."));
    }
  
  setCodePoint ();
  g_symtab = symtable_new ();
  
  /* 
  ** sort_init must come after symtab has been initialized 
  */
  sort_init ();
  abstract_init ();
  setCodePoint ();
  
  /* 
  ** Equivalent to importing old spec_csupport.lcl
  ** define immutable LCL type "bool" and bool constants TRUE and FALSE
  ** and initialized them to be equal to LSL's "true" and "false".
  **
  ** Reads in CTrait.syms (derived from CTrait.lsl) on LARCH_PATH.
  */
      
  LCLBuiltins (); 
  LCLReportEolTokens (FALSE);
}
Example #4
0
int main(int argc, char **argv)
{
    INIT_GLB_VARS();
    SET_PROCESS_ROLE(PROCESS_ROLE_MASTER);
    SET_CHILD_PROCESS(PROCESS_ROLE_MASTER, getpid());

    /* 此处注册清理函数, 以便主进程由于某些原因退出时, kill掉
     * 启动的所有子进程. 但man atexit可知, 通过fork的子进程会
     * 继承atexit的注册链, 而exec后将抛弃此注册链.
     * <NOTE> 此处不考虑fork子进程也执行此函数带来的影响 */
    (void)atexit(kill_child_all);

    if (log_init() == RET_ERR) {
        SDNS_LOG_ERR("LOG init failed");
        exit(EXIT_FAILURE);
    }

    if (zone_init() == RET_ERR) {
        SDNS_LOG_ERR("ZONE init failed");
        exit(EXIT_FAILURE);
    }

    if (get_options(argc, argv) == RET_ERR) {
        SDNS_LOG_ERR("parse cmdline failed");
        usage_help();
        exit(EXIT_FAILURE);
    }

    if (IS_PROCESS_ROLE(PROCESS_ROLE_SIGNALLER)) {
        process_option_signal();
        exit(EXIT_SUCCESS);
    }

    if (IS_PROCESS_ROLE(PROCESS_ROLE_HELPER)) {
        usage_help();
        exit(EXIT_SUCCESS);
    }

    if (start_monitor() == RET_ERR) {
        exit(EXIT_FAILURE);
    }

    if (parse_conf() == RET_ERR) {
        exit(EXIT_FAILURE);
    }
    
    if (IS_PROCESS_ROLE(PROCESS_ROLE_TESTER)) {
        SDNS_LOG_DEBUG("配置文件测试OK");
        print_parse_res();
        exit(EXIT_SUCCESS);
    }

    if (pkt_engine_init() == RET_ERR) {
        SDNS_LOG_ERR("engine init failed");
        exit(EXIT_FAILURE);
    }

    if (set_required_signal() == RET_ERR
            || block_required_signal() == RET_ERR) {
        SDNS_LOG_ERR("signal init failed");
        exit(EXIT_FAILURE);
    }

    if (sort_init() == RET_ERR) {
        SDNS_LOG_ERR("sort init failed");
        exit(EXIT_FAILURE);
    }

    start_worker();

    if (start_pkt_engine() == RET_ERR) {
        SDNS_LOG_ERR("start engine failed");
        exit(EXIT_FAILURE);
    }

    for(;;) {
        (void)wait_required_signal();
        (void)process_signals();
    }

    exit(EXIT_SUCCESS);
}
Example #5
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 #6
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 #7
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;
}