/// <summary> /// 二駒関係を読込むぜ☆(^▽^) /// </summary> public static void Load_Nikoma(StringBuilder syuturyoku) { if (IsEnableBoardSize()) { syuturyoku.Append("二駒関係ファイル読込中"); { var msg = syuturyoku.ToString(); syuturyoku.Clear(); Logger.Flush(msg); } // ファイル名☆(^▽^) string file = $"_auto_nikoma{(Option_Application.Optionlist.SagareruHiyoko ? Logger.LocalRuleSagareruHiyoko : Logger.LocalRuleHonshogi)}.txt"; syuturyoku.Append("."); { var msg = syuturyoku.ToString(); syuturyoku.Clear(); Logger.Flush(msg); } if (File.Exists(file))//定跡ファイルがある場合のみ、定跡を使うぜ☆(^▽^) { Util_NikomaKankei.Parse(System.IO.File.ReadAllText(file)); } syuturyoku.AppendLine("☆"); { var msg = syuturyoku.ToString(); syuturyoku.Clear(); Logger.Flush(msg); } } }
/// <summary> /// 二駒関係を書き出すぜ☆(^▽^) /// </summary> public static void Flush_Nikoma(StringBuilder syuturyoku) { if (IsEnableBoardSize() && Util_NikomaKankei.Edited) { syuturyoku.Append("二駒関係ファイル書出中"); { var msg = syuturyoku.ToString(); syuturyoku.Clear(); Logger.Flush(msg); } // 容量がでかくなったので、複数のファイルに分割して保存するぜ☆(^▽^) // 残すべきファイル名☆(^▽^) string file = $"_auto_nikoma{(Option_Application.Optionlist.SagareruHiyoko ? Logger.LocalRuleSagareruHiyoko : Logger.LocalRuleHonshogi)}.txt"; if (!File.Exists(file)) { // ファイルが無ければ作成します。 FileStream fs = File.Create(file); fs.Close(); // File.Create したあとは、必ず Close() しないと、ロックがかかったままになる☆(^▽^) } syuturyoku.Append("."); { var msg = syuturyoku.ToString(); syuturyoku.Clear(); Logger.Flush(msg); } // 定跡の文字列化☆ StringBuilder nikomaMojiretu = new StringBuilder(); Util_NikomaKankei.ToString(nikomaMojiretu); syuturyoku.Append("."); { var msg = syuturyoku.ToString(); syuturyoku.Clear(); Logger.Flush(msg); } // 上書き☆ System.IO.File.WriteAllText(file, nikomaMojiretu.ToString()); syuturyoku.AppendLine("☆"); { var msg = syuturyoku.ToString(); syuturyoku.Clear(); Logger.Flush(msg); } Util_NikomaKankei.Edited = false; } }
/// <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> /// <param name="ky"></param> /// <param name="mk"></param> /// <param name="ninsyo"></param> public void HaneiMotiKoma(Kyokumen ky, MotiKoma mk) { if (DebugOptions.EvaluationHand) { // 駒の位置(評価関数の項目番号)☆ 持ち駒が 0 枚で、-1 の場合もあり☆ int koumokuNo = Util_NikomaKankei.GetKoumokuBango_MotiKoma(ky, mk); if (-1 != koumokuNo) { Util_NikomaKankei.MakeKoumokuBangoHairetu_Subete(ky, Util_NikomaKankei.KoumokuBangoHairetu1); Increase( Util_NikomaKankei.Kazoeru_NikomaKankeiHyokati_ItiTaiTa_SabunKosinYou(ky, koumokuNo, Util_NikomaKankei.KoumokuBangoHairetu1 ) ); } } }
/// <summary> /// 差分更新は、対局者1 の視点の盤で行えなんだぜ☆(^▽^) /// </summary> /// <param name="ky"></param> /// <param name="km"></param> /// <param name="ms"></param> /// <param name="fueta"></param> public void FuyasuBanjoKoma(Kyokumen ky, Koma km, Masu ms) { if (DebugOptions.AddPiecesOnBoard) { var optionalPiece = OptionalPiece.From(km); Debug.Assert(Conv_Koma.IsOk(optionalPiece), "");//空白とか禁止☆(^~^)! Util_NikomaKankei.MakeKoumokuBangoHairetu_Subete(ky, Util_NikomaKankei.KoumokuBangoHairetu1); Increase( Util_NikomaKankei.Kazoeru_NikomaKankeiHyokati_ItiTaiTa_SabunKosinYou(ky, Util_NikomaKankei.GetKoumokuBango_Banjo(ky, km, ms),// 駒の位置(評価関数の項目番号)をリストに入れておくぜ☆ Util_NikomaKankei.KoumokuBangoHairetu1 )); } }
public void KesuMotiKoma(Kyokumen ky, MotiKoma mk) { if (DebugOptions.ReduceHand) { // 駒の位置(評価関数の項目番号)☆ 持ち駒が 0 枚で、-1 の場合もあり☆ int koumokuNo = Util_NikomaKankei.GetKoumokuBango_MotiKoma(ky, mk); // Debug.Assert(koumokuNo != -1, $"mk=[{mk}]"); // 減点するぜ☆(^▽^) if (-1 != koumokuNo) { Util_NikomaKankei.MakeKoumokuBangoHairetu_Subete(ky, Util_NikomaKankei.KoumokuBangoHairetu1); Increase((Hyokati)( -(int)Util_NikomaKankei.Kazoeru_NikomaKankeiHyokati_ItiTaiTa_SabunKosinYou(ky, koumokuNo, Util_NikomaKankei.KoumokuBangoHairetu1)//評価値 )); } } }
/// <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//自分の手番なら 足すぜ☆ ); } }