public JosekiMove AddMove(Move bestMove, Hyokati hyokati, int fukasa, int version) { JosekiMove josekiSs; if (!this.SsItems.ContainsKey(bestMove)) { // 無ければ問答無用で追加☆(^▽^) josekiSs = new JosekiMove(bestMove, Move.Toryo, hyokati, fukasa, version, this); this.SsItems.Add(bestMove, josekiSs); this.Owner.Edited = true; } else { // 既存なら josekiSs = this.SsItems[bestMove]; if (josekiSs.Version < version) // 新しいソフトの評価を優先☆ { josekiSs = new JosekiMove(bestMove, Move.Toryo, hyokati, fukasa, version, this); this.SsItems[bestMove] = josekiSs; this.Owner.Edited = true; } // バージョンが同じなら else if (josekiSs.Fukasa < fukasa)// 深い探索の方を優先☆(^▽^) { josekiSs = new JosekiMove(bestMove, Move.Toryo, hyokati, fukasa, version, this); this.SsItems[bestMove] = josekiSs; this.Owner.Edited = true; } // 深さが同じなら // 無視☆ } return(josekiSs); }
/// <summary> /// 反転できるものは反転するぜ☆(^▽^) /// </summary> /// <param name="ref_hyokati"></param> /// <returns></returns> public static void Hanten(ref Hyokati ref_hyokati) { if (Conv_Hyokati.InHyokatiOrTumeTesu(ref_hyokati)) { ref_hyokati = (Hyokati)(-(int)ref_hyokati); } }
public static void Update(Hyokati hyokati, Option <Phase> optionalPhase, int teme) { var phaseIndex = OptionalPhase.IndexOf(optionalPhase); if (Conv_Hyokati.InTumeTesu(hyokati)) { // 詰め手数が表示されているぜ☆ if (Util_Taikyoku.PNNantedume_Teme[phaseIndex] == int.MaxValue) { // 詰め手数が新たに表示されたようだぜ☆ Util_Taikyoku.PNNantedume_Teme[phaseIndex] = teme; } // 前から表示されていたのなら、そのままだぜ☆(^▽^) } else { // 詰め手数は、表示されていないぜ☆ if (Util_Taikyoku.PNNantedume_Teme[phaseIndex] != int.MaxValue) { // 詰め手数が消えたようだぜ☆ Util_Taikyoku.PNNantedume_Teme[phaseIndex] = int.MaxValue; } // もともと表示されていなかったのなら、そのままだぜ☆(^▽^) } }
/// <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); }
public static string ToContents(Hyokati hyokaSu) { StringBuilder hyoji = new StringBuilder(); Setumei(hyokaSu, hyoji); return(hyoji.ToString()); }
/// <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); }
public static void Update(Hyokati hyokaSu, Taikyokusya taikyokusya) { if (Conv_Tumesu.None != hyokaSu.tumeSu) { // 詰め手数が表示されているぜ☆ if (Util_Taikyoku.nantedumeTeme_playerN[(int)taikyokusya] == int.MaxValue) { // 詰め手数が新たに表示されたようだぜ☆ Util_Taikyoku.nantedumeTeme_playerN[(int)taikyokusya] = PureMemory.kifu_endTeme; } // 前から表示されていたのなら、そのままだぜ☆(^▽^) } else { // 詰め手数は、表示されていないぜ☆ if (Util_Taikyoku.nantedumeTeme_playerN[(int)taikyokusya] != int.MaxValue) { // 詰め手数が消えたようだぜ☆ Util_Taikyoku.nantedumeTeme_playerN[(int)taikyokusya] = int.MaxValue; } // もともと表示されていなかったのなら、そのままだぜ☆(^▽^) } }
public static void Assert_Sabun_Komawari(string message, Kyokumen.Sindanyo kys, StringBuilder syuturyoku) { KomawariHyokatiSabunItiran saikeisan = new KomawariHyokatiSabunItiran(); saikeisan.Tukurinaosi(kys); Hyokati hyokati1 = kys.GetKomawari(OptionalPhase.Black); Hyokati hyokati2 = kys.GetKomawari(OptionalPhase.White); bool safe = hyokati1 == saikeisan.Get(OptionalPhase.Black) && hyokati2 == saikeisan.Get(OptionalPhase.White) ; string msg = $@"{message}#河馬 診断 駒割り評価値 P1差分 =[{hyokati1}] 再計算=[{saikeisan.Get(OptionalPhase.Black)}] P2差分 =[{hyokati2}] 再計算=[{saikeisan.Get(OptionalPhase.White)}] "; if (!safe) { syuturyoku.AppendLine(msg); { var msg2 = syuturyoku.ToString(); syuturyoku.Clear(); Logger.Flush(msg2); } } Debug.Assert(safe, msg); }
/// <summary> /// 詰め手数を示していれば、真だぜ☆(^▽^) /// </summary> /// <param name="hyokati"></param> /// <returns></returns> public static bool InTumeTesu(Hyokati hyokati) { return ((Hyokati.TumeTesu_FuNoSu_ReiTeTumerare <= hyokati && hyokati <= Hyokati.TumeTesu_FuNoSu_HyakuTeTumerare) || (Hyokati.TumeTesu_SeiNoSu_HyakuTeDume <= hyokati && hyokati <= Hyokati.TumeTesu_SeiNoSu_ReiTeDume) ); }
/// <summary> /// 符号を反転したものを返す /// </summary> public HyokatiUtiwake ToHanten() { Hyokati edaBest2 = EdaBest; Conv_Hyokati.Hanten(ref edaBest2); Hyokati komawari2 = Komawari; Conv_Hyokati.Hanten(ref komawari2); Hyokati nikoma2 = Nikoma; Conv_Hyokati.Hanten(ref nikoma2); Hyokati okimari2 = Okimari; Conv_Hyokati.Hanten(ref okimari2); return(new HyokatiUtiwake(edaBest2, komawari2, nikoma2, okimari2, Riyu, RiyuHosoku)); }
public JosekiMove(Move move, Move ousyu, Hyokati hyokati, int fukasa, int version, JosekiKyokumen owner) { this.Owner = owner; this.Move = move; this.Ousyu = ousyu; this.Hyokati = hyokati; this.Fukasa = fukasa; this.Version = version; }
/// <summary> /// 評価値、または 詰め手数を示していれば、真だぜ☆(^▽^) /// </summary> /// <param name="hyokati"></param> /// <returns></returns> public static bool InHyokatiOrTumeTesu(Hyokati hyokati) { return // 0手詰められ ~ 評価値 ~ 0手詰め (Hyokati.TumeTesu_FuNoSu_ReiTeTumerare <= hyokati && hyokati <= Hyokati.TumeTesu_SeiNoSu_ReiTeDume ); }
public HyokatiUtiwake(Hyokati edaBest, Hyokati komawari, Hyokati nikoma, Hyokati okimari, HyokaRiyu riyu, string riyuHosoku) { EdaBest = edaBest; Komawari = komawari; Nikoma = nikoma; Okimari = okimari; Riyu = riyu; RiyuHosoku = riyuHosoku; Assert(); }
/// <summary> /// 詰みの場合、数字をカウントアップするぜ☆(^▽^) /// </summary> /// <returns></returns> public static Hyokati CountUpTume(Hyokati hyokati) { if (Hyokati.TumeTesu_SeiNoSu_HyakuTeDume < hyokati) { hyokati = hyokati - 1; // 何手詰めの数字が大きくなるぜ☆ } else if (hyokati < Hyokati.TumeTesu_FuNoSu_HyakuTeTumerare) { hyokati = hyokati + 1; // 何手詰められの数字が大きくなるぜ☆ } return(hyokati); }
/// <summary> /// 評価値の計算し直し。 /// /// 多対多の項目の組み合わせを全部加算。 /// </summary> /// <param name="ky"></param> /// <returns>手番の視点で返す</returns> public void KeisanSinaosi(Kyokumen ky) { // 駒の位置(評価関数の項目番号)をリストに入れておくぜ☆ Util_NikomaKankei.MakeKoumokuBangoHairetu_Subete(ky, Util_NikomaKankei.KoumokuBangoHairetu1); // 評価値 int hyokati = 0; for (int iGyoIndex = 0; iGyoIndex < Util_NikomaKankei.KoumokuBangoHairetu1.Nagasa; iGyoIndex++) { for (int iRetuIndex = 0; iRetuIndex < Util_NikomaKankei.KoumokuBangoHairetu1.Nagasa; iRetuIndex++) { if (Util_NikomaKankei.KoumokuBangoHairetu1.Hairetu[iGyoIndex] <= Util_NikomaKankei.KoumokuBangoHairetu1.Hairetu[iRetuIndex])// 組み合わせを反対から見ただけの同じものを弾くぜ☆(^~^) { continue; } // 差分更新と比較するので、差分更新用☆(^~^) //hyokati += Util_NikomaKankei.GetHyokaNumber_SabunKosinYou(Util_NikomaKankei.KoumokuBangoHairetu1.Hairetu[iRetuIndex], Util_NikomaKankei.KoumokuBangoHairetu1.Hairetu[iGyoIndex]); // (^▽^)関数(小さい数字,大きい数字)だぜ☆ そうでなければ逆立ちさせるぜ☆(^▽^)www if (Util_NikomaKankei.KoumokuBangoHairetu1.Hairetu[iRetuIndex] < Util_NikomaKankei.KoumokuBangoHairetu1.Hairetu[iGyoIndex]) { hyokati += Util_NikomaKankei.GetHyokaNumber_SabunKosinYou(Util_NikomaKankei.KoumokuBangoHairetu1.Hairetu[iRetuIndex], Util_NikomaKankei.KoumokuBangoHairetu1.Hairetu[iGyoIndex]); } else if (Util_NikomaKankei.KoumokuBangoHairetu1.Hairetu[iGyoIndex] < Util_NikomaKankei.KoumokuBangoHairetu1.Hairetu[iRetuIndex]) { // 逆立ち☆(^▽^)www hyokati += Util_NikomaKankei.GetHyokaNumber_SabunKosinYou(Util_NikomaKankei.KoumokuBangoHairetu1.Hairetu[iGyoIndex], Util_NikomaKankei.KoumokuBangoHairetu1.Hairetu[iRetuIndex]); } } } if (hyokati < Util_NikomaKankei.SAISYO_HYOKATI_SABUNKOSINYOU) { hyokati = Util_NikomaKankei.SAISYO_HYOKATI_SABUNKOSINYOU; } else if (Util_NikomaKankei.SAIDAI_HYOKATI_SABUNKOSINYOU < hyokati) { hyokati = Util_NikomaKankei.SAIDAI_HYOKATI_SABUNKOSINYOU; } var(exists, phase) = ky.CurrentOptionalPhase.Match; if (exists) { if (phase == Phase.White) { hyokati = -hyokati; // 対局者2視点に変えるぜ☆(^▽^) } } Hyokati = (Hyokati)hyokati; }
/// <summary> /// 定跡更新(ゲームセクション内) /// </summary> public static void Update2_JosekiToroku(Move bestMove, Hyokati bestHyokati, Kyokumen ky, StringBuilder syuturyoku) { if (Util_Machine.IsEnableBoardSize() && Option_Application.Optionlist.JosekiRec) { if (!IsJosekiTraced)// 定跡を使った指し手ではない場合に限り { #if DEBUG // 指し手の整合性をチェックしておきたいぜ☆(^▽^) { Kyokumen ky_forAssert = new Kyokumen(); int caret_2 = 0; if (!ky_forAssert.ParsePositionvalue(Option_Application.Optionlist.USI, KyFen_before, ref caret_2, true, false, out string moves, syuturyoku)) // ビットボードを更新したいので、適用する { syuturyoku.AppendLine("パースに失敗だぜ☆(^~^)! #鯰"); var msg = syuturyoku.ToString(); syuturyoku.Clear(); Logger.Flush(msg); throw new Exception(msg); } if (!ky_forAssert.CanDoMove(bestMove, out MoveMatigaiRiyu riyu)) { StringBuilder reigai1 = new StringBuilder(); reigai1.AppendLine("指せない指し手を定跡に登録しようとしたぜ☆(^~^)!:"); // reigai1.Append("理由:"); ConvMove.SetumeiLine(riyu, reigai1); reigai1.Append("指し手:"); ConvMove.SetumeiLine(Option_Application.Optionlist.USI, bestMove, reigai1); reigai1.Append("定跡にする1手前の局面 ("); reigai1.Append(KyFen_before); reigai1.AppendLine(")"); Util_Information.Setumei_Lines_Kyokumen(ky_forAssert, reigai1); reigai1.AppendLine(); reigai1.Append("1手後は、現局面"); Util_Information.Setumei_Lines_Kyokumen(ky, reigai1); syuturyoku.AppendLine(reigai1.ToString()); var msg = syuturyoku.ToString(); syuturyoku.Clear(); Logger.Flush(msg); throw new Exception(msg); } } #endif Option_Application.Joseki.AddMove(KyFen_before, KyHash_before, OptionalPhaseBeforeMove, bestMove, bestHyokati, Util_Tansaku.NekkoKaranoFukasa, Util_Application.VERSION, syuturyoku); } } }
/// <summary> /// 局面に点数を付けるぜ☆(^▽^) /// /// どちらの対局者でも、自分に有利と思っていれば正の数の方向に点数が付くぜ☆(^▽^) /// </summary> /// <param name="ky_base"></param> /// <returns></returns> public void Tukurinaosi(Kyokumen.Sindanyo kys) { Hyokati[] hyokati = new Hyokati[] { Hyokati.Hyokati_Rei, Hyokati.Hyokati_Rei , Hyokati.Hyokati_Rei // 空白は手番なしで ここに入れるぜ☆(^~^) }; // 盤上 Bitboard komaBB = new Bitboard(); for (int iTai = 0; iTai < Conv_Taikyokusya.AllOptionalPhaseList.Length; iTai++) { var optionalPhase = Conv_Taikyokusya.AllOptionalPhaseList[iTai]; for (int iKs = 0; iKs < Conv_Komasyurui.Itiran.Length; iKs++) { Komasyurui ks = Conv_Komasyurui.Itiran[iKs]; kys.ToSetIbasho(Med_Koma.KomasyuruiAndTaikyokusyaToKoma(ks, optionalPhase), komaBB); while (komaBB.Ref_PopNTZ(out Masu ms_jissai)) { hyokati[iTai] += Conv_Koma.BanjoKomaHyokatiNumber[(int)Med_Koma.KomasyuruiAndTaikyokusyaToKoma(ks, optionalPhase)]; } } } // 持ち駒 foreach (MotiKoma mk in Conv_MotiKoma.Itiran) { var optionalPhase = Med_Koma.MotiKomaToPhase(mk); var phaseIndex = OptionalPhase.IndexOf(optionalPhase); MotiKomasyurui mks = Med_Koma.MotiKomaToMotiKomasyrui(mk); Hyokati komaHyokati = Conv_Hyokati.KomaHyokati[(int)Med_Koma.MotiKomasyuruiAndPhaseToKoma(mks, optionalPhase)]; hyokati[phaseIndex] += (int)komaHyokati * kys.CountMotikoma(mk); } // 手番 - 相手番 Hyokati hyokatiP1 = hyokati[(int)Phase.Black]; hyokati[(int)Phase.Black] -= hyokati[(int)Phase.White]; hyokati[(int)Phase.White] -= hyokatiP1; KomawariHyokati_Sabun = hyokati; }
public static void Assert_Sabun_Nikoma(string message, Kyokumen ky, StringBuilder syuturyoku) { Hyokati current = ky.Nikoma.Get(false); NikomaHyokati saikeisan = new NikomaHyokati(); saikeisan.KeisanSinaosi(ky); bool safe = Math.Abs(current - saikeisan.Hyokati) < 2; // 差分更新で 誤差 が出ると、どんどん溜まっていくぜ☆(^▽^)www string msg = $"{message} 二駒評価値 差分更新 current =[{ current }] 再計算=[{ saikeisan }]"; if (!safe) { syuturyoku.AppendLine(msg); { var msg2 = syuturyoku.ToString(); syuturyoku.Clear(); Logger.Flush(msg2); } } Debug.Assert(safe, msg); }
public static void JohoMatome( int fukasa, Hyokati hyokasuToBack, StringBuilder hyoji #if DEBUG , string hint #endif ) { if (Util_TimeManager.CanShowJoho()) { PureAppli.dlgt_CreateJoho( PureMemory.kifu_teban, hyokasuToBack, fukasa + 1,// 深さは 0 になっているので、Tansaku していない状態(=+1 して)に戻すぜ☆ HanpukuSinka.happaenoFukasa, hyoji #if DEBUG , hint #endif ); Util_TimeManager.DoneShowJoho(); } }
public void Hanten() { this.Hyokati = (Hyokati)(-(int)this.Hyokati); }
public void Increase(Hyokati henkaRyo) { this.Hyokati += (int)henkaRyo; }
/// <summary> /// 定跡ファイルの容量を小さくしたいときに、定跡を削っていくぜ☆(^~^) /// </summary> /// <param name="removeBytes">減らしたいバイトサイズ☆(^▽^)</param> public long DownSizeing(long removeBytes) { long removed = 0; if (removeBytes < 1) { return(removed); } // 削る優先順 // (1)バージョンが古い順、 // (2)深さが浅い順、 // (3)1つの局面の中で、2つ以上の指し手があり、評価値が一番悪い手、 // (4)あとは泣く泣く適当に削る☆ // // 最後に、指し手を持たない局面を削っておくぜ☆ //──────────────────────────────────────── // (1)バージョンが古い順 //──────────────────────────────────────── while (true) { // 全ての手を走査し、一番バージョン番号が古いもの☆(^▽^) int oldest = int.MaxValue; int newest = int.MinValue; foreach (JosekiKyokumen josekiKy in this.KyItems.Values) { foreach (JosekiMove josekiSs in josekiKy.SsItems.Values) { if (josekiSs.Version < oldest) { oldest = josekiSs.Version; } else if (newest < josekiSs.Version) { newest = josekiSs.Version; } } } if (oldest == newest || newest < oldest) { break; } foreach (JosekiKyokumen josekiKy in this.KyItems.Values) { // バージョン番号が古いキーを列挙☆(^▽^) List <Move> removee = new List <Move>(); foreach (KeyValuePair <Move, JosekiMove> entry in josekiKy.SsItems) { if (oldest == entry.Value.Version) { removee.Add(entry.Key); } } // 列挙したキーに従って削除だぜ☆(^▽^) foreach (Move key in removee) { int size = josekiKy.SsItems[key].ToString().Length; josekiKy.SsItems.Remove(key); removeBytes -= size; removed += size; if (removeBytes < 1) { goto gt_FinishRemove; } } } } //──────────────────────────────────────── // (2)深さが浅い順、 //──────────────────────────────────────── while (true) { // 全ての手を走査し、一番深さが浅いもの☆(^▽^) int shallowest = int.MaxValue; int deepest = int.MinValue; foreach (JosekiKyokumen josekiKy in this.KyItems.Values) { foreach (JosekiMove josekiSs in josekiKy.SsItems.Values) { if (josekiSs.Fukasa < shallowest) { shallowest = josekiSs.Fukasa; } else if (deepest < josekiSs.Fukasa) { deepest = josekiSs.Fukasa; } } } if (shallowest == deepest || deepest < shallowest) { break; } // 深さが該当する手は消すぜ☆(^▽^) foreach (JosekiKyokumen josekiKy in this.KyItems.Values) { // 浅いキーを列挙☆(^▽^) List <Move> removee = new List <Move>(); foreach (KeyValuePair <Move, JosekiMove> entry in josekiKy.SsItems) { if (shallowest == entry.Value.Fukasa) { removee.Add(entry.Key); } } // 列挙したキーに従って削除だぜ☆(^▽^) foreach (Move key in removee) { int size = josekiKy.SsItems[key].ToString().Length; josekiKy.SsItems.Remove(key); removeBytes -= size; removed += size; if (removeBytes < 1) { goto gt_FinishRemove; } } } } //──────────────────────────────────────── // (3)1つの局面の中で、2つ以上の指し手があり、評価値が一番悪い手 //──────────────────────────────────────── foreach (JosekiKyokumen josekiKy in this.KyItems.Values) { if (2 <= josekiKy.SsItems.Count) { // 全ての手を走査し、一番評価が悪いもの☆(^▽^) Hyokati badest = Hyokati.TumeTesu_SeiNoSu_ReiTeDume; Hyokati goodest = Hyokati.TumeTesu_FuNoSu_ReiTeTumerare; foreach (JosekiMove josekiSs in josekiKy.SsItems.Values) { if (josekiSs.Hyokati < badest) { badest = josekiSs.Hyokati; } else if (goodest < josekiSs.Hyokati) { goodest = josekiSs.Hyokati; } } if (badest == goodest || goodest < badest) { break; } // 評価が悪いキーを列挙☆(^▽^) List <Move> removee = new List <Move>(); foreach (KeyValuePair <Move, JosekiMove> entry in josekiKy.SsItems) { if (badest == entry.Value.Hyokati) { removee.Add(entry.Key); } } // 列挙したキーに従って削除だぜ☆(^▽^) foreach (Move key in removee) { int size = josekiKy.SsItems[key].ToString().Length; josekiKy.SsItems.Remove(key); removeBytes -= size; removed += size; if (removeBytes < 1) { goto gt_FinishRemove; } } } } //──────────────────────────────────────── // (4)あとは泣く泣く適当に削る☆ //──────────────────────────────────────── { // 全部のキーを列挙☆(^▽^) List <ulong> removee = new List <ulong>(); foreach (KeyValuePair <ulong, JosekiKyokumen> entry in this.KyItems) { removee.Add(entry.Key); } // 列挙したキーに従って削除だぜ☆(^▽^) foreach (ulong key in removee) { int size = this.KyItems[key].ToString().Length; this.KyItems.Remove(key); removeBytes -= size; removed += size; if (removeBytes < 1) { goto gt_FinishRemove; } } } gt_FinishRemove: //──────────────────────────────────────── // (最後に)指し手を持たない局面を削る☆ //──────────────────────────────────────── { // 指し手を持たない局面のキーを列挙☆(^▽^) List <ulong> removee = new List <ulong>(); foreach (KeyValuePair <ulong, JosekiKyokumen> entry in this.KyItems) { if (entry.Value.SsItems.Count < 1) { removee.Add(entry.Key); } } // 列挙したキーに従って削除だぜ☆(^▽^) foreach (ulong key in removee) { this.KyItems.Remove(key); } } if (0 < removed) { this.Edited = true; } return(removed); }
/// <summary> /// 評価値の表示。 /// 基本的に数字なんだが、数字の前に説明がつくことがあるぜ☆(^~^) /// 説明は各括弧で囲んであるぜ☆(^▽^) /// </summary> /// <param name="hyokaSu"></param> /// <param name="hyoji"></param> public static void Setumei(Hyokati hyokaSu, StringBuilder hyoji) { if (hyokaSu.tumeSu == Conv_Tumesu.None) { // スルー } else if (hyokaSu.IsKatu()) { // 詰み手数が見えたときだぜ☆(^▽^) switch (PureSettei.fenSyurui) { case FenSyurui.sfe_n: { hyoji.Append("mate "); hyoji.Append(hyokaSu.GetKatu().ToString()); } break; case FenSyurui.dfe_n: { hyoji.Append("[katu "); hyoji.Append(hyokaSu.GetKatu().ToString()); hyoji.Append("] "); hyoji.Append(hyokaSu.ToString_Ten()); } break; default: throw new Exception(string.Format("未定義 {0}", PureSettei.fenSyurui)); } return; } else if (hyokaSu.IsMakeru()) { // 詰めを食らうぜ☆(>_<) switch (PureSettei.fenSyurui) { case FenSyurui.sfe_n: { hyoji.Append("mate "); hyoji.Append(hyokaSu.GetMakeru().ToString()); } break; case FenSyurui.dfe_n: { // 負数で出てくるのを、正の数に変換して表示するぜ☆(^▽^) hyoji.Append("[makeru "); hyoji.Append(hyokaSu.GetMakeru().ToString()); hyoji.Append("] "); hyoji.Append(hyokaSu.ToString_Ten()); } break; default: throw new Exception(string.Format("未定義 {0}", PureSettei.fenSyurui)); } return; } // 評価値☆ hyoji.Append("cp "); hyoji.Append(hyokaSu.ToString_Ten());//enum型の名前が出ないように一旦int型に変換 }
static PureMemory() { int taiLn = Conv_Taikyokusya.itiran.Length; #region 被王手判定 // ビットボード hot_bb_checkerAr = new Bitboard[taiLn]; hot_bb_raion8KinboAr = new Bitboard[taiLn]; hot_bb_nigemitiWoFusaideiruAiteNoKomaAr = new Bitboard[taiLn]; hot_bb_nigereruAr = new Bitboard[taiLn]; hot_bb_nigeroAr = new Bitboard[taiLn]; for (int iTai = 0; iTai < taiLn; iTai++) { hot_bb_checkerAr[iTai] = new Bitboard(); hot_bb_raion8KinboAr[iTai] = new Bitboard(); hot_bb_nigemitiWoFusaideiruAiteNoKomaAr[iTai] = new Bitboard(); hot_bb_nigereruAr[iTai] = new Bitboard(); hot_bb_nigeroAr[iTai] = new Bitboard(); } hot_ms_raionAr = new Masu[taiLn]; hot_outeKomasCountAr = new int[taiLn]; hot_isNigerarenaiCheckerAr = new bool[taiLn]; hot_raionCatchChosaAr = new bool[taiLn]; #endregion #region 指し手生成(シングルスレッドを想定) ssss_moveList = new MoveList[PureMemory.MaxMoveDepth]; ssss_moveListBad = new MoveList[PureMemory.MaxMoveDepth]; ssss_bbVar_idosaki_narazu = new Bitboard(); ssss_bbVar_idosaki_nari = new Bitboard(); ssssTmp_bbVar_ibasho = new Bitboard(); ssss_bbBase_idosaki01_checker = new Bitboard(); ssss_bbBase_idosaki02_raionCatch = new Bitboard(); ssss_bbBase_idosaki03_nigeroTe = new Bitboard(); ssss_bbBase_idosaki04_try = new Bitboard(); ssss_bbBase_idosaki05_komaWoToruTe = new Bitboard(); ssss_bbBase_idosaki06_himodukiOteZasi = new Bitboard(); ssss_bbBase_idosaki07_suteOteZasi = new Bitboard(); ssss_bbBase_idosaki08_suteOteDa = new Bitboard(); ssss_bbBase_idosaki09_himodukiOteDa = new Bitboard(); ssss_bbBase_idosaki10_himodukiKanmanDa = new Bitboard(); ssss_bbBase_idosaki11_himodukiKanmanZasi = new Bitboard(); ssss_bbBase_idosaki12_bottiKanmanZasi = new Bitboard(); ssss_bbBase_idosaki13_bottiKanmanDa = new Bitboard(); ssss_bbBase_idosaki14_suteKanmanZasi = new Bitboard(); ssss_bbBase_idosaki15_suteKanmanDa = new Bitboard(); ssss_movePickerWoNuketaBasho1 = ""; for (int iFukasa = 0; iFukasa < PureMemory.MaxMoveDepth; iFukasa++) { ssss_moveList[iFukasa] = new MoveList(); ssss_moveListBad[iFukasa] = new MoveList(); } #endregion #region ムーブス mvs_ssAr = new Move[KIFU_SIZE]; #endregion #region 棋譜(コンピューター・プレイヤー同時に1つまで) kifu_syokiKyokumenFen = ""; kifu_toraretaKsAr = new Komasyurui[KIFU_SIZE]; kifu_moveArray = new Move[KIFU_SIZE]; kifu_moveTypeArray = new MoveType[KIFU_SIZE]; // 手番☆(^~^) kifu_tebanAr_ = new Taikyokusya[KIFU_SIZE]; kifu_aitebanAr_ = new Taikyokusya[KIFU_SIZE]; kifu_nTebanAr_ = new int[KIFU_SIZE]; kifu_nAitebanAr_ = new int[KIFU_SIZE]; // 初期局面手番を未設定にしておいて、ResetTebanArray( ) すれば、手番配列の初期値が入るぜ☆(^~^) kifu_syokikyokumenTeban = Taikyokusya.Yososu; ResetTebanArray(Taikyokusya.T1); // 配列等の初期化が終わったあとで、手目をリセット ClearTeme( //kifu_syokikyokumenTeban ); #endregion #region 現局面(棋譜カーソルが指している局面)(コンピューター・プレイヤー同時に1つまで) gky_kekka = TaikyokuKekka.Karappo; gky_ky = new Kyokumen(); gky_hyokati = new Hyokati(); Util_Control.UpdateRule( #if DEBUG "static PureMemory" #endif ); #endregion #region 探索(tnsk) tnsk_kohoMove = Move.Toryo; #endregion }
/// <summary> /// 評価値の表示。 /// 基本的に数字なんだが、数字の前に説明がつくことがあるぜ☆(^~^) /// 説明は各括弧で囲んであるぜ☆(^▽^) /// </summary> /// <param name="hyokati"></param> /// <param name="syuturyoku"></param> public static void Setumei(Hyokati hyokati, StringBuilder syuturyoku) { if (Conv_Hyokati.InSyokiti(hyokati)) { if (Option_Application.Optionlist.USI) { // USI syuturyoku.Append(((int)hyokati).ToString()); } else if (Hyokati.Syokiti_Alpha == hyokati) { syuturyoku.Append($"[α未設定] {(int)hyokati}"); } else if (Hyokati.Syokiti_Beta == hyokati) { syuturyoku.Append("[β未設定] {(int)hyokati}"); } else { throw new Exception("予期しない初期値だぜ☆(^~^)"); } return; } else if (Hyokati.TumeTesu_SeiNoSu_HyakuTeDume <= hyokati) { if (Hyokati.Sonota <= hyokati) { // その他☆(^~^) if (Option_Application.Optionlist.USI) { // USI syuturyoku.Append("0"); } else { switch (hyokati) { case Hyokati.Sonota_SyobuNasi: { syuturyoku.Append($"[SyobuNasi] {(int)hyokati}"); } break; default: { StringBuilder mojiretu1 = new StringBuilder(); mojiretu1.Append("[予期しない評価値だぜ☆(^~^) "); Conv_Hyokati.Setumei(hyokati, mojiretu1); mojiretu1.Append($"] {(int)hyokati}"); syuturyoku.AppendLine(mojiretu1.ToString()); throw new Exception(mojiretu1.ToString()); } } } } else { // 詰み手数が見えたときだぜ☆(^▽^) if (Option_Application.Optionlist.USI) { syuturyoku.Append("mate "); syuturyoku.Append(((int)(Hyokati.TumeTesu_SeiNoSu_ReiTeDume - (int)hyokati)).ToString()); } else { syuturyoku.Append("[katu "); syuturyoku.Append(((int)(Hyokati.TumeTesu_SeiNoSu_ReiTeDume - (int)hyokati)).ToString()); syuturyoku.Append("] "); syuturyoku.Append(((int)hyokati).ToString()); } } return; } else if (hyokati <= Hyokati.TumeTesu_FuNoSu_HyakuTeTumerare) { // 詰めを食らうぜ☆(>_<) if (Option_Application.Optionlist.USI) { syuturyoku.Append("mate "); syuturyoku.Append(((int)(Hyokati.TumeTesu_FuNoSu_ReiTeTumerare - (int)hyokati)).ToString()); } else { // 負数で出てくるのを、正の数に変換して表示するぜ☆(^▽^) syuturyoku.Append("[makeru "); syuturyoku.Append((-(int)(Hyokati.TumeTesu_FuNoSu_ReiTeTumerare - (int)hyokati)).ToString()); syuturyoku.Append("] "); syuturyoku.Append(((int)hyokati).ToString()); } return; } // 評価値☆ syuturyoku.Append("cp "); syuturyoku.Append(((int)hyokati).ToString());//enum型の名前が出ないように一旦int型に変換 }
/// <summary> /// 初期値なら、真だぜ☆(^▽^)説明用☆(^▽^) /// </summary> /// <param name="hyokati"></param> /// <returns></returns> public static bool InSyokiti(Hyokati hyokati) { return(Hyokati.Syokiti_Alpha == hyokati || Hyokati.Syokiti_Beta == hyokati); }
public void Increase(Option <Phase> optionalPhase, Hyokati henkaRyo) { this.KomawariHyokati_Sabun[OptionalPhase.IndexOf(optionalPhase)] += (int)henkaRyo; }
/// <summary> /// 評価値を更新するぜ☆(^▽^) /// </summary> /// <param name="erandaSasite">実際に選んだ指し手☆</param> /// <param name="erandaHyokati">実際に選んだ手の評価値☆</param> public static void Update(Move erandaSasite, Hyokati erandaHyokati, Kyokumen ky, StringBuilder syuturyoku) { JosekiKyokumen joKy_orNull = Option_Application.Joseki.GetKyokumen(Util_KikaiGakusyu.KaisiKyHash); if (null == joKy_orNull)// この局面の定跡データが入っていなければ、そもそも 学習できないぜ☆(^▽^) { return; } // 成績表を見て、現局面で最も勝率の高い指し手を、教師とするぜ☆(^~^) Move kyosiSs = Option_Application.Seiseki.GetSasite_Winest(ky, out float kyosiSyoritu_notUse); Hyokati kyosiHyokati; // 教師の手の評価値☆ if (Util_KikaiGakusyu.FirstAndHappaFens.ContainsKey(kyosiSs)) // 教師の手はあるはずだろ☆(^~^)? { // まず、一手指すぜ☆ Nanteme nanteme = new Nanteme(); ky.DoMove(Option_Application.Optionlist.USI, kyosiSs, MoveType.N00_Karappo, ref nanteme, ky.CurrentOptionalPhase, syuturyoku); // 評価値を調べようぜ☆(^▽^) Hyokati komawariHyokati = ky.Komawari.Get(ky.CurrentOptionalPhase); Hyokati nikomaHyokati = ky.Nikoma.Get(true); kyosiHyokati = (int)komawariHyokati + nikomaHyokati; // 一手戻そうぜ☆(^▽^) ky.UndoMove(Option_Application.Optionlist.USI, kyosiSs, syuturyoku); } else { return; } // 教師の手の評価値が、一番高いとは限らないぜ☆(^~^) if (!Conv_Hyokati.InHyokati(kyosiHyokati)) { // 教師の評価値が、メートの数字などになっている場合は、学習はできないぜ☆(>_<) return; } Kyokumen happaKy = new Kyokumen(); int caret_temp2; double sumSigmoidY = 0.0d;// 積分☆ // 深さが異なるので、自分の局面、相手の局面 の数も異なり、 // 足す局面と、引く局面の数が合わなくなるぜ☆(^~^) // ↓ // せっかく 1P、2P の評価値を持っているのだから、 // 1P から引いた分は 2P に足す、ということでどうか☆(^~^)? // では、今回の合法手を全て見ていくぜ☆(^~^) foreach (KeyValuePair <Move, List <string> > entry in Util_KikaiGakusyu.FirstAndHappaFens) { if (entry.Key == kyosiSs) { // 教師の手は、今回はスルーするぜ☆(^▽^) continue; } // さて、教師以外の手だが……☆(^~^) HyokatiUtiwake sonotanoTe_hyokatiUtiwake; // まず、一手指すぜ☆ Nanteme nanteme = new Nanteme(); ky.DoMove(Option_Application.Optionlist.USI, entry.Key, MoveType.N00_Karappo, ref nanteme, ky.CurrentOptionalPhase, syuturyoku); // 評価値を調べようぜ☆(^▽^) ky.Hyoka(out sonotanoTe_hyokatiUtiwake, HyokaRiyu.Yososu, true// ランダムな局面で学習したりもするし☆(^~^) ); // 一手戻そうぜ☆(^▽^) ky.UndoMove(Option_Application.Optionlist.USI, entry.Key, syuturyoku); if (!Conv_Hyokati.InHyokati(sonotanoTe_hyokatiUtiwake.EdaBest)) { // その他の手の評価値が、メートの数字などになっている場合は、学習はできないぜ☆(>_<) continue; } // 教師の手と、それ以外の手の 評価値の差を、 // シグモイドの x に当てはめて、y を求めるぜ☆ double sigmoidY = Option_Application.Optionlist.NikomaGakusyuKeisu * Util_Sigmoid.Sigmoid(erandaHyokati - kyosiHyokati); // 教師の手(=一番評価値が高い手)より 評価値が上回っている手は、 // すると、 0.5 < y < 1 となるな☆ // 下回っていれば、 // 0 < y < 0.5 となるな☆ var(exists1, phase1) = Util_Tansaku.StartingPhase.Match; var(exists2, phase2) = happaKy.CurrentOptionalPhase.Match; // この点数を、葉 から かき集めるぜ☆www(^▽^) foreach (string happaFen in entry.Value) { caret_temp2 = 0; happaKy.ParsePositionvalue(Option_Application.Optionlist.USI, happaFen, ref caret_temp2, false, false, out string moves, syuturyoku); // この局面の2駒関係を、シグモイドの y 点分、下げるぜ☆ sumSigmoidY += Util_NikomaKankei.DecrementParamerter_KikaiGakusyu( happaKy, (exists1 && exists2 && phase1 == phase2) ? -sigmoidY : sigmoidY//自分の手番なら 引く☆ ); } } // 下げてかき集めた シグモイドの y の量を、 // 教師の指し手の葉に 山分けするぜ☆(^▽^) double yamawake = sumSigmoidY / (double)Util_KikaiGakusyu.FirstAndHappaFens[kyosiSs].Count; foreach (string happaFen in Util_KikaiGakusyu.FirstAndHappaFens[kyosiSs])// 教師の手はあるはずだろ☆(^~^)? { caret_temp2 = 0; happaKy.ParsePositionvalue(Option_Application.Optionlist.USI, happaFen, ref caret_temp2, false, false, out string moves, syuturyoku); var(exists1, phase1) = Util_Tansaku.StartingPhase.Match; var(exists2, phase2) = happaKy.CurrentOptionalPhase.Match; // 各葉に 山分けだぜ☆(^~^) Util_NikomaKankei.IncrementParamerter_KikaiGakusyu( happaKy, (exists1 && exists2 && phase1 == phase2) ? -yamawake : yamawake//自分の手番なら 足すぜ☆ ); } }
/// <summary> /// 評価値の変域内なら真だぜ☆(^▽^) /// </summary> /// <returns></returns> public static bool InHyokati(Hyokati hyokati) { return(Hyokati.Hyokati_Saisyo <= hyokati && hyokati <= Hyokati.Hyokati_Saidai); }
/// <summary> /// 探索だぜ☆(^▽^) /// </summary> /// <param name="ky"></param> /// <param name="alpha"></param> /// <param name="fukasa">カウントダウン式の数字☆(^▽^) 反復深化探索の1週目の初期値は 1、2週目の初期値は 2 だぜ☆(^▽^) /// これがどんどんカウントダウンしていくぜ☆(^▽^) 0 で呼び出されたときは葉にしてすぐ処理を終われよ☆(^▽^)www</param> /// <param name="out_yomisujiToBack"></param> /// <param name="out_bestHyokatiAb1">手番から見た指し手の評価値だぜ☆(^~^)</param> /// <param name="out_edaBest_Komawari_JohoNoTame">内訳の目視確認用に使うだけの項目。</param> /// <param name="out_edaBest__Okimari_JohoNoTame">内訳の目視確認用に使うだけの項目。</param> /// <param name="out_edaBest_____Riyu_JohoNoTame">内訳の目視確認用に使うだけの項目。</param> /// <param name="dlgt_CreateJoho"></param> /// <returns></returns> private static void Tansaku_( out Move out_bestMove, out Hyokati out_bestHyokasu // 手番側の指し手の評価値だぜ☆(^~^) ) { Debug.Assert(0 <= PureMemory.tnsk_fukasa && PureMemory.tnsk_fukasa < PureMemory.ssss_moveList.Length, ""); out_bestMove = Move.Toryo; out_bestHyokasu = null; //──────────────────────────────────────── // 時間切れ判定 //──────────────────────────────────────── if (ComSettei.timeManager.IsTimeOver_TansakuChu()) { out_bestMove = Move.Toryo; out_bestHyokasu = new Hyokati( Conv_Hyokati.Hyokati_Rei, Conv_Tumesu.Stalemate, true // 今回の探索の結果は破棄するぜ☆(^~^) #if DEBUG , Conv_Hyokati.Hyokati_Rei , Conv_Hyokati.Hyokati_Rei , Conv_Hyokati.Hyokati_Rei , HyokaRiyu.JikanGire , "" #endif ); #if DEBUG Util_Tansaku.Snapshot("時間切れだぜ☆(^~^)", out_bestMove); #endif return; } //──────────────────────────────────────── // 葉 //──────────────────────────────────────── #region 葉 if ( // 深さ0 で呼び出されたときは、葉にしろということだぜ☆(^▽^)www PureMemory.tnsk_fukasa == 0 ) { // 深さ(根っこからの深さ)は 1 以上で始まるから、ループの1週目は、スルーされるはずだぜ☆(^▽^) // 1手指して 枝を伸ばしたとき、相手の手番の局面になっているな☆(^▽^)そのとき ここを通る可能性があるぜ☆ // // 末端局面で評価値を作らないぜ☆(^~^)! // 指し手を、指したときに作るんだぜ☆(^~^)! // PureMemory.tnsk_happaTeme = PureMemory.kifu_endTeme; // 「手目」カーソルは DoMove で1つ進んでいるはずなので、戻すんだぜ☆(^~^) out_bestMove = PureMemory.kifu_moveArray[PureMemory.kifu_endTeme - 1]; out_bestHyokasu = new Hyokati(PureMemory.gky_hyokati); // 葉で情報表示 Util_Joho.JohoMatome( PureMemory.tnsk_fukasa + 1, out_bestHyokasu, PureMemory.tnsk_hyoji #if DEBUG , out_bestHyokasu.dbg_riyu.ToString() #endif ); #if DEBUG Util_Tansaku.Snapshot("葉だぜ☆(^~^)", out_bestMove); #endif return;//枝を戻る(正常終了) } #endregion //──────────────────────────────────────── // 指し手生成 //──────────────────────────────────────── // グローバル変数 Util_MoveSeisei.Sslist に指し手がセットされるぜ☆(^▽^) MoveGenAccessor.DoMovePickerBegin(MoveType.N21_All); MovePicker01.MovePickerN01(MoveType.N21_All, true); #region ステイルメイト //──────────────────────────────────────── // ステイル・メイト //──────────────────────────────────────── if (PureMemory.ssss_moveList[PureMemory.tnsk_fukasa].listCount < 1) { // 詰んでるぜ☆(^~^) out_bestMove = Move.Toryo; out_bestHyokasu = new Hyokati( Conv_Hyokati.Hyokati_Rei, Conv_Tumesu.Stalemate, false #if DEBUG , Conv_Hyokati.Hyokati_Rei , Conv_Hyokati.Hyokati_Rei , Conv_Hyokati.Hyokati_Rei , HyokaRiyu.Stalemate , "" #endif ); // ステイルメイトで情報表示 Util_Joho.JohoMatome( PureMemory.tnsk_fukasa + 1,// 深さは 0 になっているので、Tansaku していない状態(=+1 して)に戻すぜ☆ out_bestHyokasu, PureMemory.tnsk_hyoji #if DEBUG , "Stalemate" #endif ); #if DEBUG Util_Tansaku.Snapshot("ステイルメイトだぜ☆(^~^)", out_bestMove); MoveSeiseiAccessor.DumpMoveSeisei(PureMemory.tnsk_hyoji); #endif return;//枝を戻る(正常終了) } #endregion for (int iSs = 0; iSs < PureMemory.ssss_moveList[PureMemory.tnsk_fukasa].listCount; iSs++) { // 枝☆ 適当にここらへんでカウントアップするかだぜ☆(^~^) PureMemory.tnsk_tyakusyuEdas++; //──────────────────────────────────────── // 指す //──────────────────────────────────────── //#if DEBUG // Util_Tansaku.Snapshot("ドゥ前", hyoji); //#endif Move ss_jibun = PureMemory.ssss_moveList[PureMemory.tnsk_fukasa].moveList[iSs]; MoveType ssType_jibun = PureMemory.ssss_moveList[PureMemory.tnsk_fukasa].moveTypeList[iSs]; if (DoMoveOpe.TryFailDoMoveAll( ss_jibun, ssType_jibun #if DEBUG , PureSettei.fenSyurui , (IDebugMojiretu)PureMemory.tnsk_hyoji , false , "TryFail_Tansaku_(1)" #endif )) { // 探索時にエラーが起こった場合は強制終了☆(^~^) throw new Exception(PureMemory.tnsk_hyoji.ToString()); } // 手番を進めるぜ☆(^~^) MoveGenAccessor.AddKifu( ss_jibun, ssType_jibun, PureMemory.dmv_ks_c); #if DEBUG Util_Tansaku.Snapshot("ドゥ後・探索前", out_bestMove); #endif Move ss_aite; //MoveType eda_moveType; // goto文で飛ぶと未割当になるので、ヌルでも入れておくぜ☆(^~^) Hyokati hyokasu_aiteToJibun = null; // この指し手が、駒を取った手かどうか☆ PureMemory.SetTnskHyoji(PureMemory.tnsk_hyoji); // 探索者がプラスでスタートして、 // 探索者の反対側はマイナスになり、 // 探索者の反対側の反対側はプラスに戻るぜ☆(^▽^) PureMemory.DecreaseTnskFukasa(); Tansaku_( out ss_aite, out hyokasu_aiteToJibun // 相手番の指し手の評価値が入ってくるぜ☆(^~^) ); PureMemory.IncreaseTnskFukasa(); //#if DEBUG // Util_Tansaku.Snapshot("探索後・アンドゥ前", hyoji); //#endif //──────────────────────────────────────── // 詰みを発見していれば、打ち切りフラグを立てるぜ☆(*^~^*) //──────────────────────────────────────── bool undoAndBreak = false; if (hyokasu_aiteToJibun.tumeSu == Conv_Tumesu.CatchRaion) { out_bestMove = ss_jibun; out_bestHyokasu = new Hyokati( Conv_Hyokati.Hyokati_Rei, Conv_Tumesu.CatchRaion,// この枝にこれるようなら、勝ち宣言だぜ☆(^▽^) false #if DEBUG , Conv_Hyokati.Hyokati_Rei , Conv_Hyokati.Hyokati_Rei , Conv_Hyokati.Hyokati_Rei , HyokaRiyu.TansakuRaionCatch , "" #endif ); // 打ち切りで情報表示 Util_Joho.JohoMatome( PureMemory.tnsk_fukasa, out_bestHyokasu, PureMemory.tnsk_hyoji #if DEBUG , "TansakuRaionCatch" #endif ); // 詰みではなく、らいおんきゃっち または トライかを 調べるぜ☆(^~^) // この手番は、 // この指し手を選べば、勝てるという理屈だが……☆ undoAndBreak = true; #if DEBUG Util_Tansaku.Snapshot("らいおんキャッチだぜ☆(^~^)", out_bestMove); #endif } // 探索で先の枝から戻ってきたときは、評価の符号を反転し、詰め手数のカウントもアップするぜ☆(^~^) hyokasu_aiteToJibun.CountUpTume(); hyokasu_aiteToJibun.ToHanten(); if (UndoMoveOpe.TryFailUndoMove( #if DEBUG PureSettei.fenSyurui , (IDebugMojiretu)PureMemory.tnsk_hyoji #endif )) { // 探索時にエラーが起こった場合は強制終了☆(^~^) throw new Exception(PureMemory.tnsk_hyoji.ToString()); } #if DEBUG Util_Tansaku.Snapshot("アンドゥ後", out_bestMove); #endif //──────────────────────────────────────── // これ以上 弟要素を探索するのを止め、枝を戻るかどうか☆(^~^) //──────────────────────────────────────── #region 打ち切り各種 if (undoAndBreak) { // (1)千日手の権利を相手に渡すために低点数付け<それ以降の手は読まない> // (2)らいおん を捕獲した // (3)トライ した #if DEBUG Util_Tansaku.Snapshot("アンドゥ後ブレイクだぜ☆(^~^)", out_bestMove); #endif break;//枝を戻る(正常終了) } #endregion //──────────────────────────────────────── // アップデート・枝ベスト //──────────────────────────────────────── #region アップデート・枝ベスト // 点数が付かないことがあって、その場合 ベスト指し手 を1度も選ばない // 「<=」にすると同点だったら、指し手のオーダリングの低いのを選ぶが☆(^~^) if (null == out_bestHyokasu) { out_bestMove = ss_jibun; out_bestHyokasu = hyokasu_aiteToJibun;// new HyokaSu(eda_hyokasu);//ここで新規作成 #if DEBUG Util_Tansaku.Snapshot("アップデート枝ベスト1回目だぜ☆(^~^)", out_bestMove); #endif } else if (out_bestHyokasu.hyokaTen < hyokasu_aiteToJibun.hyokaTen) { out_bestMove = ss_jibun; out_bestHyokasu.ToSet(hyokasu_aiteToJibun); // 兄弟の中で一番の読み筋だぜ☆(^▽^) // ↓ // TODO: ここで情報を表示したいが……☆(^~^) #if DEBUG Util_Tansaku.Snapshot("アップデート枝ベストだぜ☆(^~^)", out_bestMove); #endif } #endregion }//指し手ループ //; // このノードでの最大評価を返すんだぜ☆(^▽^) // ここでアルファを返してしまうと、アルファが1回も更新されなかったときに、このノードの最大評価ではないものを返してしまうので不具合になるぜ☆(^~^) if (null == out_bestHyokasu) { out_bestMove = Move.Toryo; out_bestHyokasu = new Hyokati( Conv_Hyokati.Hyokati_Rei, Conv_Tumesu.None, false #if DEBUG , Conv_Hyokati.Hyokati_Rei , Conv_Hyokati.Hyokati_Rei , Conv_Hyokati.Hyokati_Rei , HyokaRiyu.Fumei , "ループ抜け" #endif ); // ステイルメイトで情報表示 Util_Joho.JohoMatome( PureMemory.tnsk_fukasa, out_bestHyokasu, PureMemory.tnsk_hyoji #if DEBUG , "LoopOut" #endif ); #if DEBUG Util_Tansaku.Snapshot("評価の決まらない、ループ抜けだぜ☆(^~^)", out_bestMove); #endif return;//枝を戻る(正常終了) } }