/// <summary> /// 超出边界(Fail-Soft)的Alpha-Beta搜索过程 /// </summary> /// <param name="alpha"></param> /// <param name="beta"></param> /// <param name="depth"></param> /// <param name="noNull"></param> /// <returns></returns> public int SearchFull(int alpha, int beta, int depth, bool noNull = false) { //一个Alpha-Beta完全搜索分为以下几个阶段 int value = 0; int mvHash = 0; if (situation.Distance > 0) { //1.到达水平线,则调用静态搜索(注意:由于空步裁剪,深度可能小于零) if (depth <= 0) { return(SearchQuiesc(alpha, beta)); } //1-1.检查重复局面(注意:不要再根节点检查,否则就没有走法了) value = situation.RepStatus(); if (value != 0) { return(situation.RepValue(value)); } //1-2.到达极限深度就返回局面评价 if (situation.Distance == LIMIT_DEPTH) { return(situation.Evaluate()); } //1-3.尝试置换表裁剪,并得到置换表走法 value = ProbeHash(alpha, beta, depth, out mvHash); if (value > -ChessLogic.MATE_VALUE) { return(value); } //1-5.尝试空步裁剪(根节点的Beta值是"MATE_VALUE",所以不可能发生空步裁剪) if (!noNull && !situation.InCheck() && situation.NullOkey()) { situation.NullMove(); value = -SearchFull(-beta, 1 - beta, depth - ChessLogic.NULL_DEPTH - 1, true); situation.UndoNullMove(); if (value > beta) { return(value); } } } else { mvHash = 0; } //2.初始化最佳值和最佳走法 int bestValue = -ChessLogic.MATE_VALUE; //是否一个走法都没走过(杀棋) int mvBest = 0; //是否搜索到了Beta走法或pv走法,以便保存到历史表 int hashFlag = HASH_ALPHA; //3.初始化走法排序结构 SortInfo sort = new SortInfo(); sort.Init(mvHash, this); //4.遍历走法 int mv = 0; while ((mv = sort.Next()) != 0) { if (situation.MakeMove(mv)) { //将军延伸 value = -SearchFull(-beta, -alpha, situation.InCheck() ? depth : depth - 1); situation.UndoMakeMove(); //5.进行Alpha-Beta大小判断和截断 if (value > bestValue) //找到最佳值(但不确定是Alpha、PV还是Beta走法) { bestValue = value; //bestValue就是目前要返回的最佳值,可能超出Alpha-Beta边界 if (value >= beta) //找到一个Beta走法 { mvBest = mv; break; } if (value > alpha) //找到一个PV走法 { mvBest = mv; //PV走法要保存到历史表 alpha = value; } } } } //6.所有走法都搜索完了,把最佳走法(不能是Alpha走法)保存到历史表,返回最佳值 if (bestValue == -ChessLogic.MATE_VALUE) { //如果是杀棋,就根据最佳走法保存到历史表 return(situation.Distance - ChessLogic.MATE_VALUE); } //记录到置换表 RecordHash(hashFlag, bestValue, depth, mvBest); if (mvBest != 0) { //如果不是Alpha走法,就将最佳走法保存到历史表中 SetBestMove(mvBest, depth); if (situation.Distance == 0) { //搜索根节点时,总是有一个最佳走法(因为全窗口搜索不会超出边界),将这个走法保存下来 mvResult = mvBest; } } return(bestValue); }