예제 #1
0
// 唯一着法检验是ElephantEye在搜索上的一大特色,用来判断用以某种深度进行的搜索是否找到了唯一着法。
// 其原理是把找到的最佳着法设成禁止着法,然后以(-WIN_VALUE, 1 - WIN_VALUE)的窗口重新搜索,
// 如果低出边界则说明其他着法都将被杀。
static bool SearchUnique(int vlBeta, int nDepth) {
  int vl, mv;
  Search2.MoveSort.ResetRoot(ROOT_UNIQUE);
  // 跳过第一个着法
  while ((mv = Search2.MoveSort.NextRoot()) != 0) {
    if (Search.pos.MakeMove(mv)) {
      vl = -SearchCut(1 - vlBeta, Search.pos.LastMove().ChkChs > 0 ? nDepth : nDepth - 1);
      Search.pos.UndoMakeMove();
      if (Search2.bStop || vl >= vlBeta) {
        return false;
      }
    }
  }
  return true;
}
예제 #2
0
/* 根结点搜索例程,和完全搜索的区别有以下几点:
 *
 * 1. 省略无害裁剪(也不获取置换表着法);
 * 2. 不使用空着裁剪;
 * 3. 选择性延伸只使用将军延伸;
 * 4. 过滤掉禁止着法;
 * 5. 搜索到最佳着法时要做很多处理(包括记录主要变例、结点排序等);
 * 6. 不更新历史表和杀手着法表。
 */
static int SearchRoot(int nDepth) {
  int nNewDepth, vlBest, vl, mv, nCurrMove;
#ifndef CCHESS_A3800
  uint32_t dwMoveStr;
#endif
  uint16_t wmvPvLine[LIMIT_DEPTH];
  // 根结点搜索例程包括以下几个步骤:

  // 1. 初始化
  vlBest = -MATE_VALUE;
  Search2.MoveSort.ResetRoot();

  // 2. 逐一搜索每个着法(要过滤禁止着法)
  nCurrMove = 0;
  while ((mv = Search2.MoveSort.NextRoot()) != 0) {
    if (Search.pos.MakeMove(mv)) {
#ifndef CCHESS_A3800
      if (Search2.bPopCurrMove || Search.bDebug) {
        dwMoveStr = MOVE_COORD(mv);
        nCurrMove ++;
        printf("info currmove %.4s currmovenumber %d\n", (const char *) &dwMoveStr, nCurrMove);
        fflush(stdout);
      }
#endif

      // 3. 尝试选择性延伸(只考虑将军延伸)
      nNewDepth = (Search.pos.LastMove().ChkChs > 0 ? nDepth : nDepth - 1);

      // 4. 主要变例搜索
      if (vlBest == -MATE_VALUE) {
        vl = -SearchPV(-MATE_VALUE, MATE_VALUE, nNewDepth, wmvPvLine);
        __ASSERT(vl > vlBest);
      } else {
        vl = -SearchCut(-vlBest, nNewDepth);
        if (vl > vlBest) { // 这里不需要" && vl < MATE_VALUE"了
          vl = -SearchPV(-MATE_VALUE, -vlBest, nNewDepth, wmvPvLine);
        }
      }
      Search.pos.UndoMakeMove();
      if (Search2.bStop) {
        return vlBest;
      }

      // 5. Alpha-Beta边界判定("vlBest"代替了"SearchPV()"中的"vlAlpha")
      if (vl > vlBest) {

        // 6. 如果搜索到第一着法,那么"未改变最佳着法"的计数器加1,否则清零
        Search2.nUnchanged = (vlBest == -MATE_VALUE ? Search2.nUnchanged + 1 : 0);
        vlBest = vl;

        // 7. 搜索到最佳着法时记录主要变例
        AppendPvLine(Search2.wmvPvLine, mv, wmvPvLine);
#ifndef CCHESS_A3800
        PopPvLine(nDepth, vl);
#endif

        // 8. 如果要考虑随机性,则Alpha值要作随机浮动,但已搜索到杀棋时不作随机浮动
        if (vlBest > -WIN_VALUE && vlBest < WIN_VALUE) {
          vlBest += (Search.rc4Random.NextLong() & Search.nRandomMask) -
              (Search.rc4Random.NextLong() & Search.nRandomMask);
          vlBest = (vlBest == Search.pos.DrawValue() ? vlBest - 1 : vlBest);
        }

        // 9. 更新根结点着法列表
        Search2.MoveSort.UpdateRoot(mv);
      }
    }
  }
  return vlBest;
}
예제 #3
0
/* 主要变例完全搜索例程,和零窗口完全搜索的区别有以下几点:
 *
 * 1. 启用内部迭代加深启发;
 * 2. 不使用有负面影响的裁剪;
 * 3. Alpha-Beta边界判定复杂;
 * 4. PV结点要获取主要变例;
 * 5. 考虑PV结点处理最佳着法的情况。
 */
static int SearchPV(int vlAlpha, int vlBeta, int nDepth, uint16_t *lpwmvPvLine) {
  int nNewDepth, nHashFlag, vlBest, vl;
  int mvBest, mvHash, mv, mvEvade;
  MoveSortStruct MoveSort;
  uint16_t wmvPvLine[LIMIT_DEPTH];
  // 完全搜索例程包括以下几个步骤:

  // 1. 在叶子结点处调用静态搜索;
  *lpwmvPvLine = 0;
  if (nDepth <= 0) {
    __ASSERT(nDepth >= -NULL_DEPTH);
    return SearchQuiesc(Search.pos, vlAlpha, vlBeta);
  }
  Search2.nAllNodes ++;

  // 2. 无害裁剪;
  vl = HarmlessPruning(Search.pos, vlBeta);
  if (vl > -MATE_VALUE) {
    return vl;
  }

  // 3. 置换裁剪;
  vl = ProbeHash(Search.pos, vlAlpha, vlBeta, nDepth, NO_NULL, mvHash);
  if (Search.bUseHash && vl > -MATE_VALUE) {
    // 由于PV结点不适用置换裁剪,所以不会发生PV路线中断的情况
    return vl;
  }

  // 4. 达到极限深度,直接返回评价值;
  __ASSERT(Search.pos.nDistance > 0);
  if (Search.pos.nDistance == LIMIT_DEPTH) {
    return Evaluate(Search.pos, vlAlpha, vlBeta);
  }
  __ASSERT(Search.pos.nDistance < LIMIT_DEPTH);

  // 5. 中断调用;
  Search2.nMainNodes ++;
  vlBest = -MATE_VALUE;
  if ((Search2.nMainNodes & Search.nCountMask) == 0 && Interrupt()) {
    return vlBest;
  }

  // 6. 内部迭代加深启发;
  if (nDepth > IID_DEPTH && mvHash == 0) {
    __ASSERT(nDepth / 2 <= nDepth - IID_DEPTH);
    vl = SearchPV(vlAlpha, vlBeta, nDepth / 2, wmvPvLine);
    if (vl <= vlAlpha) {
      vl = SearchPV(-MATE_VALUE, vlBeta, nDepth / 2, wmvPvLine);
    }
    if (Search2.bStop) {
      return vlBest;
    }
    mvHash = wmvPvLine[0];
  }

  // 7. 初始化;
  mvBest = 0;
  nHashFlag = HASH_ALPHA;
  if (Search.pos.LastMove().ChkChs > 0) {
    // 如果是将军局面,那么生成所有应将着法;
    mvEvade = MoveSort.InitEvade(Search.pos, mvHash, Search2.wmvKiller[Search.pos.nDistance]);
  } else {
    // 如果不是将军局面,那么使用正常的着法列表。
    MoveSort.InitFull(Search.pos, mvHash, Search2.wmvKiller[Search.pos.nDistance]);
    mvEvade = 0;
  }

  // 8. 按照"MoveSortStruct::NextFull()"例程的着法顺序逐一搜索;
  while ((mv = MoveSort.NextFull(Search.pos)) != 0) {
    if (Search.pos.MakeMove(mv)) {

      // 9. 尝试选择性延伸;
      nNewDepth = (Search.pos.LastMove().ChkChs > 0 || mvEvade != 0 ? nDepth : nDepth - 1);

      // 10. 主要变例搜索;
      if (vlBest == -MATE_VALUE) {
        vl = -SearchPV(-vlBeta, -vlAlpha, nNewDepth, wmvPvLine);
      } else {
        vl = -SearchCut(-vlAlpha, nNewDepth);
        if (vl > vlAlpha && vl < vlBeta) {
          vl = -SearchPV(-vlBeta, -vlAlpha, nNewDepth, wmvPvLine);
        }
      }
      Search.pos.UndoMakeMove();
      if (Search2.bStop) {
        return vlBest;
      }

      // 11. Alpha-Beta边界判定;
      if (vl > vlBest) {
        vlBest = vl;
        if (vl >= vlBeta) {
          mvBest = mv;
          nHashFlag = HASH_BETA;
          break;
        }
        if (vl > vlAlpha) {
          vlAlpha = vl;
          mvBest = mv;
          nHashFlag = HASH_PV;
          AppendPvLine(lpwmvPvLine, mv, wmvPvLine);
        }
      }
    }
  }

  // 12. 更新置换表、历史表和杀手着法表。
  if (vlBest == -MATE_VALUE) {
    __ASSERT(Search.pos.IsMate());
    return Search.pos.nDistance - MATE_VALUE;
  } else {
    RecordHash(Search.pos, nHashFlag, vlBest, nDepth, mvEvade == 0 ? mvBest : mvEvade);
    if (mvBest != 0 && !MoveSort.GoodCap(Search.pos, mvBest)) {
      SetBestMove(mvBest, nDepth, Search2.wmvKiller[Search.pos.nDistance]);
    }
    return vlBest;
  }
}
예제 #4
0
// 零窗口完全搜索例程
static int SearchCut(int vlBeta, int nDepth, bool bNoNull = false) {
  int nNewDepth, vlBest, vl;
  int mvHash, mv, mvEvade;
  MoveSortStruct MoveSort;
  // 完全搜索例程包括以下几个步骤:

  // 1. 在叶子结点处调用静态搜索;
  if (nDepth <= 0) {
    __ASSERT(nDepth >= -NULL_DEPTH);
    return SearchQuiesc(Search.pos, vlBeta - 1, vlBeta);
  }
  Search2.nAllNodes ++;

  // 2. 无害裁剪;
  vl = HarmlessPruning(Search.pos, vlBeta);
  if (vl > -MATE_VALUE) {
    return vl;
  }

  // 3. 置换裁剪;
  vl = ProbeHash(Search.pos, vlBeta - 1, vlBeta, nDepth, bNoNull, mvHash);
  if (Search.bUseHash && vl > -MATE_VALUE) {
    return vl;
  }

  // 4. 达到极限深度,直接返回评价值;
  if (Search.pos.nDistance == LIMIT_DEPTH) {
    return Evaluate(Search.pos, vlBeta - 1, vlBeta);
  }
  __ASSERT(Search.pos.nDistance < LIMIT_DEPTH);

  // 5. 中断调用;
  Search2.nMainNodes ++;
  vlBest = -MATE_VALUE;
  if ((Search2.nMainNodes & Search.nCountMask) == 0 && Interrupt()) {
    return vlBest;
  }

  // 6. 尝试空着裁剪;
  if (Search.bNullMove && !bNoNull && Search.pos.LastMove().ChkChs <= 0 && Search.pos.NullOkay()) {
    Search.pos.NullMove();
    vl = -SearchCut(1 - vlBeta, nDepth - NULL_DEPTH - 1, NO_NULL);
    Search.pos.UndoNullMove();
    if (Search2.bStop) {
      return vlBest;
    }

    if (vl >= vlBeta) {
      if (Search.pos.NullSafe()) {
        // a. 如果空着裁剪不带检验,那么记录深度至少为(NULL_DEPTH + 1);
        RecordHash(Search.pos, HASH_BETA, vl, MAX(nDepth, NULL_DEPTH + 1), 0);
        return vl;
      } else if (SearchCut(vlBeta, nDepth - NULL_DEPTH, NO_NULL) >= vlBeta) {
        // b. 如果空着裁剪带检验,那么记录深度至少为(NULL_DEPTH);
        RecordHash(Search.pos, HASH_BETA, vl, MAX(nDepth, NULL_DEPTH), 0);
        return vl;
      }
    }
  }

  // 7. 初始化;
  if (Search.pos.LastMove().ChkChs > 0) {
    // 如果是将军局面,那么生成所有应将着法;
    mvEvade = MoveSort.InitEvade(Search.pos, mvHash, Search2.wmvKiller[Search.pos.nDistance]);
  } else {
    // 如果不是将军局面,那么使用正常的着法列表。
    MoveSort.InitFull(Search.pos, mvHash, Search2.wmvKiller[Search.pos.nDistance]);
    mvEvade = 0;
  }

  // 8. 按照"MoveSortStruct::NextFull()"例程的着法顺序逐一搜索;
  while ((mv = MoveSort.NextFull(Search.pos)) != 0) {
    if (Search.pos.MakeMove(mv)) {

      // 9. 尝试选择性延伸;
      nNewDepth = (Search.pos.LastMove().ChkChs > 0 || mvEvade != 0 ? nDepth : nDepth - 1);

      // 10. 零窗口搜索;
      vl = -SearchCut(1 - vlBeta, nNewDepth);
      Search.pos.UndoMakeMove();
      if (Search2.bStop) {
        return vlBest;
      }

      // 11. 截断判定;
      if (vl > vlBest) {
        vlBest = vl;
        if (vl >= vlBeta) {
          RecordHash(Search.pos, HASH_BETA, vlBest, nDepth, mv);
          if (!MoveSort.GoodCap(Search.pos, mv)) {
            SetBestMove(mv, nDepth, Search2.wmvKiller[Search.pos.nDistance]);
          }
          return vlBest;
        }
      }
    }
  }

  // 12. 不截断措施。
  if (vlBest == -MATE_VALUE) {
    __ASSERT(Search.pos.IsMate());
    return Search.pos.nDistance - MATE_VALUE;
  } else {
    RecordHash(Search.pos, HASH_ALPHA, vlBest, nDepth, mvEvade);
    return vlBest;
  }
}
예제 #5
0
// Alpha-Beta 搜索
int SearchAlphaBeta ( int depth, int alpha, int beta ) {
	int mv, vl;
	int bmv[nBest], bvl[nBest];
	ClearBmvBvl ( bmv, bvl );
	int hash_type = HASH_TYPE_ALPHA;
	MoveSortStruct mvsort;

	if ( TimeOut() ) { // 超时
		return bvl[0];
	}

	// 无害裁剪
	vl = HarmlessPruning ();
	if ( vl > - MATE_VALUE ) {
		return vl;
	}

	// 置换裁剪
	vl = QueryValueInHashTable ( depth, alpha, beta );
	if ( vl > - MATE_VALUE ) {
		Search.bmv[0] = QueryMoveInHashTable ( depth, alpha, beta );
		Search.bvl[0] = vl;
		return vl;
	}

	// 达到极限深度
	if ( depth <= 0 ) {
		return SearchQuiesc ( alpha, beta );
	}

	// 内部迭代加深启发
	if ( depth > 2 ) {
		mv = QueryMoveInHashTableWithoutLimit ();
		if ( mv == 0 ) {
			SearchAlphaBeta ( depth / 2, alpha, beta );
			if ( TimeOut() ) { // 超时
				return bvl[0];
			}
		}
	}

	// 生成着法
	int nMoveNum = mvsort.InitMove ();
	Search.nNode ++;

	// 大搜索
	while ( (mv = mvsort.NextMove()) != 0 ) {
		pos.MakeMove ( mv );
		int newDepth = ( pos.checked || nMoveNum == 1 ) ? depth : depth - 1;
		vl = - SearchCut ( newDepth, - alpha );
		if ( vl > alpha && vl < beta ) {
			vl = - SearchAlphaBeta ( newDepth, -beta, -alpha );
		}
		pos.UndoMakeMove ();

		if ( TimeOut() ) {
			return bvl[0];
		}

		UpdateBmvBvl ( bmv, bvl, mv, vl );

		if ( bvl[0] >= beta ) {
			Search.nBeta ++;
			hash_type = HASH_TYPE_BETA;
			break;
		}
		if ( bvl[0] > alpha ) {
			alpha = bvl[0];
			hash_type = HASH_TYPE_PV;
		}
	}

	// 最后
	InsertInfoToHashTable ( depth, bmv[0], bvl[0], hash_type );
	InsertHistoryTable ( bmv[0], depth );
	CopyBmvBvl ( Search.bmv, Search.bvl, bmv, bvl );
	return bvl[0];
}
예제 #6
0
// 零窗口搜索
int SearchCut ( int depth, int beta, bool bNoNull = false ) {
	int mv, vl;
	int bmv = 0;
	int bvl = - MATE_VALUE;
	MoveSortStruct mvsort;

	if ( TimeOut() ) { // 超时
		return bvl;
	}

	// 无害裁剪
	vl = HarmlessPruning ();
	if ( vl > - MATE_VALUE ) {
		return vl;
	}

	// 置换裁剪
	vl = QueryValueInHashTable ( depth, beta - 1, beta );
	if ( vl > - MATE_VALUE ) {
		return vl;
	}

	// 达到极限深度
	if ( depth <= 0 ) {
		return SearchQuiesc ( beta - 1, beta );
	}

	// 空着裁剪 : 大切に
	if ( !bNoNull && pos.checked == false && pos.NullOkay() ) {
		pos.NullMove ();
		vl = - SearchCut ( depth - NULL_DEPTH - 1, beta, true );
		pos.UndoNullMove ();
		if ( TimeOut() ) { // 超时
			return bvl;
		}

		if ( vl >= beta ) {
			if ( pos.NullSafe() ) {
				InsertInfoToHashTable ( MAX(depth, NULL_DEPTH + 1), 0, vl, HASH_TYPE_BETA );
				return vl;
			}
			else if ( SearchCut(depth - NULL_DEPTH, beta, true) >= beta ) {
				InsertInfoToHashTable ( MAX(depth, NULL_DEPTH), 0, vl, HASH_TYPE_BETA );
				return vl;
			}
		}
	}

	// 生成着法
	int nMoveNum = mvsort.InitMove ();
	Search.nNode ++;

	// 大搜索
	while ( (mv = mvsort.NextMove()) != 0 ) {
		pos.MakeMove ( mv );
		int newDepth = ( pos.checked || nMoveNum == 1 ) ? depth : depth - 1;
		vl = - SearchCut ( newDepth, 1 - beta );
		pos.UndoMakeMove ();

		if ( TimeOut() ) { // 超时
			return bvl;
		}

		// 边界
		if ( vl > bvl ) {
			bvl = vl;
			bmv = mv;
			if ( bvl >= beta ) {
				Search.nBeta ++;
				InsertInfoToHashTable ( depth, bmv, bvl, HASH_TYPE_BETA );
				InsertHistoryTable ( bmv, depth );
				return bvl;
			}
		}
	}

	// 最后
	InsertInfoToHashTable ( depth, bmv, bvl, HASH_TYPE_ALPHA );
	return bvl;
}