/// <summary> /// 局面PNG画像書き出し。 /// </summary> public void WritePng() { var profilePath = System.Configuration.ConfigurationManager.AppSettings["Profile"]; var toml = Toml.ReadFile(Path.Combine(profilePath, "Engine.toml")); int srcMasu_orMinusOne = -1; int dstMasu_orMinusOne = -1; if (null != this.Kifu.CurNode.Key) { srcMasu_orMinusOne = Conv_SyElement.ToMasuNumber(((RO_Star)this.Kifu.CurNode.Key.LongTimeAgo).Masu); dstMasu_orMinusOne = Conv_SyElement.ToMasuNumber(((RO_Star)this.Kifu.CurNode.Key.Now).Masu); } KyokumenPngArgs_FoodOrDropKoma foodKoma; if (null != this.Kifu.CurNode.Key.FoodKomaSyurui) { switch (Util_Komasyurui14.NarazuCaseHandle((PieceType)this.Kifu.CurNode.Key.FoodKomaSyurui)) { case PieceType.None: foodKoma = KyokumenPngArgs_FoodOrDropKoma.NONE; break; case PieceType.P: foodKoma = KyokumenPngArgs_FoodOrDropKoma.FU__; break; case PieceType.L: foodKoma = KyokumenPngArgs_FoodOrDropKoma.KYO_; break; case PieceType.N: foodKoma = KyokumenPngArgs_FoodOrDropKoma.KEI_; break; case PieceType.S: foodKoma = KyokumenPngArgs_FoodOrDropKoma.GIN_; break; case PieceType.G: foodKoma = KyokumenPngArgs_FoodOrDropKoma.KIN_; break; case PieceType.R: foodKoma = KyokumenPngArgs_FoodOrDropKoma.HI__; break; case PieceType.B: foodKoma = KyokumenPngArgs_FoodOrDropKoma.KAKU; break; default: foodKoma = KyokumenPngArgs_FoodOrDropKoma.UNKNOWN; break; } } else { foodKoma = KyokumenPngArgs_FoodOrDropKoma.NONE; } // 学習フォーム Util_KyokumenPng_Writer.Write1( Conv_KifuNode.ToRO_Kyokumen1(((KifuNode)this.Kifu.CurNode)), srcMasu_orMinusOne, dstMasu_orMinusOne, foodKoma, ConvMoveStrSfen.ToMoveStrSfen(this.Kifu.CurNode.Key), "", toml.Get <TomlTable>("Resources").Get <string>("LearningPositionLogPngBasename"), LearningDataImpl.REPORT_ENVIRONMENT ); }
/// <summary> /// [一手指す]ボタン。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> public static void IttesasuByBtnClick( ref bool isRequestShowGohosyu, ref bool isRequestChangeKyokumenPng, LearningData learningData, Uc_Main ucMain) { #if DEBUG Stopwatch sw1 = new Stopwatch(); sw1.Start(); #endif if (ucMain is null) { throw new ArgumentNullException(nameof(ucMain)); } // if (logTag is null) throw new ArgumentNullException(nameof(logTag)); // // リストの先頭の項目を取得したい。 // if (ucMain.LstMove.Items.Count < 1) { goto gt_EndMethod; } // リストボックスの先頭から指し手をSFEN形式で1つ取得。 HonpuMoveListItemImpl item = (HonpuMoveListItemImpl)ucMain.LstMove.Items[0]; string sfen = item.Sfen; // (2020-12-18 fri)この機能むずかしいからいったん廃止☆(^~^) // logTag.OnAppendLog?.Invoke($"sfen={sfen}\n"); // // 現局面の合法手は、既に読んであるとします。(棋譜ツリーのNextNodesが既に設定されていること) // // // 合法手の一覧は既に作成されているものとします。 // 次の手に進みます。 // IMove nextMove; { if (learningData.Kifu.CurNode.HasChildNode(sfen)) { Node <IMove, KyokumenWrapper> nextNode = learningData.Kifu.CurNode.GetChildNode(sfen); nextMove = nextNode.Key;//次の棋譜ノードのキーが、指し手(きふわらべ式)になっています。 } else { nextMove = null; throw new Exception($@"指し手[{sfen}]はありませんでした。 {learningData.DumpToAllGohosyu(learningData.Kifu.CurNode.Value.KyokumenConst)}"); } } //---------------------------------------- // 一手指したい。 //---------------------------------------- //↓↓一手指し IttesasuResult ittesasuResult; Util_IttesasuRoutine.Before1( new IttesasuArgImpl( learningData.Kifu.CurNode.Value, ((KifuNode)learningData.Kifu.CurNode).Value.KyokumenConst.KaisiPside, nextMove, // FIXME: これがヌルのことがあるのだろうか? learningData.Kifu.CurNode.Value.KyokumenConst.Temezumi + 1 //1手進める ), out ittesasuResult, //this.Kifu,//診断用 "Util_LearningView#Ittesasu_ByBtnClick" ); Debug.Assert(ittesasuResult.Get_SyuryoNode_OrNull != null, "ittesasuResult.Get_SyuryoNode_OrNull がヌル☆?!"); Util_IttesasuRoutine.Before2( ref ittesasuResult ); // //次ノートを追加します。次ノードを、これからのカレントとします。 // //this.Kifu.AssertChildPside(this.Kifu.CurNode.Value.ToKyokumenConst.KaisiPside, ittesasuResult.Get_SyuryoNode_OrNull.Value.ToKyokumenConst.KaisiPside); Util_IttesasuRoutine.After3_ChangeCurrent( learningData.Kifu, ConvMoveStrSfen.ToMoveStrSfen(ittesasuResult.Get_SyuryoNode_OrNull.Key), ittesasuResult.Get_SyuryoNode_OrNull ); // これで、棋譜ツリーに、構造変更があったはず。 //↑↑一手指し //---------------------------------------- // カレント・ノードより古い、以前読んだ手を削除したい。 //---------------------------------------- Logger.Trace($"カレント・ノード={ConvMoveStrSfen.ToMoveStrSfen(learningData.Kifu.CurNode.Key)}"); int result_removedCount = UtilKifuTree282.IzennoHenkaCutter(learningData.Kifu); Logger.Trace($"削除した要素数={result_removedCount}"); ////---------------------------------------- //// 合法手一覧を作成したい。 ////---------------------------------------- learningData.Aa_Yomi(nextMove); // ノード情報の表示 Util_LearningView.Aa_ShowNode2(ucMain.LearningData, ucMain); // 合法手表示の更新を要求します。 isRequestShowGohosyu = true; // 局面PNG画像を更新を要求。 isRequestChangeKyokumenPng = true; // // リストの頭1個を除外します。 // ucMain.LstMove.Items.RemoveAt(0); #if DEBUG sw1.Stop(); Logger.Trace($"一手指すボタン合計 = {sw1.Elapsed}"); Logger.Trace("────────────────────────────────────────"); #endif gt_EndMethod: ; //---------------------------------------- // ボタン表示の回復 //---------------------------------------- if (0 < ucMain.LstMove.Items.Count) { ucMain.BtnUpdateKyokumenHyoka.Enabled = true;//[局面評価更新]ボタン連打防止解除。 } }
/// <summary> /// 指し手一覧を、リストボックスに表示します。 /// </summary> /// <param name="uc_Main"></param> public static void ShowMoveList( LearningData learningData, Uc_Main uc_Main ) { // // まず、リストを空っぽにします。 // uc_Main.LstMove.Items.Clear(); Playerside firstPside = Playerside.P1; KifuTree kifu1 = new KifuTreeImpl( new KifuNodeImpl( Util_Sky258A.RootMove, new KyokumenWrapper(SkyConst.NewInstance( Util_SkyWriter.New_Hirate(firstPside), 0 //初期局面は 0手済み。 )) //日本の符号読取時 ) ); //kifu1.AssertPside(kifu1.CurNode, "ShowMoveList",logTag); List <CsaKifuMove> moveList = learningData.CsaKifu.MoveList; foreach (CsaKifuMove csaMove in moveList) { // 開始局面 SkyConst kaisi_Sky = kifu1.CurNode.Value.KyokumenConst; // // csaMove を データ指し手 に変換するには? // IMove nextMove; { Playerside pside = UtilCsaMove.ToPside(csaMove); // 元位置 SyElement srcMasu = UtilCsaMove.ToSrcMasu(csaMove); Finger figSrcKoma; if (Masu_Honshogi.IsErrorBasho(srcMasu))// 駒台の "00" かも。 { //駒台の駒。 PieceType utuKomasyurui = Util_Komasyurui14.NarazuCaseHandle(UtilCsaMove.ToKomasyurui(csaMove));// 打つ駒の種類。 Okiba komadai; switch (pside) { case Playerside.P1: komadai = Okiba.Sente_Komadai; break; case Playerside.P2: komadai = Okiba.Gote_Komadai; break; default: komadai = Okiba.Empty; break; } figSrcKoma = Util_Sky_FingersQuery.InOkibaPsideKomasyuruiNow(kaisi_Sky, komadai, pside, utuKomasyurui).ToFirst(); } else { // 盤上の駒。 figSrcKoma = Util_Sky_FingerQuery.InMasuNow(kaisi_Sky, pside, srcMasu); } RO_Star srcKoma = Util_Starlightable.AsKoma(kaisi_Sky.StarlightIndexOf(figSrcKoma).Now); // 先位置 SyElement dstMasu = UtilCsaMove.ToDstMasu(csaMove); Finger figFoodKoma = Util_Sky_FingerQuery.InShogibanMasuNow(kaisi_Sky, pside, dstMasu); PieceType foodKomasyurui; if (figFoodKoma == Fingers.Error_1) { // 駒のない枡 foodKomasyurui = PieceType.None;//取った駒無し。 } else { // 駒のある枡 foodKomasyurui = Util_Starlightable.AsKoma(kaisi_Sky.StarlightIndexOf(figFoodKoma).Now).Komasyurui;//取った駒有り。 } IMoveSource dstKoma = new RO_Star( pside, dstMasu, UtilCsaMove.ToKomasyurui(csaMove) ); nextMove = new RO_Starbeam( srcKoma, // 移動元 dstKoma, // 移動先 foodKomasyurui ////取った駒 ); } { //---------------------------------------- // 一手指したい。 //---------------------------------------- // //↓↓一手指し IttesasuResult ittesasuResult; Util_IttesasuRoutine.Before1( new IttesasuArgImpl( kifu1.CurNode.Value, ((KifuNode)kifu1.CurNode).Value.KyokumenConst.KaisiPside, nextMove, kifu1.CurNode.Value.KyokumenConst.Temezumi + 1//1手進める ), out ittesasuResult, //kifu1,//診断用 "Utli_LearningViews#ShowMoveList" ); Debug.Assert(ittesasuResult.Get_SyuryoNode_OrNull != null, "ittesasuResult.Get_SyuryoNode_OrNull がヌル☆?!"); Util_IttesasuRoutine.Before2( ref ittesasuResult ); // //次ノートを追加します。次ノードを、これからのカレントとします。 // //kifu1.AssertChildPside(kifu1.CurNode.Value.ToKyokumenConst.KaisiPside, ittesasuResult.Get_SyuryoNode_OrNull.Value.ToKyokumenConst.KaisiPside); Util_IttesasuRoutine.After3_ChangeCurrent( kifu1, ConvMoveStrSfen.ToMoveStrSfen(ittesasuResult.Get_SyuryoNode_OrNull.Key),// nextMoveStr, ittesasuResult.Get_SyuryoNode_OrNull ); // これで、棋譜ツリーに、構造変更があったはず。 //↑↑一手指し } string sfen; if (kifu1.CurNode.IsRoot()) { sfen = UtilCsaMove.ToSfen(csaMove, null); } else { sfen = UtilCsaMove.ToSfen(csaMove, kifu1.CurNode.GetParentNode().Value.KyokumenConst); } HonpuMoveListItemImpl listItem = new HonpuMoveListItemImpl(csaMove, sfen); uc_Main.LstMove.Items.Add(listItem); } //---------------------------------------- // ソート //---------------------------------------- //List<MoveListItemImpl> list = new List<MoveListItemImpl>(); //list.Sort((MoveListItemImpl a, MoveListItemImpl b) => //{ // return a - b; //}); }
public void Go(string btime, string wtime, string byoyomi, string binc, string winc) { //------------------------------------------------------------ // あなたの手番です //------------------------------------------------------------ // // 図. // // log.txt // ┌──────────────────────────────────────── // ~ // │2014/08/02 2:36:19> go btime 599000 wtime 600000 byoyomi 60000 // │ // // もう指していいときに、将棋所から送られてくる文字が go です。 // //------------------------------------------------------------ // 先手 3:00 後手 0:00 記録係「50秒ぉ~」 //------------------------------------------------------------ // // 上図のメッセージのままだと使いにくいので、 // あとで使いやすいように Key と Value の表に分けて持ち直します。 // // 図. // // goDictionary // ┌──────┬──────┐ // │Key │Value │ // ┝━━━━━━┿━━━━━━┥ // │btime │599000 │ // ├──────┼──────┤ // │wtime │600000 │ // ├──────┼──────┤ // │byoyomi │60000 │ // └──────┴──────┘ // 単位はミリ秒ですので、599000 は 59.9秒 です。 // //---------------------------------------- // 棋譜ツリー、局面データは、position コマンドで先に与えられているものとします。 //---------------------------------------- // ┏━━━━プログラム━━━━┓ int latestTemezumi = this.Game.Kifu.CurNode.Value.KyokumenConst.Temezumi; //現・手目済 SkyConst src_Sky = this.Game.Kifu.NodeAt(latestTemezumi).Value.KyokumenConst; //現局面 //Logger.Trace($"将棋サーバー「{latestTemezumi}手目、きふわらべ さんの手番ですよ!」 {line}"); //---------------------------------------- // 王の状態を調べます。 //---------------------------------------- Result_KingState result_kingState; { result_kingState = Result_KingState.Empty; RO_Star king1p = Util_Starlightable.AsKoma(src_Sky.StarlightIndexOf(Finger_Honshogi.SenteOh).Now); RO_Star king2p = Util_Starlightable.AsKoma(src_Sky.StarlightIndexOf(Finger_Honshogi.GoteOh).Now); //Logger.Trace("将棋サーバー「ではここで、王さまがどこにいるか確認してみましょう」"); //Logger.Trace($"▲王の置き場={Conv_SyElement.Masu_ToOkiba(koma1.Masu)}"); //Logger.Trace($"△王の置き場={Conv_SyElement.Masu_ToOkiba(koma2.Masu)}"); if (Conv_SyElement.ToOkiba(king1p.Masu) != Okiba.ShogiBan) { // 先手の王さまが将棋盤上にいないとき☆ result_kingState = Result_KingState.Lost_SenteOh; } else if (Conv_SyElement.ToOkiba(king2p.Masu) != Okiba.ShogiBan) { // または、後手の王さまが将棋盤上にいないとき☆ result_kingState = Result_KingState.Lost_GoteOh; } else { result_kingState = Result_KingState.Empty; } } //------------------------------------------------------------ // わたしの手番のとき、王様が 将棋盤上からいなくなっていれば、投了します。 //------------------------------------------------------------ // // 将棋GUI『きふならべ』用☆ 将棋盤上に王さまがいないときに、本将棋で go コマンドが送られてくることは無いのでは☆? // switch (result_kingState) { case Result_KingState.Lost_SenteOh: // 先手の王さまが将棋盤上にいないとき☆ case Result_KingState.Lost_GoteOh: // または、後手の王さまが将棋盤上にいないとき☆ { //------------------------------------------------------------ // 投了 //------------------------------------------------------------ // // 図. // // log.txt // ┌──────────────────────────────────────── // ~ // │2014/08/02 2:36:21< bestmove resign // │ // // この将棋エンジンは、後手とします。 // 20手目、投了 を決め打ちで返します。 Playing.Send("bestmove resign"); //投了 } break; default: // どちらの王さまも、まだまだ健在だぜ☆! { List <KifuNode> bestKifuNodeList = new List <KifuNode>(); //------------------------------------------------------------ // 指し手のチョイス //------------------------------------------------------------ bool isHonshogi = true; //------------------------------------------------------------ // MultiPV のテスト中☆ //------------------------------------------------------------ // // 指し手を決めます。 // TODO: その指し手の評価値がいくらだったのか調べたい。 // // FIXME: ログがMultiPV別になっていないので、混ざって、同じ手を2度指しているみたいに見えてしまう☆ // int multiPV_Count = 1; // 2; { // 最善手、次善手、三次善手、四次善手、五次善手 for (int iMultiPV = 0; iMultiPV < multiPV_Count; iMultiPV++) { bestKifuNodeList.Add(this.WA_Bestmove( isHonshogi, this.Game.Kifu) ); } #if DEBUG //// 内容をログ出力 //// 最善手、次善手、三次善手、四次善手、五次善手 //StringBuilder sb = new StringBuilder(); //for (int iMultiPV = 0; iMultiPV < 5; iMultiPV++) //{ // string sfenText = Util_Sky.ToSfenMoveText(bestMoveList[iMultiPV]); // sb.AppendLine($"[{iMultiPV}]{sfenText}"); //} //System.Windows.Forms.MessageBox.Show(sb.ToString()); #endif } KifuNode bestKifuNode = null; // 最善手、次善手、三次善手、四次善手、五次善手 float bestScore = float.MinValue; for (int iMultiPV = 0; iMultiPV < bestKifuNodeList.Count; iMultiPV++) { KifuNode node = bestKifuNodeList[iMultiPV]; if (null != node && null != node.KyHyokaSheet_Mutable && bestScore <= node.Score) { bestScore = node.Score; bestKifuNode = node; } } IMove bestMove2; if (null == bestKifuNode) { // 投了 bestMove2 = Util_Sky258A.NullObjectMove; } else { bestMove2 = bestKifuNode.Key; } if (Util_Sky_BoolQuery.isEnableSfen(bestMove2)) { string sfenText = ConvMoveStrSfen.ToMoveStrSfen(bestMove2); // ログが重過ぎる☆! //Logger.Trace($"(Warabe)指し手のチョイス: bestmove=[{sfenText}] 棋譜={KirokuGakari.ToJsaKifuText(this.Kifu)}"); //---------------------------------------- // スコア 試し //---------------------------------------- { //int hyojiScore = (int)(bestScore / 100.0d);//FIXME:適当に調整した。 int hyojiScore = (int)bestScore; if (this.Game.Kifu.CurNode.Value.KyokumenConst.KaisiPside == Playerside.P2) { // 符号を逆転 hyojiScore = -hyojiScore; } Playing.Send($"info time 1 depth 1 nodes 1 score cp {hyojiScore.ToString()} pv "); //FIXME: //+ " pv 3a3b L*4h 4c4d" } //---------------------------------------- // 指し手を送ります。 //---------------------------------------- Playing.Send($"bestmove {sfenText}"); } else // 指し手がないときは、SFENが書けない☆ 投了だぜ☆ { // ログが重過ぎる☆! //Logger.Trace($"(Warabe)指し手のチョイス: 指し手がないときは、SFENが書けない☆ 投了だぜ☆ww(>_<) 棋譜={KirokuGakari.ToJsaKifuText(this.Kifu)}"); //---------------------------------------- // 投了w! //---------------------------------------- Playing.Send("bestmove resign"); } //------------------------------------------------------------ // 以前の手カッター //------------------------------------------------------------ UtilKifuTree282.IzennoHenkaCutter(this.Game.Kifu); } break; } // ┗━━━━プログラム━━━━┛ // Logger.Trace(); //throw new Exception("デバッグだぜ☆! エラーはキャッチできたかな~☆?(^▽^)"); }
/// <summary> /// /// </summary> /// <param name="line"></param> /// <param name="kifuNode"></param> public static void Log2_Png_Tyokkin(string line, KifuNode kifuNode) { var profilePath = System.Configuration.ConfigurationManager.AppSettings["Profile"]; var toml = Toml.ReadFile(Path.Combine(profilePath, "Engine.toml")); //Logger.Trace( // Util_Sky307.Json_1Sky(this.Kifu.CurNode.Value.ToKyokumenConst, $"現局面になっているのかなんだぜ☆? line={line}] 棋譜={KirokuGakari.ToJsaKifuText(this.Kifu, OwataMinister.WARABE_ENGINE)}", // "PgCS", // this.Kifu.CurNode.Value.ToKyokumenConst.Temezumi // ) //); // // 局面画像ログ // { // 出力先 string fileName = Path.Combine(profilePath, toml.Get <TomlTable>("Resources").Get <string>("ChokkinNoMoveLogPngBasename")); int srcMasu_orMinusOne = -1; int dstMasu_orMinusOne = -1; if (null != kifuNode.Key) { srcMasu_orMinusOne = Conv_SyElement.ToMasuNumber(((RO_Star)kifuNode.Key.LongTimeAgo).Masu); dstMasu_orMinusOne = Conv_SyElement.ToMasuNumber(((RO_Star)kifuNode.Key.Now).Masu); } KyokumenPngArgs_FoodOrDropKoma foodKoma; if (null != kifuNode.Key.FoodKomaSyurui) { switch (Util_Komasyurui14.NarazuCaseHandle((Komasyurui14)kifuNode.Key.FoodKomaSyurui)) { case Komasyurui14.H00_Null___: foodKoma = KyokumenPngArgs_FoodOrDropKoma.NONE; break; case Komasyurui14.H01_Fu_____: foodKoma = KyokumenPngArgs_FoodOrDropKoma.FU__; break; case Komasyurui14.H02_Kyo____: foodKoma = KyokumenPngArgs_FoodOrDropKoma.KYO_; break; case Komasyurui14.H03_Kei____: foodKoma = KyokumenPngArgs_FoodOrDropKoma.KEI_; break; case Komasyurui14.H04_Gin____: foodKoma = KyokumenPngArgs_FoodOrDropKoma.GIN_; break; case Komasyurui14.H05_Kin____: foodKoma = KyokumenPngArgs_FoodOrDropKoma.KIN_; break; case Komasyurui14.H07_Hisya__: foodKoma = KyokumenPngArgs_FoodOrDropKoma.HI__; break; case Komasyurui14.H08_Kaku___: foodKoma = KyokumenPngArgs_FoodOrDropKoma.KAKU; break; default: foodKoma = KyokumenPngArgs_FoodOrDropKoma.UNKNOWN; break; } } else { foodKoma = KyokumenPngArgs_FoodOrDropKoma.NONE; } // 直近の指し手。 Util_KyokumenPng_Writer.Write1( Conv_KifuNode.ToRO_Kyokumen1(kifuNode), srcMasu_orMinusOne, dstMasu_orMinusOne, foodKoma, ConvMoveStrSfen.ToMoveStrSfen(kifuNode.Key),//Conv_MoveStr_Jsa.ToMoveStr_Jsa(kifuNode, kifuNode.Value), "", fileName, Util_KifuTreeLogWriter.REPORT_ENVIRONMENT ); } }
/// <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: ; }