Exemple #1
0
void MoveToStr(int move, char *move_str) {

  static const char prom_char[5] = "nbrq";

  // Move coordinates

  move_str[0] = File(Fsq(move)) + 'a';
  move_str[1] = Rank(Fsq(move)) + '1';
  move_str[2] = File(Tsq(move)) + 'a';
  move_str[3] = Rank(Tsq(move)) + '1';
  move_str[4] = '\0';

  // Bugfix by Dave Kaye for compatibility with Knights GUI (Linux) and UCI specs
  // (needed if a GUI forces the engine to analyse in checkmate/stalemate position)

  if (strcmp(move_str, "a1a1") == 0) {
    strcpy(move_str, "0000");
  }

  // Add promoted piece, if any

  if (IsProm(move)) {
    move_str[4] = prom_char[(move >> 12) & 3];
    move_str[5] = '\0';
  }
}
Exemple #2
0
void DecreaseHistory(POS *p, int move, int depth) {

  // Increment history counter

  history[p->pc[Fsq(move)]][Tsq(move)] -= depth * depth;

  // Prevent history counters from growing too high

  if (history[p->pc[Fsq(move)]][Tsq(move)] < -HIST_LIMIT)
    TrimHistory();
}
Exemple #3
0
int MvvLva(POS *p, int move) {

  // Captures

  if (p->pc[Tsq(move)] != NO_PC)
    return TpOnSq(p, Tsq(move)) * 6 + 5 - TpOnSq(p, Fsq(move));

  // Non-capturing promotions
  
  if (IsProm(move)) return PromType(move) - 5;

  return 5;
}
Exemple #4
0
int NextCaptureOrCheck(MOVES * m)  // used in QuiesceCheck()
{
  int move;

  switch (m->phase) {
  case 0:
    while (m->next < m->last) {
      move = SelectBest(m);
      if (BadCapture(m->p, move))
        continue;

      return move;
  }
  m->phase = 1;

  case 1:
    m->last = GenerateQuietChecks(m->p, m->move);
    ScoreQuiet(m);
    m->phase = 2;

  case 2:
    while (m->next < m->last) {
      move = SelectBest(m);
      if (Swap(m->p, Fsq(move), Tsq(move)) < 0) continue;
      return move;
    }
  }
  return 0;
}
Exemple #5
0
void ScoreQuiet(MOVES *m) {

  int *movep, *valuep;
  int move_score;

  valuep = m->value;
  for (movep = m->move; movep < m->last; movep++) {
    
    move_score = history[m->p->pc[Fsq(*movep)]][Tsq(*movep)];

	if (TpOnSq(m->p,Fsq(*movep)) != K)
		move_score += Param.mg_pst[m->p->side][TpOnSq(m->p,Fsq(*movep))][Tsq(*movep)]
		            - Param.mg_pst[m->p->side][TpOnSq(m->p, Fsq(*movep))][Fsq(*movep)];

	//if (Fsq(*movep) == m->ref_sq && m->ref_sq != -1) move_score += 2048;
    
    *valuep++ = move_score;
  }
}
Exemple #6
0
void UpdateHistory(POS *p, int last_move, int move, int depth, int ply) {

  // Don't update stuff used for move ordering if a move changes material balance

  if (p->pc[Tsq(move)] != NO_PC || IsProm(move) || MoveType(move) == EP_CAP)
    return;

  // Asserts suggested by Ferdinand Mosca because history[] would overflow
  // if p->pc[Fsq(move)] == NO_PC.  If they ever fire, either move or board 
  // data are corrupt.

  assert(p->pc[Fsq(move)] != NO_PC);  // To detect no_pc
  assert(p->pc[Fsq(move)] <= NO_PC);  // To detect beyond no_pc for deeper examination 

  // Increment history counter

  history[p->pc[Fsq(move)]][Tsq(move)] += 2 * depth * depth;

  // Prevent history counters from growing too high

  if (history[p->pc[Fsq(move)]][Tsq(move)] > HIST_LIMIT)
     TrimHistory();

  // Update refutation table, saving new move in the table indexed
  // by the coordinates of last move. last_move == 0 is a null move,
  // special case of last_move == -1 denotes situations when updating
  // refutation table is switched off: at root or in QuiesceFlee()

  if (last_move >= 0)
     refutation[Fsq(last_move)][Tsq(last_move)] = move;

  // Update killer moves, taking care that they are different

  if (move != killer[ply][0]) {
    killer[ply][1] = killer[ply][0];
    killer[ply][0] = move;
  }
}
Exemple #7
0
int BadCapture(POS *p, int move) {

  int fsq = Fsq(move);
  int tsq = Tsq(move);

  // Captures that gain material or capture equal piece are good by definition

  if (tp_value[TpOnSq(p, tsq)] >= tp_value[TpOnSq(p, fsq)])
    return 0;

  // Bishop takes knight and knight takes bishop are good irrespectively from
  // the way minor pieces' values are tuned

  if ((TpOnSq(p, fsq) == B) && (TpOnSq(p, tsq) == N)) return 0;
  if ((TpOnSq(p, fsq) == N) && (TpOnSq(p, tsq) == B)) return 0;

  // En passant captures are good by definition

  if (MoveType(move) == EP_CAP) return 0;
  
  // We have to evaluate this capture using expensive Static Exchange Evaluation

  return Swap(p, fsq, tsq) < 0;
}
Exemple #8
0
void sHistory::OnMoveReduced(int move) 
{
    cutoff [Fsq(move)] [Tsq(move)] = 51;
}
void POS::UndoMove(int move, UNDO *u) {

  int sd  = Opp(side);
  int op  = side;
  int fsq = Fsq(move);
  int tsq = Tsq(move);
  int ftp = Tp(pc[tsq]);    // moving piece
  int ttp = u->ttp;

  castle_flags = u->castle_flags;
  ep_sq = u->ep_sq;
  rev_moves = u->rev_moves;
  pawn_key = u->pawn_key;
  hash_key = u->hash_key;
  head--;
  pc[fsq] = Pc(sd, ftp);
  pc[tsq] = NO_PC;
  cl_bb[sd] ^= SqBb(fsq) | SqBb(tsq);
  tp_bb[ftp] ^= SqBb(fsq) | SqBb(tsq);
#ifndef LEAF_PST
  mg_pst[sd] += Param.mg_pst_data[sd][ftp][fsq] - Param.mg_pst_data[sd][ftp][tsq];
  eg_pst[sd] += Param.eg_pst_data[sd][ftp][fsq] - Param.eg_pst_data[sd][ftp][tsq];
#endif

  // Update king location

  if (ftp == K) king_sq[sd] = fsq;

  // Undo capture

  if (ttp != NO_TP) {
    pc[tsq] = Pc(op, ttp);
    cl_bb[op] ^= SqBb(tsq);
    tp_bb[ttp] ^= SqBb(tsq);
    phase += phase_value[ttp];
#ifndef LEAF_PST
    mg_pst[op] += Param.mg_pst_data[op][ttp][tsq];
    eg_pst[op] += Param.eg_pst_data[op][ttp][tsq];
#endif
    cnt[op][ttp]++;
  }

  switch (MoveType(move)) {

  case NORMAL:
    break;

  case CASTLE:

    // define complementary rook move

    switch (tsq) {
      case C1: { fsq = A1; tsq = D1; break; }
      case G1: { fsq = H1; tsq = F1; break; }
      case C8: { fsq = A8; tsq = D8; break; }
      case G8: { fsq = H8; tsq = F8; break; }
    }

    pc[tsq] = NO_PC;
    pc[fsq] = Pc(sd, R);
    cl_bb[sd] ^= SqBb(fsq) | SqBb(tsq);
    tp_bb[R] ^= SqBb(fsq) | SqBb(tsq);
#ifndef LEAF_PST
    mg_pst[sd] += Param.mg_pst_data[sd][R][fsq] - Param.mg_pst_data[sd][R][tsq];
    eg_pst[sd] += Param.eg_pst_data[sd][R][fsq] - Param.eg_pst_data[sd][R][tsq];
#endif
    break;

  case EP_CAP:
    tsq ^= 8;
    pc[tsq] = Pc(op, P);
    cl_bb[op] ^= SqBb(tsq);
    tp_bb[P] ^= SqBb(tsq);
    phase += phase_value[P];
#ifndef LEAF_PST
    mg_pst[op] += Param.mg_pst_data[op][P][tsq];
    eg_pst[op] += Param.eg_pst_data[op][P][tsq];
#endif
    cnt[op][P]++;
    break;

  case EP_SET:
    break;

  case N_PROM: case B_PROM: case R_PROM: case Q_PROM:
    pc[fsq] = Pc(sd, P);
    tp_bb[P] ^= SqBb(fsq);
    tp_bb[ftp] ^= SqBb(fsq);
    phase += phase_value[P] - phase_value[ftp];
#ifndef LEAF_PST
    mg_pst[sd] += Param.mg_pst_data[sd][P][fsq] - Param.mg_pst_data[sd][ftp][fsq];
    eg_pst[sd] += Param.eg_pst_data[sd][P][fsq] - Param.eg_pst_data[sd][ftp][fsq];
#endif
    cnt[sd][P]++;
    cnt[sd][ftp]--;
    break;
  }
  side ^= 1;
}
int Search(POS *p, int ply, int alpha, int beta, int depth, int was_null, int last_move, int last_capt_sq, int *pv) {

  int best, score, null_score, move, new_depth, new_pv[MAX_PLY];
  int fl_check, fl_prunable_node, fl_prunable_move, mv_type, reduction;
  int is_pv = (beta > alpha + 1);
  int mv_tried = 0, quiet_tried = 0, fl_futility = 0;

  int mv_played[MAX_MOVES];
  int mv_hist_score;
  int victim, last_capt;

  MOVES m[1];
  UNDO u[1];

  assert(ply > 0);

  // Quiescence search entry point

  if (depth <= 0)
    return QuiesceChecks(p, ply, alpha, beta, pv);

  // Periodically check for timeout, ponderhit or stop command

  nodes++;
  CheckTimeout();

  // Quick exit on a timeout or on a statically detected draw
  
  if (abort_search) return 0;
  if (ply) *pv = 0;
  if (IsDraw(p)) return DrawScore(p);

  // Mate distance pruning

  int checkmatingScore = MATE - ply;
  if (checkmatingScore < beta) {
    beta = checkmatingScore;
    if (alpha >= checkmatingScore)
    return alpha;
  }

  int checkmatedScore = -MATE + ply;
  if (checkmatedScore > alpha) {
    alpha = checkmatedScore;
    if (beta <= checkmatedScore)
    return beta;
  }

  // Retrieving data from transposition table. We hope for a cutoff
  // or at least for a move to improve move ordering.

  move = 0;
  if (TransRetrieve(p->hash_key, &move, &score, alpha, beta, depth, ply)) {
    
    // For move ordering purposes, a cutoff from hash is treated
    // exactly like a cutoff from search

    if (score >= beta) UpdateHistory(p, last_move, move, depth, ply);

    // In pv nodes only exact scores are returned. This is done because
    // there is much more pruning and reductions in zero-window nodes,
    // so retrieving such scores in pv nodes works like retrieving scores
    // from slightly lower depth.

    if (!is_pv || (score > alpha && score < beta))
      return score;
  }

  // Safeguard against exceeding ply limit
  
  if (ply >= MAX_PLY - 1)
    return Eval.Return(p, 1);

  // Are we in check? Knowing that is useful when it comes 
  // to pruning/reduction decisions

  fl_check = InCheck(p);

  // INTERNAL ITERATIVE DEEPENING - we try to get a hash move to improve move ordering

  if (!move && is_pv && depth >= 6 && !fl_check) {
    Search(p, ply, alpha, beta, depth - 2, 0, 0, -1, new_pv);
    if (abort_search) return 0;
    TransRetrieve(p->hash_key, &move, &score, alpha, beta, depth, ply);
  }

  // Can we prune this node?

  fl_prunable_node = !fl_check 
                   && !is_pv 
                   && alpha > -MAX_EVAL
                   && beta < MAX_EVAL;

  // Beta pruning / static null move

  if (use_beta_pruning
  && fl_prunable_node
  && depth <= 3
  && !was_null) {
    int sc = Eval.Return(p, 1) - 120 * depth; // TODO: Tune me!
    if (sc > beta) return sc;
  }

  // Null move

  if (use_nullmove
  && fl_prunable_node
  && depth > 1
  && !was_null
  && MayNull(p)
  ) {
    int eval = Eval.Return(p, 1);
    if (eval > beta) {

      new_depth = depth - ((823 + 67 * depth) / 256); // simplified Stockfish formula

      // omit null move search if normal search to the same depth wouldn't exceed beta
      // (sometimes we can check it for free via hash table)

      if (TransRetrieve(p->hash_key, &move, &null_score, alpha, beta, new_depth, ply)) {
        if (null_score < beta) goto avoid_null;
      }

      p->DoNull(u);
      if (new_depth > 0) score = -Search(p, ply + 1, -beta, -beta + 1, new_depth, 1, 0, -1, new_pv);
      else               score = -QuiesceChecks(p, ply + 1, -beta, -beta + 1, new_pv);
      p->UndoNull(u);

      // Verification search (nb. immediate null move within it is prohibited)

      if (new_depth > 6 && score >= beta && use_null_verification)
         score = Search(p, ply, alpha, beta, new_depth - 5, 1, move, -1, new_pv);

      if (abort_search ) return 0;
      if (score >= beta) return score;
    }
  } 
  
  avoid_null:

  // end of null move code

  // Razoring based on Toga II 3.0

  if (use_razoring
  && fl_prunable_node
  && !move
  && !was_null
  && !(p->Pawns(p->side) & bbRelRank[p->side][RANK_7]) // no pawns to promote in one move
  && depth <= 3) {
    int threshold = beta - razor_margin[depth];
    int eval = Eval.Return(p, 1);

    if (eval < threshold) {
      score = QuiesceChecks(p, ply, alpha, beta, pv);
      if (score < threshold) return score;
    }
  }

  // end of razoring code 

  // Init moves and variables before entering main loop
  
  best = -INF;
  InitMoves(p, m, move, Refutation(last_move), ply);
  
  // Main loop
  
  while ((move = NextMove(m, &mv_type))) {

    // Gather data about the move

    mv_hist_score = history[p->pc[Fsq(move)]][Tsq(move)];
	victim = TpOnSq(p, Tsq(move));
	if (victim != NO_TP) last_capt = Tsq(move);
	else last_capt = -1;

    // Set futility pruning flag before the first applicable move is tried

    if (mv_type == MV_NORMAL && quiet_tried == 0) {
      if (use_futility
      && fl_prunable_node
      && depth <= 6) {
        if (Eval.Return(p, 1) + fut_margin[depth] < beta) fl_futility = 1;
      }
    }

    p->DoMove(move, u);
    if (Illegal(p)) { p->UndoMove(move, u); continue; }

  // Update move statistics 
  // (needed for reduction/pruning decisions and for updating history score)

  mv_played[mv_tried] = move;
  mv_tried++;
  if (mv_type == MV_NORMAL) quiet_tried++;

  // Can we prune this move?

  fl_prunable_move = !InCheck(p)
                  && (mv_type == MV_NORMAL)
                  && (mv_hist_score < hist_limit);

  // Set new search depth

  new_depth = depth - 1;

  // Check extension (pv node or low depth)

  if (is_pv || depth < 9) {
	  new_depth += InCheck(p);
	  if (is_pv && Tsq(move) == last_capt_sq) new_depth += 1;
  }

  // Futility pruning

  if (fl_futility
  &&  fl_prunable_move
  &&  mv_tried > 1) {
    p->UndoMove(move, u); continue;
  }

  // Late move pruning

  if (use_lmp
  && fl_prunable_node
  && fl_prunable_move
  && quiet_tried > lmp_limit[depth]
  && depth <= 3
  && MoveType(move) != CASTLE ) {
    p->UndoMove(move, u); continue;
  }

  // Late move reduction

  reduction = 0;

  if (use_lmr 
  && depth >= 2
  && mv_tried > 3
  && alpha > -MAX_EVAL && beta < MAX_EVAL
  && !fl_check 
  &&  fl_prunable_move
  && lmr_size[is_pv][depth][mv_tried] > 0
  && MoveType(move) != CASTLE ) {
    
    // read reduction size from the table

    reduction = lmr_size[is_pv][depth][mv_tried];

    // increase reduction on bad history score

    if (mv_hist_score < 0
    && new_depth - reduction > 2
    && lmr_hist_adjustement)
       reduction++;

    // reduce search depth

    new_depth -= reduction;
  }

  // a place to come back if reduction looks suspect

  re_search:
   
  // PVS

  if (best == -INF)
    score = -Search(p, ply + 1, -beta, -alpha, new_depth, 0, move, last_capt, new_pv);
  else {
    score = -Search(p, ply + 1, -alpha - 1, -alpha, new_depth, 0, move, last_capt, new_pv);
    if (!abort_search && score > alpha && score < beta)
      score = -Search(p, ply + 1, -beta, -alpha, new_depth, 0, move, last_capt, new_pv);
  }

  // Reduced move scored above alpha - we need to re-search it

  if (reduction
  && score > alpha) {
    new_depth += reduction;
    reduction = 0;
    goto re_search;
  }

  // Undo move

  p->UndoMove(move, u);
  if (abort_search) return 0;

  // Beta cutoff

    if (score >= beta) {
      if (!fl_check) {
        UpdateHistory(p, last_move, move, depth, ply);
        for (int mv = 0; mv < mv_tried; mv++)
          DecreaseHistory(p, mv_played[mv], depth);
      }
      TransStore(p->hash_key, move, score, LOWER, depth, ply);

      return score;
    }

  // Updating score and alpha

    if (score > best) {
      best = score;
      if (score > alpha) {
        alpha = score;
        BuildPv(pv, new_pv, move);
      }
    }

  } // end of the main loop

  // Return correct checkmate/stalemate score

  if (best == -INF)
    return InCheck(p) ? -MATE + ply : DrawScore(p);

  // Save score in the transposition table

  if (*pv) {
    if (!fl_check) {
      UpdateHistory(p, last_move, *pv, depth, ply);
      for (int mv = 0; mv < mv_tried; mv++)
        DecreaseHistory(p, mv_played[mv], depth);
    }
    TransStore(p->hash_key, *pv, best, EXACT, depth, ply);
  } else
    TransStore(p->hash_key, 0, best, UPPER, depth, ply);

  return best;
}
Exemple #11
0
void sHistory::UpdateCutoff(int move)
{
	cutoff [Fsq(move)] [Tsq(move)] += 8; 
	// NOTE: 8 and 9 work equally well in self-play, 7 and 10 untested
}
Exemple #12
0
int sHistory::MoveChangesMaterialBalance(sPosition *p, int move)
{
    if (p->pc[Tsq(move)] != NO_PC || IsProm(move) || MoveType(move) == EP_CAP) return 1;
	return 0;
}
Exemple #13
0
int sHistory::Refutes(int lastMove, int move)
{
	return (refutation [Fsq(lastMove)] [Tsq(lastMove)] == move);
}
int Quiesce(POS *p, int ply, int alpha, int beta, int *pv) {

  int best, score, move, new_pv[MAX_PLY];
  MOVES m[1];
  UNDO u[1];
  int op = Opp(p->side);

  // Statistics and attempt at quick exit

  if (InCheck(p)) return QuiesceFlee(p, ply, alpha, beta, pv);

  nodes++;
  CheckTimeout();
  if (abort_search) return 0;
  *pv = 0;
  if (IsDraw(p)) return DrawScore(p);
  if (ply >= MAX_PLY - 1) return Eval.Return(p, 1);

  // Get a stand-pat score and adjust bounds
  // (exiting if eval exceeds beta)

  best = Eval.Return(p, 1);
  if (best >= beta) return best;
  if (best > alpha) alpha = best;

#ifdef USE_QS_HASH
  // Transposition table read

  if (TransRetrieve(p->hash_key, &move, &score, alpha, beta, 0, ply))
    return score;
#endif

  InitCaptures(p, m);

  // Main loop

  while ((move = NextCapture(m))) {

    // Pruning in quiescence search 
	// (not applicable if we are capturing last enemy piece)

	if (p->cnt[op][N] + p->cnt[op][B] + p->cnt[op][R] + p->cnt[op][Q] > 1) {

      // 1. Delta pruning

      if (best + tp_value[TpOnSq(p, Tsq(move))] + 300 < alpha) continue;

      // 2. SEE-based pruning of bad captures

      if (BadCapture(p, move)) continue;
	}

    p->DoMove(move, u);
    if (Illegal(p)) { p->UndoMove(move, u); continue; }

    score = -Quiesce(p, ply + 1, -beta, -alpha, new_pv);

    p->UndoMove(move, u);
    if (abort_search) return 0;

  // Beta cutoff

  if (score >= beta) {
#ifdef USE_QS_HASH
    TransStore(p->hash_key, *pv, best, LOWER, 0, ply);
#endif
    return score;
  }

  // Adjust alpha and score

    if (score > best) {
      best = score;
      if (score > alpha) {
        alpha = score;
        BuildPv(pv, new_pv, move);
      }
    }
  }

#ifdef USE_QS_HASH
  if (*pv) TransStore(p->hash_key, *pv, best, EXACT, 0, ply);
  else     TransStore(p->hash_key,   0, best, UPPER, 0, ply);
#endif

  return best;
}
Exemple #15
0
int sBook::GetPolyglotMove(sPosition *p, int printOutput) {

   int bestMove  = 0;
   int bestScore = 0;
   int maxWeight = 0;
   int sumOfWeights = 0;
   int pos;
   polyglot_move entry[1];
   int move;
   int score;
   int values[100];
   U64 key = GetPolyglotKey(p);
   char moveString[6];

   nOfChoices = 0;

   if (bookFile != NULL && bookSize != 0) {
	  srand(Timer.GetMS() );

      for (pos = FindPos(key); pos < bookSize; pos++) {

         ReadEntry(entry,pos);
         if (entry->key != key) break;

         move = entry->move;
		 score = entry->weight;

		 // ugly hack to convert polyglot move to a real one
		 int fsq = Tsq(move);
		 int tsq = Fsq(move);

		 // correction for castling moves
		 if (fsq == E1 && tsq == H1 && p->kingSquare[WHITE] == E1) tsq = G1;
		 if (fsq == E8 && tsq == H8 && p->kingSquare[BLACK] == E8) tsq = G8;
		 if (fsq == E1 && tsq == A1 && p->kingSquare[WHITE] == E1) tsq = C1;
		 if (fsq == E8 && tsq == A8 && p->kingSquare[BLACK] == E8) tsq = C8;

		 // now we want to get a move with full data, not only from and to squares
		 int realMove = (tsq << 6) | fsq;
		 MoveToStr(realMove, moveString);
		 realMove = StrToMove(p, moveString);

		 if (maxWeight < score) maxWeight = score;
		 sumOfWeights += score;
		 moves[nOfChoices] = realMove;
		 values[nOfChoices] = score;
		 nOfChoices++;
      }

      // pick a move, filtering out those with significantly lower weight
	  for (int i = 0; i<nOfChoices; i++) {

		 // report about possible choices and rejected moves
		 if (values[i] > 1 || maxWeight == 1) {
            if (printOutput) {
		       printf("info string ");
		       PrintMove(moves[i]);
		       printf(" %d %%", (values[i] * 100) / sumOfWeights );
			   if (IsInfrequent(values[i], maxWeight)) printf(" infrequent ");
			}
		 }
		 
		 // shall we pick this move?
		 if (!IsInfrequent(values[i], maxWeight)) {
		    bestScore += values[i];
            if (my_random(bestScore) < values[i]) bestMove = moves[i];
		 }
		 
		 printf("\n");

	  }
   }
   //if (printOutput) PrintMissingMoves(p);
   return bestMove;
}
Exemple #16
0
void sHistory::OnMoveTried(int move) 
{
    cutoff [Fsq(move)] [Tsq(move)] -= 1;
}
Exemple #17
0
int sHistory::MoveIsBad(int move) 
{
    return (cutoff [Fsq(move)] [Tsq(move)] < Data.lmrHistLimit);
}
Exemple #18
0
int NextMove(MOVES *m, int *flag) {

  int move;

  switch (m->phase) {
  case 0: // return transposition table move, if legal
    move = m->trans_move;
    if (move 
    && Legal(m->p, move)) {
      m->phase = 1;
      *flag = MV_HASH;
      return move;
    }

  case 1: // helper phase: generate captures
    m->last = GenerateCaptures(m->p, m->move);
    ScoreCaptures(m);
    m->next = m->move;
    m->badp = m->bad;
    m->phase = 2;

  case 2: // return good captures, save bad ones on the separate list
    while (m->next < m->last) {
      move = SelectBest(m);

      if (move == m->trans_move)
        continue;

      if (BadCapture(m->p, move)) {
        *m->badp++ = move;
        continue;
      }
      *flag = MV_CAPTURE;
      return move;
    }

  case 3:  // first killer move
    move = m->killer1;
    if (move 
    && move != m->trans_move 
    && m->p->pc[Tsq(move)] == NO_PC 
    && Legal(m->p, move)) {
      m->phase = 4;
      *flag = MV_KILLER;
      return move;
    }

  case 4:  // second killer move
    move = m->killer2;
    if (move 
    && move != m->trans_move 
    && m->p->pc[Tsq(move)] == NO_PC 
    && Legal(m->p, move)) {
      m->phase = 5;
      *flag = MV_KILLER;
      return move;
    }

  case 5: // refutation move
    move = m->ref_move;
    if (move && move != m->trans_move 
    &&  m->p->pc[Tsq(move)] == NO_PC 
    &&  move != m->killer1
    &&  move != m->killer2
    && Legal(m->p, move)) {
      m->phase = 6;
      *flag = MV_NORMAL;
      return move;
    }

  case 6:  // helper phase: generate quiet moves
    m->last = GenerateQuiet(m->p, m->move);
    ScoreQuiet(m);
    m->next = m->move;
    m->phase = 7;

  case 7:  // return quiet moves
    while (m->next < m->last) {
      move = SelectBest(m);
      if (move == m->trans_move
      ||  move == m->killer1
      ||  move == m->killer2
      ||  move == m->ref_move)
        continue;
      *flag = MV_NORMAL;
      return move;
    }

    m->next = m->bad;
    m->phase = 8;

  case 8: // return bad captures
    if (m->next < m->badp) {
      *flag = MV_BADCAPT;
      return *m->next++;
    }
  }
  return 0;
}
Exemple #19
0
int sHistory::GetRefutation(int lastMove)
{
	return refutation [Fsq(lastMove)] [Tsq(lastMove)];
}
Exemple #20
0
int Refutation(int move) {
  return refutation[Fsq(move)][Tsq(move)];
}
Exemple #21
0
void sHistory::UpdateHistory(sPosition *p, int move, int depth)
{
     history[p->pc[Fsq(move)]][Tsq(move)] += depth * depth;
}
Exemple #22
0
void sManipulator::DoMove(sPosition *p, int move, UNDO *u)
{
  int side = p->side;         // moving side 
  int fsq  = Fsq(move);       // start square
  int tsq  = Tsq(move);       // target square
  int ftp  = TpOnSq(p, fsq);  // moving piece
  int ttp  = TpOnSq(p, tsq);  // captured piece

  U64 bbMove = SqBb(fsq) | SqBb(tsq); // optimization from Stockfish

  // save data for undoing a move
  u->ttp = ttp;
  u->castleFlags = p->castleFlags;
  u->epSquare = p->epSquare;
  u->reversibleMoves = p->reversibleMoves;
  u->hashKey = p->hashKey;
  u->pawnKey = p->pawnKey;

  p->repetitionList[p->head++] = p->hashKey;

  // update reversible move counter (zeroing is done on captures and pawn moves)
  p->reversibleMoves++;

  p->hashKey     ^= zobCastle[p->castleFlags];
  p->castleFlags &= castleMask[fsq] & castleMask[tsq];
  p->hashKey     ^= zobCastle[p->castleFlags];

  // clear en passant square
  if (p->epSquare != NO_SQ) {
    p->hashKey ^= zobEp[File(p->epSquare)];
    p->epSquare = NO_SQ;
  }

  // move a piece from start square
  p->pc[fsq]      = NO_PC;
  p->pc[tsq]      = Pc(side, ftp);
  p->hashKey     ^= zobPiece[Pc(side, ftp)][fsq] ^ zobPiece[Pc(side, ftp)][tsq];
  if (ftp == P) {
	  p->reversibleMoves = 0;
	  p->pawnKey ^= zobPiece[Pc(side, ftp)][fsq] ^ zobPiece[Pc(side, ftp)][tsq];
  } 
  p->bbCl[side]  ^= bbMove;
  p->bbTp[ftp]   ^= bbMove;
  p->pstMg[side] += Data.pstMg[side][ftp][tsq] - Data.pstMg[side][ftp][fsq];
  p->pstEg[side] += Data.pstEg[side][ftp][tsq] - Data.pstEg[side][ftp][fsq];

  // on a king move update king location data
  if (ftp == K) p->kingSquare[side] = tsq;
  
  // capture
  if (ttp != NO_TP) {
	p->reversibleMoves = 0;
    p->hashKey ^= zobPiece[Pc(Opp(side), ttp)][tsq];
	if (ttp == P) 
		p->pawnKey     ^= zobPiece[Pc(Opp(side), ttp)][tsq];
    p->bbCl[Opp(side)] ^= SqBb(tsq);
    p->bbTp[ttp]       ^= SqBb(tsq);
	p->pcCount[Opp(side)][ttp]--;
    p->pieceMat[Opp(side)] -= Data.matValue[ttp];
	p->phase               -= Data.phaseValue[ttp]; 
    p->pstMg[Opp(side)]    -= Data.pstMg[Opp(side)][ttp][tsq];
	p->pstEg[Opp(side)]    -= Data.pstEg[Opp(side)][ttp][tsq];
  }
  
  switch (MoveType(move)) {

  case NORMAL:
    break;

  case CASTLE:
    if (tsq > fsq) {
      fsq += 3;
      tsq -= 1;
    } else {
      fsq -= 4;
      tsq += 1;
    }
    p->pc[fsq]      = NO_PC;
    p->pc[tsq]      = Pc(side, R);
    p->hashKey     ^= zobPiece[Pc(side, R)][fsq] ^ zobPiece[Pc(side, R)][tsq];
    p->bbCl[side]  ^= SqBb(fsq) | SqBb(tsq);
    p->bbTp[R]     ^= SqBb(fsq) | SqBb(tsq);
    p->pstMg[side] += Data.pstMg[side][R][tsq] - Data.pstMg[side][R][fsq];
	p->pstEg[side] += Data.pstEg[side][R][tsq] - Data.pstEg[side][R][fsq];
    break;

  case EP_CAP:
    tsq ^= 8;
    p->pc[tsq]  = NO_PC;
    p->hashKey ^= zobPiece[Pc(Opp(side), P)][tsq];
	p->pawnKey ^= zobPiece[Pc(Opp(side), P)][tsq];
    p->bbCl[Opp(side)] ^= SqBb(tsq);
    p->bbTp[P] ^= SqBb(tsq);
	p->pcCount[Opp(side)][P]--;
	p->phase             -= Data.phaseValue[P];
    p->pstMg[Opp(side)] -= Data.pstMg[Opp(side)][P][tsq];
	p->pstEg[Opp(side)] -= Data.pstEg[Opp(side)][P][tsq];
    break;

  case EP_SET:
    tsq ^= 8;
    if (bbPawnAttacks[side][tsq] & bbPc(p, Opp(side), P)) {
      p->epSquare = tsq;
      p->hashKey ^= zobEp[File(tsq)];
    }
    break;

  // promotion:    (1) add promoted piece and add values associated with it
  case N_PROM:  // (2) remove promoted pawn and substract values associated with it 
  case B_PROM: 
  case R_PROM: 
  case Q_PROM:
    ftp = PromType(move);
    p->pc[tsq]   = Pc(side, ftp);
    p->hashKey  ^= zobPiece[Pc(side, P)][tsq] ^ zobPiece[Pc(side, ftp)][tsq];
	p->pawnKey  ^= zobPiece[Pc(side, P)][tsq];
    p->bbTp[P]  ^= SqBb(tsq);
    p->bbTp[ftp]^= SqBb(tsq);
	p->pcCount[side][ftp]++;
	p->pcCount[side][P]--;
	p->pieceMat[side] += Data.matValue[ftp];
	p->phase          += Data.phaseValue[ftp]       - Data.phaseValue[P];
    p->pstMg[side]    += Data.pstMg[side][ftp][tsq] - Data.pstMg[side][P][tsq];
	p->pstEg[side]    += Data.pstEg[side][ftp][tsq] - Data.pstEg[side][P][tsq];
    break;

  }
  p->side ^= 1;
  p->hashKey ^= SIDE_RANDOM;
}
Exemple #23
0
void sHistory::UpdateRefutation(int lastMove, int move)
{
	refutation [Fsq(lastMove)] [Tsq(lastMove)] = move;
}
int SearchRoot(POS *p, int ply, int alpha, int beta, int depth, int *pv) {

  int best, score, move, new_depth, new_pv[MAX_PLY];
  int fl_check, fl_prunable_move, mv_type, reduction;
  int mv_tried = 0, quiet_tried = 0;
  int mv_played[MAX_MOVES];
  int mv_hist_score;
  int victim, last_capt;
  int move_change = 0;
  
  fl_has_choice = 0;
  
  MOVES m[1];
  UNDO u[1];

  // Periodically check for timeout, ponderhit or stop command

  nodes++;
  CheckTimeout();

  // Quick exit
  
  if (abort_search) return 0;

  // Retrieving data from transposition table. We hope for a cutoff
  // or at least for a move to improve move ordering.

  move = 0;
  if (TransRetrieve(p->hash_key, &move, &score, alpha, beta, depth, ply)) {
    
    // For move ordering purposes, a cutoff from hash is treated
    // exactly like a cutoff from search

    if (score >= beta) UpdateHistory(p, -1, move, depth, ply);

    // Root node is a pv node, so we return only exact scores

    if (score > alpha && score < beta)
      return score;
  }
  
  // Are we in check? Knowing that is useful when it comes 
  // to pruning/reduction decisions

  fl_check = InCheck(p);

  // Init moves and variables before entering main loop
  
  best = -INF;
  InitMoves(p, m, move, Refutation(-1), ply);
  
  // Main loop
  
  while ((move = NextMove(m, &mv_type))) {

    mv_hist_score = history[p->pc[Fsq(move)]][Tsq(move)];
	victim = TpOnSq(p, Tsq(move));
	if (victim != NO_TP) last_capt = Tsq(move);
	else last_capt = -1;

    p->DoMove(move, u);
    if (Illegal(p)) { p->UndoMove(move, u); continue; }

    // Update move statistics (needed for reduction/pruning decisions)

    mv_played[mv_tried] = move;
    mv_tried++;
    if (mv_tried > 1) fl_has_choice = 1; // we have a choice between at least two root moves
    if (depth > 16 && verbose) DisplayCurrmove(move, mv_tried);
    if (mv_type == MV_NORMAL) quiet_tried++;
    fl_prunable_move = !InCheck(p) && (mv_type == MV_NORMAL);

    // Set new search depth

    new_depth = depth - 1 + InCheck(p);

    // Late move reduction
  
    reduction = 0;
  
    if (use_lmr
    && depth >= 2
    && mv_tried > 3
    && mv_hist_score < hist_limit
    && alpha > -MAX_EVAL && beta < MAX_EVAL
    && !fl_check 
    &&  fl_prunable_move
    && lmr_size[1][depth][mv_tried] > 0
    && MoveType(move) != CASTLE ) {

    reduction = lmr_size[1][depth][mv_tried];

    // increase reduction on bad history score

    if (mv_hist_score < 0 
    && new_depth - reduction > 2 
    && lmr_hist_adjustement) 
       reduction++;

    new_depth -= reduction;
  }

  re_search:
   
  // PVS

  if (best == -INF)
    score = -Search(p, ply + 1, -beta, -alpha, new_depth, 0, move, last_capt, new_pv);
  else {
    score = -Search(p, ply + 1, -alpha - 1, -alpha, new_depth, 0, move, last_capt, new_pv);
    if (!abort_search && score > alpha && score < beta)
      score = -Search(p, ply + 1, -beta, -alpha, new_depth, 0, move, last_capt, new_pv);
  }

  // Reduced move scored above alpha - we need to re-search it

  if (reduction && score > alpha) {
    new_depth += reduction;
    reduction = 0;
    goto re_search;
  }

    p->UndoMove(move, u);
    if (abort_search) return 0;

  // Beta cutoff

    if (score >= beta) {
      if (!fl_check) {
        UpdateHistory(p, -1, move, depth, ply);
        for (int mv = 0; mv < mv_tried; mv++)
          DecreaseHistory(p, mv_played[mv], depth);
      }
      TransStore(p->hash_key, move, score, LOWER, depth, ply);

      // Update search time depending on whether the first move has changed

      if (depth > 4) {
        if (pv[0] != move) Timer.OnNewRootMove();
        else               Timer.OnOldRootMove();
      }

	  // Change the best move and show the new pv

      BuildPv(pv, new_pv, move);
      DisplayPv(score, pv);

      return score;
    }

    // Updating score and alpha

    if (score > best) {
      best = score;

      if (score > alpha) {
        alpha = score;

        // Update search time depending on whether the first move has changed

        if (depth > 4) {
          if (pv[0] != move) Timer.OnNewRootMove();
          else               Timer.OnOldRootMove();
        }

	    // Change the best move and show the new pv

        BuildPv(pv, new_pv, move);
        DisplayPv(score, pv);
      }
    }

  } // end of the main loop

  // Return correct checkmate/stalemate score

  if (best == -INF)
    return InCheck(p) ? -MATE + ply : DrawScore(p);

  // Save score in the transposition table

  if (*pv) {
    if (!fl_check) {
      UpdateHistory(p, -1, *pv, depth, ply);
      for (int mv = 0; mv < mv_tried; mv++)
        DecreaseHistory(p, mv_played[mv], depth);
    }
    TransStore(p->hash_key, *pv, best, EXACT, depth, ply);
    
  } else
    TransStore(p->hash_key, 0, best, UPPER, depth, ply);

  return best;
}