/// <summary> /// 棋譜に符号を追加します。 /// /// KifuIO を通して使ってください。 /// /// ①コマ送り用。 /// ②「成り」フラグの更新用。 /// ③マウス操作用 /// /// カレントノードは変更しません。 /// </summary> public void AppendChildA_New( Node <ShootingStarlightable, KyokumenWrapper> newNode ) { System.Diagnostics.Debug.Assert(!this.ContainsKey_NextNodes(Util_Sky.ToSfenMoveText(newNode.Key))); // SFENをキーに、次ノードを増やします。 this.Add_NextNode(Util_Sky.ToSfenMoveText(newNode.Key), newNode); newNode.PreviousNode = this; }
public static KifuNode MovebetuSky_ToHubNode(Dictionary <ShootingStarlightable, KyokumenWrapper> movebetuSkys, Playerside nextTebanside) { KifuNode hubNode = new KifuNodeImpl(null, null, Playerside.Empty); foreach (KeyValuePair <ShootingStarlightable, KyokumenWrapper> nextNode in movebetuSkys) { hubNode.Add_NextNode( Util_Sky.ToSfenMoveText(nextNode.Key), new KifuNodeImpl(nextNode.Key, nextNode.Value, nextTebanside) ); } return(hubNode); }
/// <summary> /// 取った駒を差替えます。 /// /// 棋譜読取時用です。マウス操作時は、流れが異なるので使えません。 /// </summary> public void AppendChildB_Swap( PieceType tottaSyurui, SkyConst src_Sky, string hint ) { if (this.CountTesumi(this.CurNode) < 1) { // ルートしか無いなら goto gt_EndMethod; } if (null == src_Sky) { throw new Exception("ノードを追加しようとしましたが、指定されたnewSkyがヌルです。"); } Playerside genTebanside = ((KifuNode)this.CurNode).Tebanside; // 現在のノードを削除します。そのとき、もともとのキー を覚えておきます。 ShootingStarlightable motoKey = (ShootingStarlightable)this.PopCurrentNode().Key; // もともとのキーの、取った駒の種類だけを差替えます。 RO_ShootingStarlight sasikaeKey = Util_Sky.New(motoKey.LongTimeAgo, motoKey.Now, tottaSyurui);//motoKey.Finger, // キーを差替えたノード Node <ShootingStarlightable, KyokumenWrapper> sasikaeNode = new KifuNodeImpl(sasikaeKey, new KyokumenWrapper(src_Sky), genTebanside); System.Diagnostics.Debug.Assert(!this.CurNode.ContainsKey_NextNodes(Util_Sky.ToSfenMoveText(sasikaeNode.Key))); // さきほど カレントノードを削除したので、 // 今、カレントノードは、1つ前のノードになっています。 // ここに、差替えたノードを追加します。 this.CurNode.Add_NextNode(Util_Sky.ToSfenMoveText(sasikaeNode.Key), sasikaeNode); sasikaeNode.PreviousNode = this.CurNode; this.CurNode = sasikaeNode; Logger.Trace("リンクトリストの、最終ノードは差し替えられた hint=[" + hint + "] item=[" + Util_Sky.ToSfenMoveText(sasikaeKey) + "]"); // memberName=[" + memberName + "] sourceFilePath=[" + sourceFilePath + "] sourceLineNumber=[" + sourceLineNumber + "] gt_EndMethod: ; }
/// <summary> /// 棋譜ツリーの、ノードに格納されている、局面評価明細を、出力していきます。 /// </summary> public void Write_ForeachLeafs( IEngineConf engine, string nodePath, KifuNode node, KifuTree kifu, PlayerInfo playerInfo, string relFolder, ReportEnvironment reportEnvironment ) { // 次ノードの有無 if (0 < node.Count_NextNodes) { // 先に奥の枝から。 node.Foreach_NextNodes((string key, Node <ShootingStarlightable, KyokumenWrapper> nextNode, ref bool toBreak) => { double score = ((KifuNode)nextNode).KyHyoka.Total(); this.Write_ForeachLeafs( engine, nodePath + " " + Util_Sky.ToSfenMoveTextForFilename(nextNode.Key), (KifuNode)nextNode, kifu, playerInfo, relFolder + ((int)score).ToString() + "点_" + Util_Sky.ToSfenMoveText(nextNode.Key) + "/", //relFolder + ((int)((KifuNode)nextNode).KyHyoka.Total()).ToString() + "点_" + Util_Sky.ToSfenMoveText(nextNode.Key) + "/", reportEnvironment ); }); } // このノード // // 盤1個分のログの準備 // this.Log_Board( engine, nodePath, node, kifu, relFolder, reportEnvironment ); }
/// <summary> /// 次の局面の一覧をもった、入れ物ノードを返します。 /// </summary> /// <param name="kifu"></param> /// <param name="pside_genTeban"></param> /// <returns></returns> public static KifuNode ToNextNodes_AsHubNode( Maps_OneAndMulti <Finger, ShootingStarlightable> komabetuAllMove, Node <ShootingStarlightable, KyokumenWrapper> siteiNode, Playerside pside_genTeban) { KifuNode hubNode = new KifuNodeImpl(null, null, Playerside.Empty);//蝶番 #if DEBUG string dump = komabetuAllMove.Dump(); #endif foreach (KeyValuePair <Finger, List <ShootingStarlightable> > entry1 in komabetuAllMove.Items) { Finger figKoma = entry1.Key;// 駒 // 駒の動ける升全て foreach (ShootingStarlightable move in entry1.Value) { RO_Star_Koma koma = Util_Koma.AsKoma(move.Now); SyElement masu = koma.Masu; SkyConst nextSky = Util_Sasu.Sasu(siteiNode.Value.ToKyokumenConst, figKoma, masu, pside_genTeban); Node <ShootingStarlightable, KyokumenWrapper> nextNode = new KifuNodeImpl(move, new KyokumenWrapper(nextSky), KifuNodeImpl.GetReverseTebanside(pside_genTeban));//次のノード string sfenText = Util_Sky.ToSfenMoveText(move); if (hubNode.ContainsKey_NextNodes(sfenText)) { // 既存の指し手なら無視 System.Console.WriteLine("既存の指し手なので無視します。sfenText=[" + sfenText + "]"); } else { hubNode.Add_NextNode(Util_Sky.ToSfenMoveText(move), nextNode); } } } return(hubNode); }
/// <summary> /// 棋譜データを元に、符号リスト2(*1)を出力します。 /// /// *1…「position startpos moves 7g7f 3c3d 2g2f」といった書き方。 /// /// </summary> /// <param name="fugoList"></param> public static string ToSfen_PositionString(KifuTree kifu) { StringBuilder sb = new StringBuilder(); sb.Append("position "); sb.Append(kifu.GetProperty(KifuTreeImpl.PropName_Startpos)); sb.Append(" moves "); int count = 0; kifu.ForeachHonpu(kifu.CurNode, (int tesumi, KyokumenWrapper kWrap, Node <ShootingStarlightable, KyokumenWrapper> node6, ref bool toBreak) => { if (0 == tesumi) { goto gt_EndLoop; } sb.Append(Util_Sky.ToSfenMoveText(node6.Key)); //// TODO:デバッグ用 //switch (move.TottaKoma) //{ // case KomaSyurui.UNKNOWN: // case KomaSyurui.TOTTA_KOMA_NASI: // break; // default: // sb.Append("("); // sb.Append(Converter.SyuruiToSfen(move.Pside,move.TottaKoma)); // sb.Append(")"); // break; //} sb.Append(" "); gt_EndLoop: count++; }); return(sb.ToString()); }
/// <summary> /// 棋譜ツリーの、ノードのネクストノードに、点数を付けていきます。 /// </summary> public void Tensuduke_ForeachLeafs( string nodePath, KifuNode node, KifuTree kifu, Kokoro kokoro, PlayerInfo playerInfo, ReportEnvironment reportEnvironment,//MinimaxEngineImpl.REPORT_ENVIRONMENT GraphicalLog_File logF_kiki ) { // 次ノードの有無 if (node.Count_NextNodes < 1) { // 次ノードが無ければ、このノードが、葉です。 // 点数を付けます。 // 局面スコア node.KyHyoka.Clear(); // 妄想と、指定のノードを比較し、点数付けします。 foreach (Tenonagare nagare in kokoro.TenonagareItems) { node.KyHyoka.Add( nagare.Name.ToString(), this.hyokaEngineImpl.LetHandan(nagare, node, playerInfo) ); } #if DEBUG // // 盤1個分のログの準備 // this.Log_Board( nodePath, node, kifu, reportEnvironment, logF_kiki ); #endif } else { node.Foreach_NextNodes((string key, Node <ShootingStarlightable, KyokumenWrapper> nextNode, ref bool toBreak) => { this.Tensuduke_ForeachLeafs( nodePath + " " + Util_Sky.ToSfenMoveText(nextNode.Key), (KifuNode)nextNode, kifu, kokoro, playerInfo, reportEnvironment, logF_kiki ); }); // このノードが、自分の手番かどうか。 bool jibun = playerInfo.Playerside == kifu.CountPside(node); if (jibun) { // 自分のノードの場合、次ノードの中で一番点数の高いもの。 double maxScore = double.MinValue; node.Foreach_NextNodes((string key, Node <ShootingStarlightable, KyokumenWrapper> nextNode, ref bool toBreak) => { double score = ((KifuNode)nextNode).KyHyoka.Total(); if (maxScore < score) { maxScore = score; } }); node.SetBranchKyHyoka(new KyHyokaImpl(maxScore)); } else { // 相手のノードの場合、次ノードの中で一番点数の低いもの。 double minScore = double.MaxValue; node.Foreach_NextNodes((string key, Node <ShootingStarlightable, KyokumenWrapper> nextNode, ref bool toBreak) => { double score = ((KifuNode)nextNode).KyHyoka.Total(); if (score < minScore) { minScore = score; } }); node.SetBranchKyHyoka(new KyHyokaImpl(minScore)); } } }
/// <summary> /// これが通称【水際のいんちきプログラム】なんだぜ☆ /// 必要により、【成り】の指し手を追加します。 /// </summary> public static void AddNariMove( KifuNode node_yomiCur, KifuNode hubNode ) { Dictionary <string, ShootingStarlightable> newMoveList = new Dictionary <string, ShootingStarlightable>(); hubNode.Foreach_NextNodes((string key, Node <ShootingStarlightable, KyokumenWrapper> nextNode, ref bool toBreak) => { RO_Star_Koma srcKoma = Util_Koma.AsKoma(nextNode.Key.LongTimeAgo); RO_Star_Koma dstKoma = Util_Koma.AsKoma(nextNode.Key.Now); bool isPromotionable; if (!Converter04.IsPromotionable(out isPromotionable, srcKoma, dstKoma)) { // エラー goto gt_Next1; } if (isPromotionable) { ShootingStarlightable move = new RO_ShootingStarlight( //figKoma,//駒 srcKoma,// 移動元 new RO_Star_Koma( dstKoma.Pside, dstKoma.Masu, KomaSyurui14Array.ToNariCase(dstKoma.Syurui) //強制的に【成り】に駒の種類を変更 ), // 移動先 PieceType.None //取った駒不明 ); // TODO: 一段目の香車のように、既に駒は成っている場合があります。無い指し手だけ追加するようにします。 string moveStr = Util_Sky.ToSfenMoveText(move);//重複防止用のキー if (!newMoveList.ContainsKey(moveStr)) { newMoveList.Add(moveStr, move); } } gt_Next1: ; }); // 新しく作った【成り】の指し手を追加します。 foreach (ShootingStarlightable newMove in newMoveList.Values) { // 指す前の駒 RO_Star_Koma sasumaenoKoma = Util_Koma.AsKoma(newMove.LongTimeAgo); // 指した駒 RO_Star_Koma sasitaKoma = Util_Koma.AsKoma(newMove.Now); // 現局面 SkyConst src_Sky = node_yomiCur.Value.ToKyokumenConst; // 指す前の駒を、盤上のマス目で指定 Finger figSasumaenoKoma = Util_Sky.Fingers_AtMasuNow(src_Sky, sasumaenoKoma.Masu).ToFirst(); // 新たな局面 KyokumenWrapper kyokumenWrapper = new KyokumenWrapper(Util_Sasu.Sasu(src_Sky, figSasumaenoKoma, sasitaKoma.Masu, KifuNodeImpl.GetReverseTebanside(node_yomiCur.Tebanside))); try { string moveStr = Util_Sky.ToSfenMoveText(newMove); if (!hubNode.ContainsKey_NextNodes(moveStr)) { // 指し手が既存でない局面だけを追加します。 hubNode.Add_NextNode( moveStr, new KifuNodeImpl( newMove, kyokumenWrapper,//node_yomiCur.Value,//FIXME: 成りの手を指した局面を作りたい。 KifuNodeImpl.GetReverseTebanside(node_yomiCur.Tebanside) ) ); } } catch (Exception ex) { // 既存の指し手 StringBuilder sb = new StringBuilder(); { hubNode.Foreach_NextNodes((string key, Node <ShootingStarlightable, KyokumenWrapper> nextNode, ref bool toBreak) => { sb.Append("「"); sb.Append(Util_Sky.ToSfenMoveText(nextNode.Key)); sb.Append("」"); }); } //>>>>> エラーが起こりました。 // どうにもできないので ログだけ取って、上に投げます。 Logger.Error(ex.GetType().Name + " " + ex.Message + ":新しく作った「成りの指し手」を既存ノードに追加していた時です。:追加したい指し手=「" + Util_Sky.ToSfenMoveText(newMove) + "」既存の手=" + sb.ToString()); throw; } } // gt_EndMethod: // ; }
public void Go(string btime, string wtime, string byoyomi, string binc, string winc) { // ┏━━━━サンプル・プログラム━━━━┓ int latestTesumi = this.Game.Kifu.CountTesumi(this.Game.Kifu.CurNode); //現・手目済 this.PlayerInfo.Playerside = this.Game.Kifu.CountPside(latestTesumi); // 先後 //#if DEBUG // MessageBox.Show("["+latestTesumi+"]手目済 ["+this.owner.PlayerInfo.Playerside+"]の手番"); //#endif SkyConst src_Sky = this.Game.Kifu.NodeAt(latestTesumi).Value.ToKyokumenConst;//現局面 // + line Logger.Trace("将棋サーバー「" + latestTesumi + "手目、きふわらべ さんの手番ですよ!」 "); Result_Ajimi result_Ajimi = this.AjimiEngine.Ajimi(src_Sky); //------------------------------------------------------------ // わたしの手番のとき、王様が 将棋盤上からいなくなっていれば、投了します。 //------------------------------------------------------------ // // 将棋GUI『きふならべ』用☆ 将棋盤上に王さまがいないときに、本将棋で go コマンドが送られてくることは無いのでは☆? // switch (result_Ajimi) { case Result_Ajimi.Lost_SenteOh: // 先手の王さまが将棋盤上にいないとき☆ case Result_Ajimi.Lost_GoteOh: // または、後手の王さまが将棋盤上にいないとき☆ { //------------------------------------------------------------ // 投了 //------------------------------------------------------------ // // 図. // // log.txt // ┌──────────────────────────────────────── // ~ // │2014/08/02 2:36:21< bestmove resign // │ // // この将棋エンジンは、後手とします。 // 20手目、投了 を決め打ちで返します。 Playing.Send("bestmove resign"); //投了 } break; default: // どちらの王さまも、まだまだ健在だぜ☆! { //------------------------------------------------------------ // 指し手のチョイス //------------------------------------------------------------ bool enableLog = false; bool isHonshogi = true; // 指し手を決めます。 ShootingStarlightable bestMove = this.shogisasi.WA_Bestmove( enableLog, isHonshogi, this.Game.Kifu, this.PlayerInfo ); if (Util_Sky.isEnableSfen(bestMove)) { string sfenText = Util_Sky.ToSfenMoveText(bestMove); Logger.Trace("(Warabe)指し手のチョイス: bestmove=[" + sfenText + "]" + " 棋譜=" + KirokuGakari.ToJapaneseKifuText(this.Game.Kifu)); Playing.Send("bestmove " + sfenText); //指し手を送ります。 } else // 指し手がないときは、SFENが書けない☆ 投了だぜ☆ { Logger.Trace("(Warabe)指し手のチョイス: 指し手がないときは、SFENが書けない☆ 投了だぜ☆ww(>_<)" + " 棋譜=" + KirokuGakari.ToJapaneseKifuText(this.Game.Kifu)); // 投了w! Playing.Send("bestmove resign"); } } break; } // ┗━━━━サンプル・プログラム━━━━┛ }
/// <summary> /// 指し手を決めます。 /// </summary> /// <param name="enableLog"></param> /// <param name="isHonshogi"></param> /// <param name="kifu"></param> /// <param name="playerInfo"></param> /// <param name="logTag"></param> /// <returns></returns> public ShootingStarlightable WA_Bestmove( bool enableLog, bool isHonshogi, KifuTree kifu, PlayerInfo playerInfo ) { // 「移動」タイプの狙いを、どんどん付け足します。 this.Kokoro.Omoituki( playerInfo.Playerside, (KifuNode)kifu.CurNode, this.Seikaku); // // 指し手生成ルーチンで、棋譜ツリーを作ります。 // SsssLogGenjo ssssLog = new SsssLogGenjoImpl(enableLog); MoveGenRoutine.WAA_Yomu_Start(kifu, isHonshogi, ssssLog); // デバッグ用だが、メソッドはこのオブジェクトを必要としてしまう。 GraphicalLog_File logF_kiki = new GraphicalLog_File(); // 点数を付ける(葉ノードに点数を付け、途中のノードの点数も出します) this.MinimaxEngine.Tensuduke_ForeachLeafs( Util_Sky.ToSfenMoveText(kifu.CurNode.Key), (KifuNode)kifu.CurNode, kifu, this.Kokoro, playerInfo, ShogisasiImpl.ReportEnvironment, logF_kiki ); #if DEBUG // 評価明細のログ出力。 this.kyHyokaWriter.Write_ForeachLeafs( Util_Sky.ToSfenMoveText(kifu.CurNode.Key), (KifuNode)kifu.CurNode, kifu, playerInfo, "" + Util_Sky.ToSfenMoveText(kifu.CurNode.Key) + "/", ShogisasiImpl.ReportEnvironment ); if (0 < logF_kiki.boards.Count)//ログが残っているなら { // // ログの書き出し // Util_GraphicalLog.Log( true,//enableLog, "#評価ログ", "[" + Util_GraphicalLog.BoardFileLog_ToJsonStr(logF_kiki) + "]" ); // 書き出した分はクリアーします。 logF_kiki.boards.Clear(); } #endif // 枝狩りする。 this.EdagariEngine.ScoreSibori(kifu, this.Kokoro); // 1手に決める ShootingStarlightable bestMove = this.ErabuEngine.ChoiceBestMove(kifu, enableLog, isHonshogi); return(bestMove); }
/// <summary> /// C#のプログラムは、 /// この Main 関数から始まり、 Main 関数を抜けて終わります。 /// </summary> /// <param name="args"></param> static void Main(string[] args) { var engineConf = new EngineConf(); EntitiesLayer.Implement(engineConf); // var playing = new Playing(); // 思考エンジンの、記憶を読み取ります。 playing.shogisasi = new ShogisasiImpl(playing); playing.shogisasi.Kokoro.ReadTenonagare(); try { // // 図. // // プログラムの開始: ここの先頭行から始まります。 // プログラムの実行: この中で、ずっと無限ループし続けています。 // プログラムの終了: この中の最終行を終えたとき、 // または途中で Environment.Exit(0); が呼ばれたときに終わります。 // また、コンソールウィンドウの[×]ボタンを押して強制終了されたときも ぶつ切り で突然終わります。 //------+----------------------------------------------------------------------------------------------------------------- // 準備 | //------+----------------------------------------------------------------------------------------------------------------- // データの読取「道」 Michi187Array.Load(engineConf.GetResourceFullPath("Michi187")); // データの読取「配役」 Util_Haiyaku184Array.Load(engineConf.GetResourceFullPath("Haiyaku185"), Encoding.UTF8); // データの読取「強制転成表」 ※駒配役を生成した後で。 ForcePromotionArray.Load(engineConf.GetResourceFullPath("InputForcePromotion"), Encoding.UTF8); File.WriteAllText(engineConf.GetResourceFullPath("OutputForcePromotion"), ForcePromotionArray.LogHtml()); // データの読取「配役転換表」 Data_HaiyakuTransition.Load(engineConf.GetResourceFullPath("InputSyuruiToHaiyaku"), Encoding.UTF8); File.WriteAllText(engineConf.GetResourceFullPath("OutputSyuruiToHaiyaku"), Data_HaiyakuTransition.LogHtml()); //-------------------+---------------------------------------------------------------------------------------------------- // ログファイル削除 | //-------------------+---------------------------------------------------------------------------------------------------- // // 図. // // フォルダー // ├─ Engine.KifuWarabe.exe // └─ log.txt ←これを削除 // Logger.RemoveAllLogFile(); { //-------------+---------------------------------------------------------------------------------------------------------- // ログ書込み | <この将棋エンジン> 製品名、バージョン番号 //-------------+---------------------------------------------------------------------------------------------------------- // // 図. // // log.txt // ┌──────────────────────────────────────── // │2014/08/02 1:04:59> v(^▽^)v イェーイ☆ ... fugafuga 1.00.0 // │ // │ // // // 製品名とバージョン番号は、次のファイルに書かれているものを使っています。 // 場所: [ソリューション エクスプローラー]-[ソリューション名]-[プロジェクト名]-[Properties]-[AssemblyInfo.cs] の中の、[AssemblyProduct]と[AssemblyVersion] を参照。 // // バージョン番号を「1.00.0」形式(メジャー番号.マイナー番号.ビルド番号)で書くのは作者の趣味です。 // string versionStr; { // バージョン番号 Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; versionStr = String.Format("{0}.{1}.{2}", version.Major, version.Minor.ToString("00"), version.Build); //seihinName += " " + versionStr; } var engineName = engineConf.GetEngine("Name"); Logger.Trace($"v(^▽^)v イェーイ☆ ... {engineName} {versionStr}"); } //-----------+------------------------------------------------------------------------------------------------------------ // 通信開始 | //-----------+------------------------------------------------------------------------------------------------------------ // // 図. // // 無限ループ(全体) // │ // ├─無限ループ(1) // │ 将棋エンジンであることが認知されるまで、目で訴え続けます(^▽^) // │ 認知されると、無限ループ(2)に進みます。 // │ // └─無限ループ(2) // 対局中、ずっとです。 // 対局が終わると、無限ループ(1)に戻ります。 // // 無限ループの中に、2つの無限ループが入っています。 // // ループ(全体) while (true) { #if DEBUG_STOPPABLE MessageBox.Show("きふわらべのMainの無限ループでブレイク☆!", "デバッグ"); System.Diagnostics.Debugger.Break(); #endif // ループ(1つ目) while (true) { // 将棋サーバーから何かメッセージが届いていないか、見てみます。 string line = Util_Message.Download_BlockingIO(); Logger.WriteLineR(line); if ("usi" == line) { Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; var engineName = $"{engineConf.GetEngine("Name")} { version.Major}.{ version.Minor}.{ version.Build}"; var engineAuthor = engineConf.GetEngine("Author"); playing.UsiOk(engineName, engineAuthor); } else if (line.StartsWith("setoption")) { Regex regex = new Regex(@"setoption name ([^ ]+)(?: value (.*))?", RegexOptions.Singleline); Match m = regex.Match(line); if (m.Success) { string name = (string)m.Groups[1].Value; string value = ""; if (3 <= m.Groups.Count) { // 「value ★」も省略されずにありました。 //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> value = (string)m.Groups[2].Value; } playing.SetOption(name, value); } } else if ("isready" == line) { playing.ReadyOk(); } else if ("usinewgame" == line) { playing.UsiNewGame(); // 無限ループ(1つ目)を抜けます。無限ループ(2つ目)に進みます。 break; } else if ("quit" == line) { playing.Quit(); // このプログラムを終了します。 goto end_usi; } else { //------------------------------------------------------------ // ○△□×!? //------------------------------------------------------------ // // /(^×^)\ // // 通信が届いていますが、このプログラムでは 聞かなかったことにします。 // USIプロトコルの独習を進め、対応/未対応を選んでください。 } } // ループ(2つ目) playing.AjimiEngine = new AjimiEngine(playing); // // 図. // // この将棋エンジンが後手とします。 // // ┌──┬─────────────┬──────┬──────┬────────────────────────────────────┐ // │順番│ │計算 │tesumiCount │解説 │ // ┝━━┿━━━━━━━━━━━━━┿━━━━━━┿━━━━━━┿━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┥ // │ 1│初回 │ │ │相手が先手、この将棋エンジンが後手とします。 │ // │ │ │ │0 │もし、この将棋エンジンが先手なら、初回は tesumiCount = -1 とします。 │ // ├──┼─────────────┼──────┼──────┼────────────────────────────────────┤ // │ 2│position │+-0 │ │ │ // │ │ (相手が指しても、 │ │ │ │ // │ │ 指していないときでも │ │ │ │ // │ │ 送られてきます) │ │0 │ │ // ├──┼─────────────┼──────┼──────┼────────────────────────────────────┤ // │ 3│go │+2 │ │+2 します │ // │ │ (相手が指した) │ │2 │ ※「go」は、「go ponder」「go mate」「go infinite」とは区別します。 │ // ├──┼─────────────┼──────┼──────┼────────────────────────────────────┤ // │ 4│go ponder │+-0 │ │ │ // │ │ (相手はまだ指してない)│ │2 │ │ // ├──┼─────────────┼──────┼──────┼────────────────────────────────────┤ // │ 5│自分が指した │+-0 │ │相手が指してから +2 すると決めたので、 │ // │ │ │ │2 │自分が指したときにはカウントを変えません。 │ // └──┴─────────────┴──────┴──────┴────────────────────────────────────┘ // //PerformanceMetrics performanceMetrics = new PerformanceMetrics();//使ってない? while (true) { // 将棋サーバーから何かメッセージが届いていないか、見てみます。 string line = Util_Message.Download_BlockingIO(); Logger.WriteLineR(line); if (line.StartsWith("position")) { // 手番になったときに、“まず”、将棋所から送られてくる文字が position です。 // このメッセージを読むと、駒の配置が分かります。 // // “が”、まだ指してはいけません。 Logger.Trace("(^△^)positionきたコレ!"); // 入力行を解析します。 KifuParserA_Result result = new KifuParserA_ResultImpl(); var roomViewModel = new DefaultRoomViewModel(playing.Game.Kifu); var genjo = new KifuParserA_GenjoImpl(line); var parser = new KifuParserA_Impl(); Logger.Trace($@"┏━━━━━━━━━━┓ わたしは {parser.State.GetType().Name} の Execute_All だぜ☆"); KifuParserA_State nextState = parser.State; while (!genjo.ToBreak) { genjo.InputLine = parser.State.Execute( ref result, roomViewModel, out nextState, parser, genjo); parser.State = nextState; } KifuNode kifuNode = (KifuNode)result.Out_newNode_OrNull; int tesumi_yomiGenTeban_forLog = 0;//ログ用。読み進めている現在の手目済 Logger.Trace( Util_Sky.Json_1Sky(playing.Game.Kifu.CurNode.Value.ToKyokumenConst, "現局面になっているのかなんだぜ☆? line=[" + line + "] 棋譜=" + KirokuGakari.ToJapaneseKifuText(playing.Game.Kifu), "PgCS", tesumi_yomiGenTeban_forLog//読み進めている現在の手目 )); // // 局面画像ログ // if (kifuNode != null) // (2020-12-20 sun) なんでヌルになるのか分からないが、避けるぜ☆(^~^) { //SFEN文字列と、出力ファイル名を指定することで、局面の画像ログを出力します。 var ky = kifuNode.ToRO_Kyokumen1(); var fullname = SpecifyFiles.LatestPositionLogPng.Name; var env = ShogisasiImpl.ReportEnvironment; KyokumenPngWriterImpl.Write1(engineConf, ky, fullname, env); } //------------------------------------------------------------ // じっとがまん //------------------------------------------------------------ // // 応答は無用です。 // 多分、将棋所もまだ準備ができていないのではないでしょうか(?) // playing.Position(); } else if (line.StartsWith("go ponder")) { playing.GoPonder(); } // 「go ponder」「go mate」「go infinite」とは区別します。 else if (line.StartsWith("go")) { //------------------------------------------------------------ // あなたの手番です //------------------------------------------------------------ // // 図. // // log.txt // ┌──────────────────────────────────────── // ~ // │2014/08/02 2:36:19> go btime 599000 wtime 600000 byoyomi 60000 // │ // // もう指していいときに、将棋所から送られてくる文字が go です。 // // n手目を 2 増やします。 // 相手の手番と、自分の手番の 2つが増えた、という数え方です。 playing.Game.TesumiCount += 2; //------------------------------------------------------------ // 先手 3:00 後手 0:00 記録係「50秒ぉ~」 //------------------------------------------------------------ // // 上図のメッセージのままだと使いにくいので、 // あとで使いやすいように Key と Value の表に分けて持ち直します。 // // 図. // // goDictionary // ┌──────┬──────┐ // │Key │Value │ // ┝━━━━━━┿━━━━━━┥ // │btime │599000 │ // ├──────┼──────┤ // │wtime │600000 │ // ├──────┼──────┤ // │byoyomi │60000 │ // └──────┴──────┘ // 単位はミリ秒ですので、599000 は 59.9秒 です。 // Regex regex = new Regex(@"go btime (\d+) wtime (\d+) byoyomi (\d+)", RegexOptions.Singleline); Match m = regex.Match(line); if (m.Success) { playing.Go((string)m.Groups[1].Value, (string)m.Groups[2].Value, (string)m.Groups[3].Value, "", ""); } else { // (2020-12-16 wed) フィッシャー・クロック・ルールに対応☆(^~^) regex = new Regex(@"go btime (\d+) wtime (\d+) binc (\d+) winc (\d+)", RegexOptions.Singleline); m = regex.Match(line); playing.Go((string)m.Groups[1].Value, (string)m.Groups[2].Value, "", (string)m.Groups[3].Value, (string)m.Groups[4].Value); } //System.C onsole.WriteLine(); //throw new Exception("デバッグだぜ☆! エラーはキャッチできたかな~☆?(^▽^)"); } else if (line.StartsWith("stop")) { playing.Stop(); } else if (line.StartsWith("gameover")) { Regex regex = new Regex(@"gameover (.)", RegexOptions.Singleline); Match m = regex.Match(line); if (m.Success) { playing.GameOver((string)m.Groups[1].Value); } // 無限ループ(2つ目)を抜けます。無限ループ(1つ目)に戻ります。 break; } // 独自コマンド「ログ出せ」 else if ("logdase" == line) { StringBuilder sb = new StringBuilder(); sb.Append("ログだせ~(^▽^)"); playing.Game.Kifu.ForeachZenpuku( playing.Game.Kifu.GetRoot(), (int tesumi, KyokumenWrapper sky, Node <ShootingStarlightable, KyokumenWrapper> node, ref bool toBreak) => { //sb.AppendLine("(^-^)"); if (null != node) { if (null != node.Key) { string sfenText = Util_Sky.ToSfenMoveText(node.Key); sb.Append(sfenText); sb.AppendLine(); } } }); File.WriteAllText("../../Logs/_log_ログ出せ命令.txt", sb.ToString()); } else { //------------------------------------------------------------ // ○△□×!? //------------------------------------------------------------ // // /(^×^)\ // // 通信が届いていますが、このプログラムでは 聞かなかったことにします。 // USIプロトコルの独習を進め、対応/未対応を選んでください。 } } //-------------------+---------------------------------------------------------------------------------------------------- // スナップショット | //-------------------+---------------------------------------------------------------------------------------------------- // 対局後のタイミングで、データの中身を確認しておきます。 // Key と Value の表の形をしています。(順不同) // // 図. // ※内容はサンプルです。実際と異なる場合があります。 // // setoptionDictionary // ┌──────┬──────┐ // │Key │Value │ // ┝━━━━━━┿━━━━━━┥ // │USI_Ponder │true │ // ├──────┼──────┤ // │USI_Hash │256 │ // └──────┴──────┘ // // goDictionary // ┌──────┬──────┐ // │Key │Value │ // ┝━━━━━━┿━━━━━━┥ // │btime │599000 │ // ├──────┼──────┤ // │wtime │600000 │ // ├──────┼──────┤ // │byoyomi │60000 │ // └──────┴──────┘ // // goMateDictionary // ┌──────┬──────┐ // │Key │Value │ // ┝━━━━━━┿━━━━━━┥ // │mate │599000 │ // └──────┴──────┘ // // gameoverDictionary // ┌──────┬──────┐ // │Key │Value │ // ┝━━━━━━┿━━━━━━┥ // │gameover │lose │ // └──────┴──────┘ // Logger.Trace("KifuParserA_Impl.LOGGING_BY_ENGINE, ┏━確認━━━━setoptionDictionary ━┓"); foreach (KeyValuePair <string, string> pair in playing.SetoptionDictionary) { Logger.Trace(pair.Key + "=" + pair.Value); } Logger.Trace("┗━━━━━━━━━━━━━━━━━━┛"); //Dictionary<string, string> goMateProperties = new Dictionary<string, string>(); //goMateProperties["mate"] = ""; //LarabeLoggerList_Warabe.ENGINE.WriteLine_AddMemo("┏━確認━━━━goMateDictionary━━━┓"); //foreach (KeyValuePair<string, string> pair in this.goMateProperties) //{ // LarabeLoggerList_Warabe.ENGINE.WriteLine_AddMemo(pair.Key + "=" + pair.Value); //} Logger.Trace("┗━━━━━━━━━━━━━━━━━━┛"); } } catch (Exception ex) { // エラーが起こりました。 //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> // どうにもできないので ログだけ取って無視します。 Logger.Fatal($"(^ー^)「大外枠でキャッチ」{ex}"); Playing.Send("bestmove resign"); } end_usi: // 終了時に、妄想履歴のログを残します。 playing.shogisasi.Kokoro.WriteTenonagare(playing.shogisasi); }