/// <summary> /// 読み筋を返すぜ☆(^~^) /// </summary> /// <param name="sentoNantemade">初期局面からのリンクリストなので、どの「図はn手まで」戻すか☆</param> /// <returns></returns> public void ScanYomisuji(bool isSfen, int sentoNantemade, StringBuilder syuturyoku) { // 先頭(投了、初期局面、図は0手まで)まで戻るぜ☆ Nanteme nanteme = this; for (; null != nanteme.Ittemae; nanteme = nanteme.Ittemae) { } // 先頭から今までの読み筋をつなげるぜ☆(^▽^) int zuhaNantemade = 0; // 図はn手まで for (; null != nanteme;// 一番最後まで回すぜ☆(^▽^) nanteme = nanteme.Ittego) { if (sentoNantemade <= zuhaNantemade) { // 「図はn手まで」の数字 syuturyoku.Append($"({zuhaNantemade})"); ConvMove.AppendFenTo(isSfen, nanteme.Move, syuturyoku); syuturyoku.Append(" "); // おまけ syuturyoku.Append($"{AbstractConvMoveType.Setumei(nanteme.MoveType)} "); } zuhaNantemade++; } }
public static void Rnd(Kyokumen ky, StringBuilder syuturyoku) { int fukasa = 0; AbstractUtilMoveGen.GenerateMove01(fukasa, ky, MoveType.N21_All, true, syuturyoku);//グローバル変数に指し手がセットされるぜ☆(^▽^) if (AbstractUtilMoveGen.MoveList[fukasa].SslistCount < 1) { Nanteme nanteme = new Nanteme(); ky.DoMove(Option_Application.Optionlist.USI, Move.Toryo, MoveType.N00_Karappo, ref nanteme, ky.CurrentOptionalPhase, syuturyoku); } else { Move ss = AbstractUtilMoveGen.MoveList[fukasa].ListMove[Option_Application.Random.Next(AbstractUtilMoveGen.MoveList[fukasa].SslistCount)]; Nanteme nanteme = new Nanteme(); ky.DoMove(Option_Application.Optionlist.USI, ss, MoveType.N00_Karappo, ref nanteme, ky.CurrentOptionalPhase, syuturyoku); } }
/// <summary> /// 千日手の判定だぜ☆(^~^)反復した回数を返すぜ☆ /// 千日手になったら数えるのを止めるぜ☆ /// </summary> /// <returns></returns> public int GetSennititeCount() { ulong expected = this.SennititeHash; int count = 1;// 同じ局面が出た回数☆ for (Nanteme nanteme = this.Ittemae; null != nanteme; nanteme = nanteme.Ittemae) { if (nanteme.SennititeHash == expected) { count++; if (Const_Game.SENNITITE_COUNT <= count)// 千日手だぜ☆(^~^)数えるのを止めるぜ☆ { break; } } } return(count); }
/// <summary> /// 何手目かを数えるぜ☆(^~^) /// </summary> /// <returns></returns> public int ScanNantemadeBango() { int nantemeBango = 0; // 先頭には投了(初期局面)が入っているぜ☆(^▽^) // 先頭の一手前はヌルだぜ☆ // 先頭の投了(初期局面)まで戻るぜ☆ Nanteme nanteme = this; for (; null != nanteme.Ittemae; nanteme = nanteme.Ittemae) { nantemeBango++; } // 初期局面は 0 手目と表示される計算だぜ☆(^▽^) return(nantemeBango); }
/// <summary> /// 指定の手目まで進めるぜ☆(^~^) /// </summary> /// <param name="temeMade"></param> /// <param name="ky"></param> /// <param name="syuturyoku"></param> public void GoToTememade(bool isSfen, int temeMade, Kyokumen ky, StringBuilder syuturyoku) { // 棋譜を元に、局面データを再現するぜ☆ ky.Clear(); int caret = 0; ky.ParsePositionvalue(isSfen, SyokiKyokumenFen, ref caret, true//適用 , false, out string moves, syuturyoku ); // 指定の手目まで進めるぜ☆(^~^) foreach (Move ss in SsList) { if (temeMade < 1) { break; } Nanteme nanteme = new Nanteme(); ky.DoMove(isSfen, ss, MoveType.N00_Karappo, ref nanteme, ky.CurrentOptionalPhase, syuturyoku); temeMade--; } }
/// <summary> /// 終局図まで進めるぜ☆(^~^) /// </summary> /// <param name="ky"></param> /// <param name="syuturyoku"></param> public void GoToFinish(bool isSfen, Kyokumen ky, StringBuilder syuturyoku) { ky.Clear(); int caret = 0; ky.ParsePositionvalue(isSfen, SyokiKyokumenFen, ref caret, true//適用 , false, out string moves, syuturyoku ); // 棋譜を元に、局面データを再現するぜ☆ foreach (Move ss in SsList) { Nanteme nanteme = new Nanteme(); ky.DoMove(isSfen, ss, MoveType.N00_Karappo, ref nanteme, ky.CurrentOptionalPhase, syuturyoku); #if DEBUG //Util_Commands.Ky(isSfen, "ky", ky, syuturyoku); ////Logger.Flush(syuturyoku); //Logger.Flush_USI(syuturyoku); #endif } }
/// <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> /// <param name="nanteme"></param> public void CopyPropertyFrom(Nanteme nanteme) { }