public static void Undo(string commandline, Kyokumen ky, StringBuilder syuturyoku) { // うしろに続く文字は☆(^▽^) int caret = 0; Util_String.TobasuTangoToMatubiKuhaku(commandline, ref caret, "undo "); if (!Med_Parser.TryFenMove(Option_Application.Optionlist.USI, commandline, ref caret, ky.Sindan, out Move ss)) { throw new Exception($"パースエラー [{ commandline }]"); } ky.UndoMove(Option_Application.Optionlist.USI, ss, syuturyoku); // このムーブには取った駒は含まれないのでは。 }
/// <summary> /// 終局後に棋譜を作る場合☆(^~^)感想戦用だぜ☆(^▽^) /// /// ・成績 /// /// の作成も混ざっている☆(^~^) /// </summary> public static void TukuruKifu(bool isSfen, Kyokumen ky, StringBuilder syuturyoku) { // 指した後の手☆(成績 登録用) Move ss_after = Move.Toryo; // 未使用時の初期値 // 決着から初期局面まで、逆順で戻しながら棋譜を記録するぜ☆(^▽^) int fukasa = 0; while (null != ky.Konoteme.Ittemae) //アンドゥできなくなるまで戻すぜ☆(^▽^) { ss_after = ky.Konoteme.Move; // アンドゥする前に指し手を残しておくぜ☆(^▽^) Option_Application.Kifu.AddFirst(ss_after); ky.UndoMove(isSfen, ss_after, syuturyoku); // 指し手を頼りにアンドゥするぜ☆(^▽^) Util_Application.InLoop_SeisekiKosin(ss_after, ky, syuturyoku); // 成績更新☆(^▽^) fukasa++; } }
/// <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//自分の手番なら 足すぜ☆ ); } }