/// <summary> /// 差分更新で使う☆(^▽^)駒取り☆ /// </summary> public void Hetta(Option <Phase> optionalPhase, MotiKoma mk) { Hyokati henkaRyo = Conv_MotiKoma.MotikomaHyokati[(int)mk]; this.Increase(optionalPhase, (Hyokati)(-(int)henkaRyo)); this.Increase(Conv_Taikyokusya.Reverse(optionalPhase), henkaRyo); }
/// <summary> /// 差分更新で使う☆(^▽^)駒取り☆ /// </summary> public void Herasu(Option <Phase> optionalPhase, Koma km) { Hyokati henkaRyo = Conv_Hyokati.KomaHyokati[(int)km]; this.Increase(optionalPhase, (Hyokati)(-(int)henkaRyo)); this.Increase(Conv_Taikyokusya.Reverse(optionalPhase), henkaRyo); }
/// <summary> /// /// </summary> /// <param name="bestSasite">投了かどうか調べるだけ☆</param> public static void JudgeKettyaku(Move bestSasite, Kyokumen ky) { var optionalOpponent2 = Conv_Taikyokusya.Reverse(ky.CurrentOptionalPhase); if (Move.Toryo == bestSasite) { switch (ky.CurrentOptionalPhase.Unwrap())// 投了した時点で、次の手番に移っているぜ☆ { case Phase.White: // 対局者1が投了して、対局者2の手番になったということだぜ☆ // だから対局者2の勝ちだぜ☆ ky.Kekka = TaikyokuKekka.Taikyokusya2NoKati; break; case Phase.Black: ky.Kekka = TaikyokuKekka.Taikyokusya1NoKati; break; default: throw new Exception("未定義の手番"); } } else if (ky.Konoteme.IsSennitite()) { ky.Kekka = TaikyokuKekka.Sennitite; } // トライルール else if (Util_TryRule.IsTried(ky, optionalOpponent2//手番が進んでいるので、相手番のトライを判定☆ ) ) { switch (optionalOpponent2.Unwrap()) { case Phase.Black: ky.Kekka = TaikyokuKekka.Taikyokusya1NoKati; break; case Phase.White: ky.Kekka = TaikyokuKekka.Taikyokusya2NoKati; break; default: throw new Exception("未定義の手番"); } } else { // らいおんがいるか☆ bool raion1Vanished = ky.Shogiban.IsEmptyBBKoma(Koma.King1); bool raion2Vanished = ky.Shogiban.IsEmptyBBKoma(Koma.King2); if (raion1Vanished && raion2Vanished) { // らいおんが2匹ともいない場合(エラー) ky.Kekka = TaikyokuKekka.Hikiwake; } else if (raion2Vanished) { ky.Kekka = TaikyokuKekka.Taikyokusya1NoKati; } else if (raion1Vanished) { ky.Kekka = TaikyokuKekka.Taikyokusya2NoKati; } } }
/// <summary> /// コンピューター思考中表示☆(^~^) /// </summary> public static void AppendMessage_ComputerSikochu(Kyokumen ky, StringBuilder syuturyoku) { #if DEBUG syuturyoku.Append("**デバッグ・モード** ");//注意喚起☆(^▽^) #endif Conv_Taikyokusya.Setumei_Name(ky.CurrentOptionalPhase, syuturyoku); syuturyoku.Append("("); syuturyoku.Append(Option_Application.Optionlist.PNChar[OptionalPhase.IndexOf(ky.CurrentOptionalPhase)].ToString()); syuturyoku.Append(")の思考中(^~^)"); Logger.Flush(syuturyoku.ToString()); syuturyoku.Clear(); }
public static void Assert_Sabun_Kiki(string message, Kyokumen.Sindanyo kys) { // 駒の利き☆ bool safe = true; // 再計算 Recalculate Shogiban saikeisan = new Shogiban(kys); saikeisan.Tukurinaosi_1_Clear_KikiKomabetu(); saikeisan.Tukurinaosi_2_Input_KikiKomabetu(kys); foreach (var optionalPhase in Conv_Taikyokusya.AllOptionalPhaseList) // 対局者1、対局者2 { int iKm = 0; //どの駒でエラーがあったか foreach (Koma km in Conv_Koma.ItiranTai[OptionalPhase.IndexOf(optionalPhase)]) { if (!kys.EqualsKiki(km, saikeisan))//現行版と、再計算版の比較 { safe = false; break; } iKm++; } // ダイアログボックスに収まるように分けるぜ☆ if (!safe) { StringBuilder sindan1 = new StringBuilder(); //// 参考:駒の居場所 //{ // sindan1.Append(message); // sindan1.AppendLine("参考:駒の居場所"); // Util_Information.HyojiKomanoIbasho(ky.BB_KomaZenbu, ky.BB_Koma, sindan1); // sindan1.AppendLine($"Util_Tansaku.TansakuTyakusyuEdas=[{Util_Tansaku.TansakuTyakusyuEdas}]"); //} sindan1.Append(message); sindan1.Append("【エラー】"); Conv_Taikyokusya.Setumei_Name(optionalPhase, sindan1); sindan1.AppendLine(); sindan1.AppendLine($"iKm=[{iKm}]"); sindan1.AppendLine("利き:(再計算)"); Util_Information.Setumei_Bitboards(Med_Koma.GetKomasyuruiNamaeItiran(optionalPhase), saikeisan.WhereBBKiki(optionalPhase), sindan1); kys.Setumei_GenkoKiki(optionalPhase, sindan1); // 利き:(現行) var msg = sindan1.ToString(); sindan1.Clear(); Logger.Flush(msg); Debug.Assert(safe, msg); } } }
/// <summary> /// 手番の駒 の8近傍を調べて、利きに飛び込んでいたら真顔で真だぜ☆(^▽^) /// </summary> /// <param name="ky"></param> /// <param name="attackerMs">相手の攻撃駒の居場所</param> /// <param name="targetMs">狙っている升</param> /// <returns></returns> public static bool InKiki(Kyokumen ky, Masu attackerMs, Masu targetMs) { var optionalOpponent = Conv_Taikyokusya.Reverse(ky.CurrentOptionalPhase); if (ky.Shogiban.ExistsBBKomaZenbu(optionalOpponent, attackerMs)) // 指定の場所に相手の駒があることを確認 { if (ky.Shogiban.ExistsBBKoma(optionalOpponent, attackerMs, out Komasyurui ks)) // 攻撃側の駒の種類 { return(ky.Shogiban.GetKomanoUgokikata(Med_Koma.KomasyuruiAndTaikyokusyaToKoma(ks, optionalOpponent), attackerMs).IsIntersect( //相手の攻撃駒の利き targetMs //調べる升 )); } } return(false); }
/// <summary> /// 手番らいおん の逃げ道を開ける相手番の手かどうか調べるぜ☆(^▽^) /// </summary> /// <returns></returns> public bool IsNigemitiWoAkeru(Kyokumen ky, Komasyurui ks_aite, Masu ms_t0, Masu ms_t1) { if (NigemitiWoFusaideiruAiteNoKomaBB.IsOff(ms_t0)) { // 逃げ道を塞いでいる駒ではないのなら、スルーするぜ☆(^▽^) return(false); } // 手番らいおん の8近傍 のどこかに、重ね利きの数 0 が出来ていれば、 // 逃げ道を開けると判定するぜ☆(^▽^) bool akeru = false; Koma km_t0 = Med_Koma.KomasyuruiAndTaikyokusyaToKoma(ks_aite, CurrentOptionalPhase); Koma km_t1 = km_t0;// FIXME: 成りを考慮していない // 重ね利きの数を差分更新するぜ☆(^▽^) ky.Shogiban.N100_HerasuKiki(km_t0, ky.Sindan.CloneKomanoUgoki(km_t0, ms_t0), ky.Sindan); ky.Shogiban.N100_FuyasuKiki(km_t1, ky.Sindan.CloneKomanoUgoki(km_t1, ms_t1), ky.Sindan); Bitboard nigemitiBB = new Bitboard(); nigemitiBB.Set(FriendRaion8KinboBB); nigemitiBB.Sitdown(FriendKomaBB); while (nigemitiBB.Ref_PopNTZ(out Masu ms_nigemiti)) { if (0 == ky.Shogiban.CountKikisuZenbu(Conv_Taikyokusya.Reverse(CurrentOptionalPhase), ms_nigemiti)) // 相手番の利きが無くなったか☆(^▽^) { akeru = true; // (^▽^)逃げ道が開いたぜ☆! goto gt_EndLoop; } } gt_EndLoop: ; // 重ね利きの数の差分更新を、元に戻すぜ☆(^▽^) ky.Shogiban.N100_HerasuKiki(km_t1, ky.Sindan.CloneKomanoUgoki(km_t1, ms_t1), ky.Sindan); ky.Shogiban.N100_FuyasuKiki(km_t0, ky.Sindan.CloneKomanoUgoki(km_t0, ms_t0), ky.Sindan); return(akeru); }
//private static Option<T> Option<T>(T white) //{ // throw new NotImplementedException(); //} /// <summary> /// 将棋盤をコンソールへ出力するぜ☆(^▽^) /// コンソールでゲームするのに向いた表示☆ /// </summary> /// <returns></returns> public static void Setumei_NingenGameYo(Kyokumen ky, StringBuilder syuturyoku) { // 1行目 { // 千日手 int sennitite = ky.Konoteme.GetSennititeCount(); if (Const_Game.SENNITITE_COUNT == sennitite) { Conv_Taikyokusya.Setumei_Name(Conv_Taikyokusya.Reverse(ky.CurrentOptionalPhase), syuturyoku); syuturyoku.Append("の着手にて 千日手"); syuturyoku.AppendLine(); } else if (1 < sennitite) { syuturyoku.Append("同一局面反復 "); syuturyoku.Append(sennitite.ToString()); syuturyoku.AppendLine(" 回目"); } else { syuturyoku.AppendLine(); } } // 2行目 { // 何手目 syuturyoku.Append("図は"); syuturyoku.Append(string.Format("{0,3}", ky.Konoteme.ScanNantemadeBango())); syuturyoku.Append("手まで "); // 手番 Conv_Taikyokusya.Setumei_Name(ky.CurrentOptionalPhase, syuturyoku); syuturyoku.Append("の番"); // #仲ルール if (Option_Application.Optionlist.SagareruHiyoko) { syuturyoku.Append(" #仲"); } syuturyoku.AppendLine(); } // 3行目 後手の持ち駒の数 { foreach (MotiKomasyurui mks in Conv_MotiKomasyurui.Itiran) { MotiKoma mk = Med_Koma.MotiKomasyuruiAndPhaseToMotiKoma(mks, OptionalPhase.White); if (ky.MotiKomas.HasMotiKoma(mk)) { syuturyoku.Append(Conv_MotiKomasyurui.GetHyojiName(mks)); syuturyoku.Append(ky.MotiKomas.Get(mk).ToString()); } } syuturyoku.AppendLine(); } // 4行目 { syuturyoku.Append(" "); AppendLine_SujiFugo_Kyokumen(syuturyoku); //syuturyoku.AppendLine(" A B C "); } // 5行目~13行目 // 盤上 { // 5行目 syuturyoku.Append(" "); Util_Information.AppendLine_Top_Kyokumen(1, syuturyoku); // ┌──┬──┬──┐ for (int dan = 0; dan < Option_Application.Optionlist.BanTateHaba; dan++) { // 6,8,10,12行目 syuturyoku.Append(Conv_Kihon.ToZenkakuInteger(dan + 1)); AppendLine_Data_Kyokumen(ky, dan, syuturyoku); if (dan + 1 < Option_Application.Optionlist.BanTateHaba) { // 7,9,11行目 syuturyoku.Append(" "); AppendLine_Middle(1, syuturyoku);//├──┼──┼──┤ } } // 13行目 syuturyoku.Append(" "); AppendLine_Bottom(1, syuturyoku);//└──┴──┴──┘ } // 14行目 { // 先手の持ち駒の数 foreach (MotiKomasyurui mks in Conv_MotiKomasyurui.Itiran) { MotiKoma mk = Med_Koma.MotiKomasyuruiAndPhaseToMotiKoma(mks, OptionalPhase.Black); if (ky.MotiKomas.HasMotiKoma(mk)) { syuturyoku.Append(Conv_MotiKomasyurui.GetHyojiName(mks)); syuturyoku.Append(ky.MotiKomas.Get(mk).ToString()); } } syuturyoku.AppendLine(); } }
/// <summary> /// 一手詰めの局面かどうか調べるぜ☆(^▽^) /// /// 盤上の駒を動かすのか、駒台の駒を打つのかによって、利き の形が異なるぜ☆(^~^) /// /// 自分が一手詰めを掛けられるから、この指し手は作らないでおこう、といった使い方がされるぜ☆(^▽^) /// /// FIXME: 成りを考慮してない /// </summary> /// <param name="ky"></param> /// <param name="jibun"></param> /// <param name="ms_t0">移動元。持ち駒の場合、エラー値</param> /// <param name="ms_t1">移動先</param> /// <param name="jibunHioute"></param> /// <returns></returns> public static bool Ittedume_BanjoKoma(Kyokumen ky, Option <Phase> phase, Masu ms_t0, Masu ms_t1, HiouteJoho jibunHioute, HiouteJoho aiteHioute) { Debug.Assert(ky.Sindan.IsBanjo(ms_t1), "升エラー"); var optionalOpponent = Conv_Taikyokusya.Reverse(phase); // 動かす駒 if (!ky.Shogiban.ExistsBBKoma(phase, ms_t0, out Komasyurui ks_t0)) { StringBuilder reigai1 = new StringBuilder(); reigai1.AppendLine($"盤上の駒じゃないじゃないか☆(^▽^)www phase=[{ phase }] ms_src=[{ ms_t0 }] ks_jibun=[{ ks_t0 }]"); Util_Information.HyojiKomanoIbasho(ky.Shogiban, reigai1); var msg = reigai1.ToString(); Logger.Flush(msg); throw new Exception(msg); } Koma km_t0 = Med_Koma.KomasyuruiAndTaikyokusyaToKoma(ks_t0, phase); Koma km_t1 = km_t0; // FIXME: 成りを考慮していないぜ☆(>_<) // A B C // ┌──┬──┬──┐ //1│ │▽ら│ │ // ├──┼──┼──┤ //2│▲き│ │▲き│ // ├──┼──┼──┤ //3│ │▲に│▲ら│ // ├──┼──┼──┤ //4│▲ぞ│▲ひ│▲ぞ│ // └──┴──┴──┘ // 動かしたばかりの駒を 取り返されるようでは、一手詰めは成功しないぜ☆(^~^)(ステイルメイト除く) if (1 < ky.Shogiban.CountKikisuZenbu(optionalOpponent, ms_t1)) { // 移動先升は、相手らいおん の利きも 1つ あるはず。 // 移動先升に 相手の利きが2つあれば、駒を取り返される☆ return(false); } if (!ky.Shogiban.GetBBKoma(aiteHioute.KmRaion).IsIntersect( // 相手のらいおん ky.Shogiban.GetKomanoUgokikata(km_t0, ms_t1) // 移動先での駒の利き )) // 相手らいおん が、移動先での駒の利きの中に居ないんだったら、一手詰め にはならないぜ☆(^~^) { // FIXME: ステイルメイトは考えてないぜ☆(>_<) return(false); } Bitboard bb_idogoKikiNew = new Bitboard();// 移動後の、利き { // 盤上の重ね利きの数を差分更新するぜ☆(^▽^) { ky.Shogiban.N100_HerasuKiki(km_t0, ky.Sindan.CloneKomanoUgoki(km_t0, ms_t0), ky.Sindan); // 移動元の駒の利きを消すぜ☆(^▽^) ky.Shogiban.N100_FuyasuKiki(km_t1, ky.Sindan.CloneKomanoUgoki(km_t1, ms_t1), ky.Sindan); // 移動先の駒の利きを増やすぜ☆(^▽^) } // 移動後の利きを作り直し bb_idogoKikiNew = ky.Shogiban.ToBitboard_KikisuZenbuPositiveNumber(phase, ky.Sindan); // 盤上の重ね利きの数の差分更新を元に戻すぜ☆(^▽^) { //ky.BB_KikiZenbu ky.Shogiban.N100_HerasuKiki(km_t1, ky.Sindan.CloneKomanoUgoki(km_t1, ms_t1), ky.Sindan); // 移動先の駒の利きを減らすぜ☆(^▽^) ky.Shogiban.N100_FuyasuKiki(km_t0, ky.Sindan.CloneKomanoUgoki(km_t0, ms_t0), ky.Sindan); // 移動元の駒の利きを増やすぜ☆(^▽^) } } return (aiteHioute.FriendRaion8KinboBB.Clone() // 相手らいおん が逃げれる、相手らいおんの周りの空白 .Sitdown(ky.Shogiban.GetBBKomaZenbu(optionalOpponent)) // 相手の駒がない升 .Sitdown(bb_idogoKikiNew) // こっちの利きがない升 .IsEmpty()); // がない場合、詰み☆ ; }
/// <summary> /// 自殺手チェック☆ /// 相手番の利きに入っていたら真顔で真だぜ☆(^▽^) /// </summary> /// <param name="ky"></param> /// <param name="targetMs"></param> /// <returns></returns> public static bool IsJisatusyu(Kyokumen ky, Masu targetMs) { return(ky.Shogiban.GetBBKikiZenbu(Conv_Taikyokusya.Reverse(ky.CurrentOptionalPhase)).IsIntersect( // 相手の駒の利き☆ targetMs //調べる升 )); }
/// <summary> /// トライできる先。 /// </summary> /// <param name="ky">局面</param> /// <param name="kikiBB">手番らいおんの利きビットボード</param> /// <param name="tb">手番</param> /// <param name="ms1">手番らいおんがいる升</param> /// <returns></returns> public static Bitboard GetTrySaki(Kyokumen ky, Bitboard kikiBB, Option <Phase> optionalPhase, Masu ms1, StringBuilder syuturyoku) { var phaseIndex = OptionalPhase.IndexOf(optionalPhase); Util_Test.AppendLine("テスト: トライルール", syuturyoku); m_trySakiBB_.Clear(); // 自分はN段目にいる☆ int dan = Conv_Masu.ToDan_JibunSiten(optionalPhase, ms1, ky.Sindan); bool nidanme = 2 == dan; Util_Test.AppendLine("2段目にいるか☆?[{ nidanme }] わたしは[{ dan }]段目にいるぜ☆", syuturyoku); if (!nidanme) { Util_Test.AppendLine("むりだぜ☆", syuturyoku); Util_Test.Flush(syuturyoku); return(m_trySakiBB_); } // 1段目に移動できる升☆ m_trySakiBB_.Set(kikiBB); m_trySakiBB_.Select(ky.BB_Try[phaseIndex]); Util_Test.TestCode((StringBuilder syuturyoku2) => { Util_Information.Setumei_Bitboards(new string[] { "らいおんの利き", "1段目に移動できる升" }, new Bitboard[] { kikiBB, m_trySakiBB_ }, syuturyoku2); }); // 味方の駒がないところ☆ Bitboard spaceBB = new Bitboard(); spaceBB.Set(ky.BB_BoardArea); spaceBB.Sitdown(ky.Shogiban.GetBBKomaZenbu(optionalPhase)); m_trySakiBB_.Select(spaceBB); Util_Test.TestCode((StringBuilder str) => { Util_Information.Setumei_Bitboards(new string[] { "味方駒無い所", "トライ先" }, new Bitboard[] { spaceBB, m_trySakiBB_ }, str); }); if (m_trySakiBB_.IsEmpty()) { Util_Test.AppendLine("むりだぜ☆", syuturyoku); Util_Test.Flush(syuturyoku); return(m_trySakiBB_); } // 相手の利きが届いていないところ☆ var optionalOpponent2 = Conv_Taikyokusya.Reverse(optionalPhase); Bitboard safeBB = new Bitboard(); safeBB.Set(ky.BB_BoardArea); ky.Shogiban.ToSitdown_BBKikiZenbu(optionalOpponent2, safeBB); m_trySakiBB_.Select(safeBB); Util_Test.TestCode((StringBuilder syuturyoku2) => { Util_Information.Setumei_Bitboards(new string[] { "相手利き無い所", "トライ先" }, new Bitboard[] { safeBB, m_trySakiBB_ }, syuturyoku2); }); if (m_trySakiBB_.IsEmpty()) { Util_Test.AppendLine("むりだぜ☆", syuturyoku); Util_Test.Flush(syuturyoku); return(m_trySakiBB_); } Util_Test.AppendLine("トライできるぜ☆", syuturyoku); Util_Test.Flush(syuturyoku); return(m_trySakiBB_); }