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> /// <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> /// 指定された手の中から、王手局面を除外します。 /// /// 王手回避漏れを防ぎたいんだぜ☆ /// </summary> /// <param name="km_available">自軍の各駒の移動できる升セット</param> /// <param name="sbGohosyu"></param> /// <param name="logTag"></param> public static KifuNode LA_RemoveMate( bool isHonshogi, Maps_OneAndMulti <Finger, ShootingStarlightable> genTeban_komabetuAllMove1, // 現手番の、どの駒が、どんな手を指すことができるか int yomuDeep, //脳内読み手数 int tesumi_yomiGenTeban, Playerside pside_yomiGenTeban, KifuNode siteiNode_yomiGenTeban, bool enableLog, GraphicalLog_File logF_kiki, string hint) { Node <ShootingStarlightable, KyokumenWrapper> hubNode = UtilKomabetuMove.ToNextNodes_AsHubNode( genTeban_komabetuAllMove1, siteiNode_yomiGenTeban, pside_yomiGenTeban ); // ハブ・ノード自身はダミーノードなんだが、子ノードに、次のノードが入っている。 Converter04.AssertNariMove(hubNode, "#LA_RemoveMate(1)"); //ここはok Util_LegalMove.Log1(hubNode, enableLog, tesumi_yomiGenTeban, hint); if (isHonshogi) { // 王手が掛かっている局面を除きます。 Util_LegalMove.LAA_RemoveNextNode_IfMate( hubNode, enableLog, yomuDeep, tesumi_yomiGenTeban, pside_yomiGenTeban, logF_kiki); } Converter04.AssertNariMove(hubNode, "#LA_RemoveMate(2)王手局面削除直後");//ここはok // 「指し手一覧」を、「駒別の全指し手」に分けます。 Maps_OneAndMulti <Finger, ShootingStarlightable> komabetuAllMoves2 = siteiNode_yomiGenTeban.SplitMoveByKoma(hubNode); Converter04.AssertNariMove(komabetuAllMoves2, "#LA_RemoveMate(3)更に変換後");//ここはok // // 「駒別の指し手一覧」を、「駒別の進むマス一覧」になるよう、データ構造を変換します。 // Maps_OneAndOne <Finger, SySet <SyElement> > komabetuSusumuMasus = new Maps_OneAndOne <Finger, SySet <SyElement> >();// 「どの駒を、どこに進める」の一覧 foreach (KeyValuePair <Finger, List <ShootingStarlightable> > entry in komabetuAllMoves2.Items) { Finger finger = entry.Key; List <ShootingStarlightable> teList = entry.Value; // ポテンシャル・ムーブを調べます。 SySet <SyElement> masus_PotentialMove = new SySet_Default <SyElement>("ポテンシャルムーブ"); foreach (ShootingStarlightable te in teList) { RO_Star_Koma koma = Util_Koma.AsKoma(te.Now); masus_PotentialMove.AddElement(koma.Masu); } if (!masus_PotentialMove.IsEmptySet()) { // 空でないなら Util_KomabetuMasus.AddOverwrite(komabetuSusumuMasus, finger, masus_PotentialMove); } } // まず、ディクショナリー構造へ変換。 Dictionary <ShootingStarlightable, KyokumenWrapper> movebetuSky = Converter04.KomabetuMasus_ToMovebetuSky( komabetuSusumuMasus, siteiNode_yomiGenTeban.Value.ToKyokumenConst, pside_yomiGenTeban); // 棋譜ノード構造へ変換。 return(Converter04.MovebetuSky_ToHubNode(movebetuSky, KifuNodeImpl.GetReverseTebanside(pside_yomiGenTeban))); }
/// <summary> /// 棋譜データを元に、符号リスト1(*1)を出力します。 /// /// *1…「▲2六歩△8四歩▲7六歩」といった書き方。 /// /// </summary> /// <param name="fugoList"></param> public static string ToJapaneseKifuText( KifuTree kifu ) { StringBuilder sb = new StringBuilder(); sb.Append("position "); sb.Append(kifu.GetProperty(KifuTreeImpl.PropName_Startpos)); sb.Append(" moves "); // 採譜用に、新しい対局を用意します。 KifuTree saifuKifu; { saifuKifu = new KifuTreeImpl( new KifuNodeImpl( Util_Sky.NullObjectMove, new KyokumenWrapper(new SkyConst(Util_Sky.New_Hirate())), //日本の符号読取時 Playerside.P2 ) ); saifuKifu.Clear();// 棋譜を空っぽにします。 saifuKifu.SetProperty(KifuTreeImpl.PropName_FirstPside, Playerside.P1); saifuKifu.SetProperty(KifuTreeImpl.PropName_Startpos, "startpos");//平手の初期局面 // FIXME:平手とは限らないのでは? } kifu.ForeachHonpu(kifu.CurNode, (int tesumi, KyokumenWrapper kWrap, Node <ShootingStarlightable, KyokumenWrapper> node6, ref bool toBreak) => { if (0 == tesumi) { goto gt_EndLoop; } FugoJ fugo; //------------------------------ // 符号の追加(記録係) //------------------------------ KyokumenWrapper saifu_kWrap = saifuKifu.CurNode.Value; KifuNode newNode = new KifuNodeImpl( node6.Key, new KyokumenWrapper(saifu_kWrap.ToKyokumenConst), KifuNodeImpl.GetReverseTebanside(((KifuNode)saifuKifu.CurNode).Tebanside) ); // TODO: ↓? ((KifuNode)saifuKifu.CurNode).AppendChildA_New(newNode); saifuKifu.CurNode = newNode; RO_Star_Koma koma = Util_Koma.AsKoma(((ShootingStarlightable)node6.Key).LongTimeAgo); fugo = JFugoCreator15Array.ItemMethods[(int)Haiyaku184Array.Syurui(koma.Haiyaku)](node6.Key, saifu_kWrap);//「▲2二角成」なら、馬(dst)ではなくて角(src)。 sb.Append(fugo.ToText_UseDou(node6)); gt_EndLoop: ; }); return(sb.ToString()); }
/// <summary> /// まず前提として、 /// 現手番の「被王手の局面」だけがピックアップされます。 /// これはつまり、次の局面がないときは、その枝は投了ということです。 /// </summary> /// <param name="enableLog"></param> /// <param name="isHonshogi"></param> /// <param name="yomuDeep"></param> /// <param name="tesumi_yomiCur"></param> /// <param name="pside_yomiCur"></param> /// <param name="node_yomiCur"></param> /// <param name="logF_moveKiki"></param> /// <param name="logTag"></param> /// <returns>複数のノードを持つハブ・ノード</returns> private static KifuNode WAAAA_CreateNextNodes( MoveGenGenjo genjo, KifuNode node_yomiCur, SsssLogGenjo log ) { // 利きから、被王手の局面を除いたハブノード // このハブ・ノード自身は空っぽで、ハブ・ノードの次ノードが、次局面のリストになっています。 KifuNode hubNode; { // ①現手番の駒の移動可能場所_被王手含む List_OneAndMulti <Finger, SySet <SyElement> > komaBETUSusumeruMasus; { GraphicalLog_Board logBrd_move1 = new GraphicalLog_Board();// 盤1個分のログの準備 Util_MovableMove.LA_Get_KomaBETUSusumeruMasus( out komaBETUSusumeruMasus, //進めるマス new MmGenjo_MovableMasuImpl( genjo.Args.IsHonshogi, //本将棋か node_yomiCur.Value.ToKyokumenConst, //現在の局面 genjo.Pside_teban, //手番 false //相手番か ), new MmLogGenjoImpl( log.EnableLog, //ログを出力するかfalse, logBrd_move1, //ログ? genjo.YomuDeep, //読みの深さ genjo.Tesumi_yomiCur, //手済み node_yomiCur.Key //指し手 ) ); MoveGenRoutine.Log1(genjo, node_yomiCur, logBrd_move1);//ログ試し } // ②利きから、被王手の局面を除いたハブノード if (genjo.Args.IsHonshogi) { Maps_OneAndMulti <Finger, ShootingStarlightable> komaBETUAllMoves = Converter04.KomaBETUSusumeruMasusToKomaBETUAllMoves(komaBETUSusumeruMasus, node_yomiCur); Converter04.AssertNariMove(komaBETUAllMoves, "#WAAAA_CreateNextNodes(1)"); // 本将棋の場合、王手されている局面は削除します。 hubNode = Util_LegalMove.LA_RemoveMate( genjo.Args.IsHonshogi, komaBETUAllMoves, genjo.YomuDeep, genjo.Tesumi_yomiCur, genjo.Pside_teban, node_yomiCur, log.EnableLog, genjo.Args.LogF_moveKiki,//利き用 "読みNextルーチン"); Converter04.AddNariMove(node_yomiCur, hubNode); Converter04.AssertNariMove(hubNode, "#WAAAA_CreateNextNodes(2)");//ここで消えていた☆ } else { //そのまま変換 Dictionary <ShootingStarlightable, KyokumenWrapper> ss = Converter04.KomabetuMasusToMovebetuSky( komaBETUSusumeruMasus, node_yomiCur.Value.ToKyokumenConst, genjo.Pside_teban); hubNode = Converter04.MovebetuSky_ToHubNode(ss, KifuNodeImpl.GetReverseTebanside(genjo.Pside_teban)); } } return(hubNode); }
/// <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: // ; }
/// <summary> /// /// </summary> /// <param name="figMovedKoma"></param> /// <param name="move">棋譜に記録するために「指す前/指した後」を含めた手。</param> /// <param name="kifu"></param> /// <param name="isMakimodosi"></param> private static void Kifusasi25( out Finger figMovedKoma, ShootingStarlightable move, KifuTree kifu, bool isMakimodosi , [CallerMemberName] string memberName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0 ) { figMovedKoma = Fingers.Error_1; SkyConst src_Sky = kifu.CurNode.Value.ToKyokumenConst; //------------------------------------------------------------ // 選択 : 動かす駒 //------------------------------------------------------------ if (isMakimodosi) { // [巻戻し]のとき //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> // 打った駒も、指した駒も、結局は将棋盤の上にあるはず。 RO_Star_Koma koma = Util_Koma.AsKoma(move.Now); // 動かす駒 figMovedKoma = Util_Sky.Finger_AtMasuNow_Shogiban( src_Sky, koma.Pside, koma.Masu//[巻戻し]のときは、先位置が 駒の居場所。 ); } else { // 進むとき //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> //------------------------------ // 符号の追加(一手進む) //------------------------------ KifuNode genKyokumenCopyNode = new KifuNodeImpl(move, new KyokumenWrapper(src_Sky), KifuNodeImpl.GetReverseTebanside(((KifuNode)kifu.CurNode).Tebanside)); // TODO: ↓? ((KifuNode)kifu.CurNode).AppendChildA_New(genKyokumenCopyNode); kifu.CurNode = genKyokumenCopyNode; if (Util_Sky.IsDaAction(move)) { //---------- // 駒台から “打” //---------- RO_Star_Koma srcKoma = Util_Koma.AsKoma(move.LongTimeAgo); RO_Star_Koma dstKoma = Util_Koma.AsKoma(move.Now); figMovedKoma = Util_Sky.FingerNow_BySyuruiIgnoreCase( src_Sky, Util_Masu.GetOkiba(srcKoma.Masu), Haiyaku184Array.Syurui(dstKoma.Haiyaku) ); } else { //---------- // 将棋盤から //---------- RO_Star_Koma srcKoma = Util_Koma.AsKoma(move.LongTimeAgo); RO_Star_Koma dstKoma = Util_Koma.AsKoma(move.Now); figMovedKoma = Util_Sky.Finger_AtMasuNow_Shogiban( src_Sky, dstKoma.Pside, Util_Masu.OkibaSujiDanToMasu( Util_Masu.GetOkiba(Masu_Honshogi.Items_All[Util_Masu.AsMasuNumber(dstKoma.Masu)]), Util_Masu.AsMasuNumber(srcKoma.Masu) ) ); } } }