예제 #1
0
 public static Move BestMove(string openingBookFile, Board board)
 {
     using (OpeningBook book = new OpeningBook(openingBookFile))
     {
         return(book.FindBestMove(board));
     }
 }
예제 #2
0
        /// <summary>
        /// 把一盘PGN对局里的前N个着法放入对局库中
        /// </summary>
        /// <param name="pgnFilename">PGN文件名</param>
        /// <returns>加入到开局库时,返回true
        /// 如果在解析PGN时遇到不规范的棋谱时,返回false,此时控制台会打印出错误信息</returns>
        public static bool AddPgnFileToOpeningBook(string bookFilename, string pgnFilename, int maxStep)
        {
            using (OpeningBook book = new OpeningBook(bookFilename))
            {
                // 从PGN文件里读出所有着法来,这里用的是纵列格式
                string[] allmoves = PgnUtil.GetAllMovesFromPgnFile(pgnFilename);

                Board board   = new Board();
                int   numMove = 0; // 记录已走了第几步了
                foreach (string strMove in allmoves)
                {
                    if (numMove >= maxStep)
                    {
                        break;
                    }
                    try
                    {
                        // 走一步后,把盘面生成zobrist值,保存到开局库里
                        // TODO: board.CreateMoveFromString(NotationConverter.Convert(board, strMove));
                        Move move = MoveNotation.CreateMoveFromChineseNotation(board, strMove);
                        board.MakeMove(move);
                        //   Console.WriteLine("==== " + strMove + "\n" + board);
                        ++numMove;
                        ulong zobrist = Zobrist.ZoristHash(board);
                        book.InsertBoardZobrist(zobrist);
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine("--- " + strMove + " ---");
                        Console.WriteLine(e.Message);
                        Console.WriteLine(board);
                        return(false);
                    }
                } // end 对每一着法循环结束
            }
            return(true);
        }
예제 #3
0
        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);
        }