/// <summary> /// "go mate"に対しては "bestmove"ではなく、"checkmate.."という文字列が返ってくる。 /// これをparseする。 /// </summary> /// <param name="scanner"></param> public void HandleCheckmate(Scanner scanner) { EvalValueEx eval = null; var moves = new List <Move>(); if (scanner.PeekText("nomate")) { // 不詰を表現している(ことにする) moves.Add(Move.MATE_ENGINE_NO_MATE); } else if (scanner.PeekText("notimplemented")) { // 手番側が王手をされているとき、詰将棋エンジンが実装されていない。 moves.Add(Move.MATE_ENGINE_NOT_IMPLEMENTED); } else if (scanner.PeekText("timeout")) { // 時間切れ moves.Add(Move.MATE_TIMEOUT); } else { // 詰みを発見した。 while (!scanner.IsEof) { var token = scanner.ParseText(); var move = Core.Util.FromUsiMove(token); if (move == Move.NONE) { break; } moves.Add(move); } // {moves.Count}手で詰み…とは限らないのでエンジンによってはこれあまり良くなかったり? eval = new EvalValueEx(EvalValue.Mate - moves.Count, ScoreBound.Exact); // 手数不明の詰み //eval = new EvalValueEx(EvalValue.MatePlus , ScoreBound.Exact); } // 次のThink()が呼び出されているなら、この読み筋は、無効化されなくてはならない。 if (!ThinkingBridge.IsStopping) { ThinkReport = new UsiThinkReport() { Moves = moves, Eval = eval, ElapsedTime = ThinkingBridge.ElapsedTime, // 消費時間はサーバー計測 }; } // 確定したので格納しておく。 if (ThinkingBridge.BestMoveReceived(moves[0], Move.NONE)) { ThinkReport = UsiEngineReportMessageType.UsiThinkEnd; } }
/// <summary> /// infoコマンドを処理します。 /// </summary> private void HandleInfo(Scanner scanner) { // あとで書く。 #if false var report = new UsiThinkReport(this); // reportの情報をエンジンにも設定する if (!report.Parse(CurrBoard, scanner, this)) { return; } if ((report.PVSeq != null && report.PVSeq.Any()) || report.InfoString != null) { AddThinkReport(report); } #endif }
/// <summary> /// infoコマンドを処理します。 /// </summary> private void HandleInfo(Scanner scanner) { try { var info = new UsiThinkReport(); var parseEnd = false; while (!scanner.IsEof && !parseEnd) { switch (scanner.ParseText()) { // hash使用率 1000分率返ってくるので10で割って100分率に変換して代入する。 case "hashfull": info.HashPercentage = (float)scanner.ParseInt() / 10.0f; break; // nps case "nps": info.Nps = scanner.ParseInt(); break; // 現在の探索手 case "currmove": info.CurrentMove = scanner.ParseText(); break; // 探索ノード数 case "nodes": info.Nodes = scanner.ParseInt(); break; // 探索深さ,選択探索深さ // ここに文字が入っている可能性があるので(upperbound/lowerboundを表現するための"↑"など)文字列として扱う。 case "depth": info.Depth = scanner.ParseText(); break; case "seldepth": info.SelDepth = scanner.ParseText(); break; case "score": info.Eval = HandleInfoScore(scanner); break; case "pv": info.Moves = HandlePVSeq(scanner); //parseEnd = true; // "pv"はそのあと末尾まで。 // ここから、解釈できない文字列はinfo.MovesSuffixに追加。 info.MovesSuffix = HandlePVSuffix(scanner); break; // リポート情報のみ更新 case "time": info.ElapsedTime = TimeSpan.FromMilliseconds(scanner.ParseInt()); break; case "multipv": info.MultiPV = (int)scanner.ParseInt(); break; case "string": info.InfoString = scanner.LastText; // 残り全部 parseEnd = true; break; #if false // なんかよくわからん。あとで考える。 case "count": GodwhaleCount = scanner.ParseInt(); break; case "ranking": GodwhaleRank = scanner.ParseInt(); break; // 無視 case "currmovenumber": case "cpuload": case "refutation": case "currline": case "id": // クジラちゃん用 scanner.ParseText(); break; #endif // エラー default: throw new Exception(); } } // 次のThink()が呼び出されているなら、この読み筋は、無効化されなくてはならない。 if (!ThinkingBridge.IsStopping) { ThinkReport = info; } } catch { throw new UsiException("info 文字列の解析に失敗 : " + scanner.Text); } }