/// <summary> /// ************************************************************************************************************************ /// 1手進む /// ************************************************************************************************************************ /// /// <棋譜読込用><マウス入力非対応> /// /// 「棋譜並べモード」と「vsコンピューター対局」でも、これを使いますが、 /// 「棋譜並べモード」では送られてくる SFEN が「position startpos moves 8c8d」とフルであるのに対し、 /// 「vsコンピューター対局」では、送られてくる SFEN が「8c8d」だけです。 /// /// それにより、処理の流れが異なります。 /// /// </summary> public static bool ReadLine_TuginoItteSusumu_Srv( ref string inputLine, Model_Taikyoku model_Taikyoku,//SetCurNodeがある。[コマ送り][再生]などで使用。 Model_Manual model_Manual, out bool toBreak, string hint , [CallerMemberName] string memberName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0 ) { //IErrorController logTag = OwataMinister.SERVER_KIFU_YOMITORI; bool successful = false; KifuParserA_Impl kifuParserA_Impl = new KifuParserA_Impl(); KifuParserA_Result result = new KifuParserA_ResultImpl(); KifuParserA_Genjo genjo = new KifuParserA_GenjoImpl(inputLine); try { if (kifuParserA_Impl.State is KifuParserA_StateA0_Document) { // 最初はここ #if DEBUG Logger.Trace("(^o^)... ..."); Logger.Trace($"サイショハココ☆ : {memberName}.{sourceFilePath}.{sourceLineNumber}"); #endif inputLine = kifuParserA_Impl.Execute_Step( ref result, model_Taikyoku, genjo ); Debug.Assert(result.Out_newNode_OrNull == null, "ここでノードに変化があるのはおかしい。"); if (genjo.IsBreak()) { goto gt_EndMethod; } // (1)position コマンドを処理しました。→startpos // (2)日本式棋譜で、何もしませんでした。→moves } if (kifuParserA_Impl.State is KifuParserA_StateA1_SfenPosition) { //------------------------------------------------------------ // このブロックでは「position ~ moves 」まで一気に(*1)を処理します。 //------------------------------------------------------------ // // *1…初期配置を作るということです。 // { #if DEBUG string message = $"(^o^)ツギハ ヒラテ マタハ シテイキョクメン ヲ ショリシタイ☆ inputLine=[{inputLine}]"; Logger.Trace(message); #endif inputLine = kifuParserA_Impl.Execute_Step( ref result, model_Taikyoku, genjo ); Debug.Assert(result.Out_newNode_OrNull == null, "ここでノードに変化があるのはおかしい。"); if (genjo.IsBreak()) { goto gt_EndMethod; } } { #if DEBUG Logger.Trace("(^o^)ツギハ ムーブス ヲ ショリシタイ☆"); #endif inputLine = kifuParserA_Impl.Execute_Step( ref result, model_Taikyoku, genjo ); Debug.Assert(result.Out_newNode_OrNull == null, "ここでノードに変化があるのはおかしい。"); if (genjo.IsBreak()) { goto gt_EndMethod; } // moves を処理しました。 // ここまでで、「position ~ moves 」といった記述が入力されていたとすれば、入力欄から削除済みです。 } // →moves } // // 対COMP戦で関係があるのはここです。 // if (kifuParserA_Impl.State is KifuParserA_StateA2_SfenMoves) { #if DEBUG Logger.Trace("ツギハ イッテ ショリシタイ☆"); #endif inputLine = kifuParserA_Impl.Execute_Step( ref result, model_Taikyoku, genjo ); if (null != result.Out_newNode_OrNull) { string jsaFugoStr; Util_Functions_Server.SetCurNode_Srv(model_Taikyoku, model_Manual, result.Out_newNode_OrNull, out jsaFugoStr); } if (genjo.IsBreak()) { goto gt_EndMethod; } // 1手を処理した☆? } if (null != genjo.StartposImporter_OrNull) { // 初期配置が平手でないとき。 // ************************************************************************************************************************ // SFENの初期配置の書き方(*1)を元に、駒を並べます。 // ************************************************************************************************************************ // // *1…「position startpos moves 7g7f 3c3d 2g2f」といった書き方。 // ParsedKyokumen parsedKyokumen = Conv_StartposImporter.ToParsedKyokumen( model_Manual, genjo.StartposImporter_OrNull,//指定されているはず。 genjo ); //------------------------------ // 駒の配置 //------------------------------ string jsaFugoStr; Util_Functions_Server.SetCurNode_Srv(model_Taikyoku, model_Manual, parsedKyokumen.KifuNode, out jsaFugoStr);// GUIに通知するだけ。 ////------------------------------ //// 駒を、駒袋から駒台に移動させます。 ////------------------------------ //model_Operating.Manual.SetGuiSky( // SkyConst.NewInstance( // parsedKyokumen.buffer_Sky, // -1//そのまま // ) //); } successful = true; } catch (Exception ex) { Util_Message.Show($"{ex}"); toBreak = true; successful = false; } gt_EndMethod: toBreak = genjo.IsBreak(); return(successful); }
/// <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(); //-------------------+---------------------------------------------------------------------------------------------------- // ログファイル削除 | //-------------------+---------------------------------------------------------------------------------------------------- { // // 図. // // フォルダー // ├─ Engine.KifuWarabe.exe // └─ log.txt ←これを削除 // Logger.RemoveAllLogFiles(); } //------------------------------------------------------------------------------------------------------------------------ // 思考エンジンの、記憶を読み取ります。 //------------------------------------------------------------------------------------------------------------------------ Util_FvLoad.OpenFv(engineConf, playing.FeatureVector, engineConf.GetResourceFullPath("Fv00Komawari")); //------------------------------------------------------------------------------------------------------------------------ // ファイル読込み //------------------------------------------------------------------------------------------------------------------------ { // データの読取「道」 if (Michi187Array.Load(engineConf.GetResourceFullPath("Michi187"))) { } // データの読取「配役」 Util_Array_KomahaiyakuEx184.Load(engineConf.GetResourceFullPath("Haiyaku185"), Encoding.UTF8); // データの読取「強制転成表」 ※駒配役を生成した後で。 Array_ForcePromotion.Load(engineConf.GetResourceFullPath("InputForcePromotion"), Encoding.UTF8); #if DEBUG { File.WriteAllText(engineConf.GetResourceFullPath("OutputForcePromotion"), Array_ForcePromotion.LogHtml()); } #endif // データの読取「配役転換表」 Data_KomahaiyakuTransition.Load(engineConf.GetResourceFullPath("InputSyuruiToHaiyaku"), Encoding.UTF8); #if DEBUG { File.WriteAllText(engineConf.GetResourceFullPath("OutputSyuruiToHaiyaku"), Data_KomahaiyakuTransition.Format_LogHtml()); } #endif } //-------------+---------------------------------------------------------------------------------------------------------- // ログ書込み | <この将棋エンジン> 製品名、バージョン番号 //-------------+---------------------------------------------------------------------------------------------------------- // // 図. // // 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}"; #if DEBUG var engineName = engineConf.GetEngine("Name"); Logger.Trace($"v(^▽^)v イェーイ☆ ... {engineName} {versionStr}"); #endif } bool isTimeoutShutdown = false; try { // // 図. // // プログラムの開始: ここの先頭行から始まります。 // プログラムの実行: この中で、ずっと無限ループし続けています。 // プログラムの終了: この中の最終行を終えたとき、 // または途中で Environment.Exit(0); が呼ばれたときに終わります。 // また、コンソールウィンドウの[×]ボタンを押して強制終了されたときも ぶつ切り で突然終わります。 // ループ(全体) // // 図. // // 無限ループ(全体) // │ // ├─無限ループ(1) // │ 将棋エンジンであることが認知されるまで、目で訴え続けます(^▽^) // │ 認知されると、無限ループ(2)に進みます。 // │ // └─無限ループ(2) // 対局中、ずっとです。 // 対局が終わると、無限ループ(1)に戻ります。 // // 無限ループの中に、2つの無限ループが入っています。 // while (true) { #if DEBUG_STOPPABLE MessageBox.Show("きふわらべのMainの無限ループでブレイク☆!", "デバッグ"); System.Diagnostics.Debugger.Break(); #endif isTimeoutShutdown = false; // // サーバーに noop を送ってもよいかどうかは setoption コマンドがくるまで分からないので、 // 作ってしまっておきます。 // 1回も役に立たずに Loop2 に行くようなら、正常です。 #if NOOPABLE NoopTimerImpl noopTimer = new NoopTimerImpl(); noopTimer._01_BeforeLoop(); #endif // USIループ(1つ目) while (true) { // 将棋サーバーから何かメッセージが届いていないか、見てみます。 string line = Util_Message.Download_Nonstop(); // (2020-12-13 sun) ノン・ブロッキングなら このコードが意味あったんだが☆(^~^) if (null == line)//次の行が無ければヌル。 { // メッセージは届いていませんでした。 //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> #if NOOPABLE bool isTimeoutShutdown_temp; noopTimer._03_AtEmptyMessage(this.Owner, out isTimeoutShutdown_temp); if (isTimeoutShutdown_temp) { //MessageBox.Show("ループ1でタイムアウトだぜ☆!"); out_isTimeoutShutdown = isTimeoutShutdown_temp; result_UsiLoop1 = PhaseResult_UsiLoop1.TimeoutShutdown; goto end_loop1; } #endif goto gt_NextTime1; } // 通信ログは必ず取ります。 Logger.WriteLineC(line); #if NOOPABLE noopTimer._04_AtResponsed(this.Owner, line); #endif if ("usi" == line) { var engineName = engineConf.GetEngine("Name"); Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; var engineAuthor = engineConf.GetEngine("Author"); playing.UsiOk($"{engineName} {version.Major}.{version.Minor}.{version.Build}", engineAuthor); } else if (line.StartsWith("setoption")) { Match m = regexOfSetoption.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つ目)に進みます。 goto end_loop1; } else if ("quit" == line) { playing.Quit(); // このプログラムを終了します。 goto gt_EndMethod;//全体ループを抜けます。 } else { //------------------------------------------------------------ // ○△□×!? //------------------------------------------------------------ // // /(^×^)\ // // 通信が届いていますが、このプログラムでは 聞かなかったことにします。 // USIプロトコルの独習を進め、対応/未対応を選んでください。 // // ログだけ取って、スルーします。 } gt_NextTime1: ; } end_loop1: if (isTimeoutShutdown) { //MessageBox.Show("ループ1で矯正終了するんだぜ☆!"); goto gt_EndMethod; } // // USIループ(2つ目) // // // 図. // // この将棋エンジンが後手とします。 // // ┌──┬─────────────┬──────┬──────┬────────────────────────────────────┐ // │順番│ │計算 │temezumiCount │解説 │ // ┝━━┿━━━━━━━━━━━━━┿━━━━━━┿━━━━━━┿━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┥ // │ 1│初回 │ │ │相手が先手、この将棋エンジンが後手とします。 │ // │ │ │ │0 │もし、この将棋エンジンが先手なら、初回は temezumiCount = -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 │自分が指したときにはカウントを変えません。 │ // └──┴─────────────┴──────┴──────┴────────────────────────────────────┘ // // 棋譜 { Debug.Assert(!Conv_MasuHandle.OnKomabukuro( Conv_SyElement.ToMasuNumber(((RO_Star)playing.Game.Kifu.CurNode.Value.KyokumenConst.StarlightIndexOf((Finger)0).Now).Masu) ), "駒が駒袋にあった。"); } // go ponderの属性一覧 { playing.Game.GoPonderNow = false; // go ponderを将棋所に伝えたなら真 } isTimeoutShutdown = false; //PerformanceMetrics performanceMetrics = new PerformanceMetrics();//使ってない? #if NOOPABLE // サーバーに noop を送ってもよい場合だけ有効にします。 NoopTimerImpl noopTimer = null; if (this.owner.Option_enable_serverNoopable) { noopTimer = new NoopTimerImpl(); noopTimer._01_BeforeLoop(); } #endif while (true) { PhaseResult_UsiLoop2 result_UsiLoop2 = PhaseResult_UsiLoop2.None; //ノンストップ版 //string line = TimeoutReader.ReadLine(1000);//指定ミリ秒だけブロック。 (2020-12-13 sun) そのあと抜ける。頼んで作ってもらった関数、入力を取りこぼす不具合がある☆(^~^)? // ブロッキングIO。 string line = Console.In.ReadLine(); // 通信ログは必ず取ります。 Logger.WriteLineC(line); #if NOOPABLE if (this.owner.Option_enable_serverNoopable) { noopTimer._03_AtResponsed(this.owner, line); } #endif if (line.StartsWith("position")) { #if DEBUG Logger.Trace("(^△^)positionきたコレ!"); #endif // 入力行を解析します。 KifuParserA_Result result = new KifuParserA_ResultImpl(); KifuParserA_Impl kifuParserA = new KifuParserA_Impl(); Model_Taikyoku model_Taikyoku = new Model_TaikyokuImpl(playing.Game.Kifu);//FIXME: この棋譜を委譲メソッドで修正するはず。 ShogiGui_Warabeは? KifuParserA_Genjo genjo = new KifuParserA_GenjoImpl(line); kifuParserA.Execute_All( ref result, model_Taikyoku, genjo ); if (null != genjo.StartposImporter_OrNull) { // SFENの解析結果を渡すので、 // その解析結果をどう使うかは、委譲します。 Util_InClient.OnChangeSky_Im_Client( model_Taikyoku, genjo ); } #if DEBUG Playing.Log2_Png_Tyokkin(line, (KifuNode)result.Out_newNode_OrNull); #endif //------------------------------------------------------------ // じっとがまん //------------------------------------------------------------ // // 応答は無用です。 // 多分、将棋所もまだ準備ができていないのではないでしょうか(?) // playing.Position(); } else if (line.StartsWith("go ponder")) { playing.GoPonder(); } // 「go ponder」「go mate」「go infinite」とは区別します。 else if (line.StartsWith("go")) { Match m = regexOfGo.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) フィッシャー・クロック・ルールに対応☆(^~^) m = regexOfGoFisherClock.Match(line); playing.Go((string)m.Groups[1].Value, (string)m.Groups[2].Value, "", (string)m.Groups[3].Value, (string)m.Groups[4].Value); } } else if (line.StartsWith("stop")) { playing.Stop(); } else if (line.StartsWith("gameover")) { Match m = regexOfGameover.Match(line); if (m.Success) { playing.GameOver((string)m.Groups[1].Value); } // 無限ループ(2つ目)を抜けます。無限ループ(1つ目)に戻ります。 result_UsiLoop2 = PhaseResult_UsiLoop2.Break; } else if ("logdase" == line) { StringBuilder sb = new StringBuilder(); sb.Append("ログだせ~(^▽^)"); playing.Game.Kifu.ForeachZenpuku( playing.Game.Kifu.GetRoot(), (int temezumi, KyokumenWrapper sky, Node <IMove, KyokumenWrapper> node, ref bool toBreak) => { //sb.AppendLine("(^-^)"); if (null != node) { if (null != node.Key) { string sfenText = ConvMoveStrSfen.ToMoveStrSfen(node.Key); sb.Append(sfenText); sb.AppendLine(); } } }); File.WriteAllText(engineConf.GetResourceFullPath("LogDaseMeirei"), sb.ToString()); } else { //------------------------------------------------------------ // ○△□×!? //------------------------------------------------------------ // // /(^×^)\ // // 通信が届いていますが、このプログラムでは 聞かなかったことにします。 // USIプロトコルの独習を進め、対応/未対応を選んでください。 // // ログだけ取って、スルーします。 } switch (result_UsiLoop2) { case PhaseResult_UsiLoop2.Break: goto end_loop2; default: break; } #pragma warning disable CS0164 // このラベルは参照されていません gt_NextLine_loop2: #pragma warning restore CS0164 // このラベルは参照されていません ; } end_loop2: ; //-------------------+---------------------------------------------------------------------------------------------------- // スナップショット | //-------------------+---------------------------------------------------------------------------------------------------- // 対局後のタイミングで、データの中身を確認しておきます。 // 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 │ // └──────┴──────┘ // #if DEBUG 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.WriteLineAddMemo("┗━━━━━━━━━━━━━━━━━━┛"); //LarabeLoggerList_Warabe.ENGINE.WriteLineAddMemo("┏━確認━━━━goMateDictionary━━━┓"); //foreach (KeyValuePair<string, string> pair in this.goMateProperties) //{ // LarabeLoggerList_Warabe.ENGINE.WriteLineAddMemo($"{pair.Key}={pair.Value}"); //} #endif if (isTimeoutShutdown) { //MessageBox.Show("ループ2で矯正終了するんだぜ☆!"); goto gt_EndMethod;//全体ループを抜けます。 } } } catch (Exception ex) { // エラーが起こりました。 //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> // どうにもできないので ログだけ取って無視します。 Logger.Fatal($"(^ー^)「大外枠でキャッチ」{ex}"); Playing.Send("bestmove resign"); } gt_EndMethod: ; }
/// <summary> /// 1手進む /// /// <棋譜読込用><マウス入力非対応> /// /// 「棋譜並べモード」と「vsコンピューター対局」でも、これを使いますが、 /// 「棋譜並べモード」では送られてくる SFEN が「position startpos moves 8c8d」とフルであるのに対し、 /// 「vsコンピューター対局」では、送られてくる SFEN が「8c8d」だけです。 /// /// それにより、処理の流れが異なります。 /// /// </summary> public static bool ReadLine_TuginoItteSusumu_Srv( ref string inputLine, IRoomViewModel roomViewModel, out bool toBreak, string hint , [CallerMemberName] string memberName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0 ) { bool successful = false; KifuParserA_Impl kifuParserA_Impl = new KifuParserA_Impl(); KifuParserA_Result result = new KifuParserA_ResultImpl(); KifuParserA_Genjo genjo = new KifuParserA_GenjoImpl(inputLine); try { kifuParserA_Impl.Delegate_OnChangeSky_Im_Srv = Util_InServer.OnChangeSky_Im_Srv; if (kifuParserA_Impl.State is KifuParserA_StateA0_Document) { // 最初はここ Logger.Trace("... ..."); Logger.Trace("サイショハココ☆ : " + memberName + "." + sourceFilePath + "." + sourceLineNumber); inputLine = kifuParserA_Impl.Execute_Step( ref result, roomViewModel, genjo ); Debug.Assert(result.Out_newNode_OrNull == null, "ここでノードに変化があるのはおかしい。"); if (genjo.ToBreak) { goto gt_EndMethod; } // (1)position コマンドを処理しました。→startpos // (2)日本式棋譜で、何もしませんでした。→moves } if (kifuParserA_Impl.State is KifuParserA_StateA1_SfenPosition) { //------------------------------------------------------------ // このブロックでは「position ~ moves 」まで一気に(*1)を処理します。 //------------------------------------------------------------ // // *1…初期配置を作るということです。 // { string message = "ツギハ ヒラテ マタハ シテイキョクメン ヲ ショリシタイ☆ inputLine=[" + inputLine + "]"; Logger.Trace(message); inputLine = kifuParserA_Impl.Execute_Step( ref result, roomViewModel, genjo ); Debug.Assert(result.Out_newNode_OrNull == null, "ここでノードに変化があるのはおかしい。"); if (genjo.ToBreak) { goto gt_EndMethod; } } { Logger.Trace("ツギハ ムーブス ヲ ショリシタイ☆"); inputLine = kifuParserA_Impl.Execute_Step( ref result, roomViewModel, genjo ); Debug.Assert(result.Out_newNode_OrNull == null, "ここでノードに変化があるのはおかしい。"); if (genjo.ToBreak) { goto gt_EndMethod; } // moves を処理しました。 // ここまでで、「position ~ moves 」といった記述が入力されていたとすれば、入力欄から削除済みです。 } // →moves } // // 対COMP戦で関係があるのはここです。 // if (kifuParserA_Impl.State is KifuParserA_StateA2_SfenMoves) { Logger.Trace("ツギハ イッテ ショリシタイ☆"); inputLine = kifuParserA_Impl.Execute_Step( ref result, roomViewModel, genjo ); if (null != result.Out_newNode_OrNull) { Util_InServer.SetCurNode_Srv(roomViewModel, result.Out_newNode_OrNull); } if (genjo.ToBreak) { goto gt_EndMethod; } // 1手を処理した☆? } successful = true; } catch (Exception ex) { Util_Message.Show(ex.GetType().Name + ":" + ex.Message); toBreak = true; successful = false; } gt_EndMethod: toBreak = genjo.ToBreak; return(successful); }
/// <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); }