/// <summary> /// 构造函数 /// </summary> /// <param name="board">盘面</param> /// <param name="transpositionTable">置换表</param> /// <param name="engine">引擎</param> public SearchTT(Board board, TranspositionTable transpositionTable, PonderEngine engine) { this.Ply = 0; this.board = board; this.transpositionTable = transpositionTable; //this.bestMove = null; this.engine = engine; }
/// <summary> /// 构造函数 /// </summary> /// <param name="board">盘面</param> /// <param name="transpositionTable">置换表</param> public SearchTT(Board board, TranspositionTable transpositionTable) : this(board, transpositionTable, null) { }
public EngineStatus ExecuteCommand(string strCommand) { PrintDebugInfo("receive command:" + strCommand); UcciCommand cmd = UcciCommand.Parse(strCommand); if (status == EngineStatus.Boot) { if (cmd.Name == "ucci") { //引导状态的反馈。显示引擎的版本号、版权、作者和授权用户,例如: //id name ElephantEye 1.6 Beta,说明引擎的版本号 //id copyright 2004-2006 www.xqbase.com,说明引擎的版权 //id author Morning Yellow,说明引擎的作者 //id user ElephantEye Test Team,说明引擎授权给用户 info = "id name PonderEngine " + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; m_LogHandler.logging(info); Output.WriteLine(info); info = "id copyright 2013 by slb"; m_LogHandler.logging(info); Output.WriteLine(info); info = "id author shen longbin"; m_LogHandler.logging(info); Output.WriteLine(info); info = "id user slb test"; m_LogHandler.logging(info); Output.WriteLine(info); // TODO: 给出支持option选项 // option <选项> type <类型> [min <最小值>] [max <最大值>] // [var <可选项> [var <可选项> [...]]] [default <默认值>] //引导状态的反馈。显示引擎所支持的选项,<option>指选项的名称, //选项的类型是label(标签,非选项)、button(指令)、check(是或非)、combo(多选项)、 //spin(整数)、string(字符串)中的一种。 //option usemillisec type check default false //option usebook type check default true //引导状态的反馈,此后引擎进入空闲状态。 info = "option usebook type check default true"; m_LogHandler.logging(info); Output.WriteLine(info); info = "option bookfiles type string default " + "opening.ob"; m_LogHandler.logging(info); Output.WriteLine(info); // 这里完成一些初始化的任务 transpositionTable = new TranspositionTable(); info = "ucciok"; m_LogHandler.logging(info); Output.WriteLine(info); status = EngineStatus.Idle; } else { //如果引导状态下UCCI引擎收到其他指令,则可以退出。 info = "quited directly"; m_LogHandler.logging(info); Output.WriteLine(info); return(EngineStatus.Quit); } } else if (status == EngineStatus.Idle) { //isready //空闲状态和思考状态的指令。检测引擎是否处于就绪状态,其反馈总是readyok,该指令仅仅用来检测引擎是否能够正常接收指令。 if (cmd.Name == "isready") { //空闲状态和思考状态的反馈。表明引擎处于就绪状态(可正常接收指令)。 Output.WriteLine("readyok"); } else if (cmd.Name == "setoption") { ExecuteSetoptionCommand(cmd); } else if (cmd.Name == "position") { ExecutePositionCommand(cmd); } else if (cmd.Name == "banmoves") { // banmoves <禁止着法列表> // 空闲状态的指令。为当前局面设置禁手,以解决引擎无法处理的长打问题。当出现长打局面时, // 棋手可以操控界面向引擎发出禁手指令。例如: // position fen 1r2kab1r/2c1a4/n1c1b1n2/4p2N1/p1p6/1C4P2/P1P1P4/2N1B3C/4A4/1RBAK2R1 w - - 0 1 moves h6i4 i9h9 i4h6 h9i9 // banmoves h6i4 // 本例取自《象棋竞赛规则》(1999年版)棋例图三,由于大多数象棋引擎无法识别红方这种方式的长捉, // 所以在采用中国象棋协会的比赛规则时,遇到这种局面就必须给引擎发出禁手指令。 // 下一次发送position指令后,前面设置过的禁止着法就取消了,需要重新设置禁止着法。 // 目前UCCI界面《象棋巫师》不识别长打禁手,所以不会向引擎发送banmoves指令。 /****************** 估计永远也不会实现了 ************************/ } else if (cmd.Name == "go") { // go [ponder | draw] <思考模式> // 空闲状态的指令,此后引擎进入思考状态。让引擎根据position指令设定的棋盘来思考, // 各选项为思考方式,有三种模式可供选择: // (1) depth <深度> | infinite: // 限定搜索深度,infinite表示无限制思考(直到找到杀棋或用stop指令中止)。 // 如果深度设定为0,那么引擎可以只列出当前局面静态评价的分数,并且反馈nobestmove。 // (2) nodes <结点数>:限定搜索结点数。 // (3) time <时间> [movestogo <剩余步数> | increment <每步加时>] // [opptime <对方时间> [oppmovestogo <对方剩余步数> | oppincrement <对方每步加时>]] // 限定时间,时间单位是秒(默认)或毫秒(启用毫秒制时),movestogo适用于时段制,increment适用于加时制。 // opptime、oppmovestogo和oppincrement可以让界面把对方的用时情况告诉引擎。 // 例如:go time 120 movestogo 120 opptime 120 oppmovestogo 120 // ------- // 如果指定ponder选项,则引擎思考时时钟不走,直到接受到ponderhit指令后才计时,该选项用于后台思考, // 它只对限定时间的思考模式有效。 // 指定draw选项表示向引擎提和,引擎以bestmove提供的选项作为反馈,参阅bestmove指令。 // 注意:ponder和draw选项不能同时使用,如果界面向正在后台思考中的引擎求和, // 则使用ponderhit draw指令。 status = EngineStatus.Thinking; Board board = new Board(fen); if (moves != null && moves != "") { board.MakeMoves(moves); } if (useBook) { Move bestInOpening = OpeningBook.BestMove(openingBookFile, board); if (bestInOpening.From != 0) { PrintDebugInfo("命中开局库!"); Output.WriteLine("bestmove " + bestInOpening); status = EngineStatus.Idle; return(status); } } int idxDepth = cmd.Paras.IndexOf("depth"); int searchDepth = 4; if (idxDepth >= 0) { searchDepth = int.Parse(cmd.Paras.Substring(idxDepth + 5)); } //SimpleSearch search = new SimpleSearch(board, this); //search.NegaAlphaBeta(0, searchDepth, Evaluator.MIN_EVAL_VALUE, Evaluator.MAX_EVAL_VALUE); SearchTT search = new SearchTT(board, transpositionTable, this); //search.NegaAlphaBetaTT_old(0, searchDepth, Evaluator.MIN_EVAL_VALUE, Evaluator.MAX_EVAL_VALUE); //search.StartPVS(searchDepth, Evaluator.MIN_EVAL_VALUE, Evaluator.MAX_EVAL_VALUE); search.IterativeDeepeningSearch(searchDepth); //search.StartAlphaBetaTT(searchDepth, Evaluator.MIN_EVAL_VALUE, Evaluator.MAX_EVAL_VALUE); /************* * bestmove <最佳着法> [ponder <后台思考的猜测着法>] [draw | resign] * 思考状态的反馈,此后引擎返回空闲状态。显示思考结果,即引擎认为在当前局面下的最佳着法, * 以及猜测在这个着法后对手会有怎样的应对(即后台思考的猜测着法)。 * 通常,最佳着法是思考路线(主要变例)中的第一个着法,而后台思考的猜测着法 * 则是第二个着法。 * 在对手尚未落子时,可以根据该着法来设定局面,并作后台思考。 * 当对手走出的着法和后台思考的猜测着法吻合时,称为“后台思考命中”。 * draw选项表示引擎提和或者接受界面向引擎发送的提和请求,参阅go draw和ponderhit draw指令。 * resign选项表示引擎认输。UCCI界面在人机对弈方式下,根据不同情况, * 可以对引擎的bestmove反馈中的draw和resign选项作出相应的处理: * (1) 如果用户提和,界面向引擎发出go draw或ponderhit draw指令,而引擎反馈带draw的bestmove, * 那么界面可终止对局并判议和; * (2) 如果用户没有提和,而引擎反馈带draw的bestmove,那么界面可向用户提和, * 用户接受提和则可终止对局并判议和; * (3) 如果引擎反馈带resign的bestmove,那么界面可终止对局并判引擎认输。 * 引擎应该根据当前局面的情况(由position指令给出),以及界面是否发送了带draw的go或ponderhit指令, * 来考虑是否反馈带draw或resign的bestmove。 *************/ //TODO: bestmove Move bestMove = search.BestMove; if (bestMove == null || bestMove.From == 0) { Output.WriteLine("bestmove resign"); } else { Output.WriteLine("bestmove " + bestMove); } status = EngineStatus.Idle; } else if (cmd.Name == "quit") { //接收到quit指令后的反馈"bye"。引擎完成了退出运转前的准备工作,通知界面, //引擎将在瞬间正常退出运转。界面收到该指令后,即可关闭输入输出通道。 info = "bye"; m_LogHandler.logging(info); Output.WriteLine(info); status = EngineStatus.Quit; } } else // Thinking状态时 { //isready //空闲状态和思考状态的指令。检测引擎是否处于就绪状态,其反馈总是readyok,该指令仅仅用来检测引擎是否能够正常接收指令。 if (cmd.Name == "isready") { //空闲状态和思考状态的反馈。表明引擎处于就绪状态(可正常接收指令)。 Output.WriteLine("readyok"); } else if (cmd.Name == "ponderhit") { // ponderhit [draw] // 思考状态的指令。告诉引擎后台思考命中,现在转入正常思考模式(引擎继续处于思考状态, // 此时go指令设定的时限开始起作用)。 // 指定draw选项表示向引擎提和,引擎以bestmove提供的选项作为反馈,参阅bestmove指令。 } else if (cmd.Name == "stop") { // stop // 思考状态的指令。中止引擎的思考。另外,后台思考没有命中时,就用该指令来中止思考,然后重新输入局面。 // 注意:发出该指令并不意味着引擎将立即回到空闲状态,而是要等到引擎反馈 // bestmove或nobestmove后才表示回到空闲状态,引擎应尽可能快地作出这样的反馈。 } else { } } return(status); }