Exemple #1
0
        /// <summary>
        /// データを追加するぜ☆(^▽^) 指しながら定跡を追加していくときだぜ☆
        /// </summary>
        /// <param name="ky_before"></param>
        public JosekiKyokumen AddMove(string kyFen_before, ulong kyHash_before, Option <Phase> optionalPhaseBeforeMove, Move bestMove, Hyokati hyokati, int fukasa, int version, StringBuilder syuturyoku)
        {
            JosekiKyokumen josekiKy = this.ParseKyokumenLine(kyFen_before, kyHash_before, optionalPhaseBeforeMove, syuturyoku);

            //#if DEBUG
            //            //────────────────────────────────────────
            //            // データを追加する前に
            //            //────────────────────────────────────────
            //            //
            //            // 指し手の整合性をチェックして、不正なデータを弾くことは必要だぜ☆(^▽^)
            //            //
            //            {
            //                Kyokumen ky2 = new KyokumenImpl();
            //                if(!ky2.ParseFen(kyFen_before, false))
            //                {
            //                    string msg = "パースに失敗だぜ☆(^~^)!";
            //                    Face_Application.MessageLine(msg);
            //                    Face_Application.Write();
            //                    throw new Exception(msg);
            //                }

            //                MoveError reason;
            //                if (!ky2.CanDoMove(bestMove, out reason))
            //                {
            //                    throw new Exception($"指せない指し手を定跡に登録しようとしたぜ☆(^~^)!:{ConvMove.Setumei(reason)}");
            //                }
            //            }

            //            // これから登録する指し手を、ログに書き出しておきたいぜ☆(^▽^)マージのとき、うるさい☆(^~^)
            //            {
            //                // 定跡登録
            //                //     fen .../.../.../ - 1
            //                //     B1A1 .....
            //                Util_Machine.AppendLine("定跡登録");
            //                Util_Machine.AppendLine($"    {kyFen_before}");
            //                Util_Machine.AppendLine($"    {ConvMove.ToFen(bestMove)}");
            //            }
            //#endif

            josekiKy.AddMove(bestMove, hyokati, fukasa, version);

            //#if DEBUG
            //            // 定跡を追加した直後にダンプして中身を目視確認だぜ☆(^~^)
            //            Util_Machine.AppendLine(
            //                    $@"定跡を追加した直後にダンプして中身を目視確認だぜ☆(^~^)
            //┌──────────┐
            //{this.ToString()}
            //└──────────┘
            //"
            //                );
            //            Logger.Flush();
            //#endif

            return(josekiKy);
        }
Exemple #2
0
        /// <summary>
        /// 定跡に登録されている指し手一覧。
        /// </summary>
        /// <param name="ky"></param>
        /// <returns></returns>
        public List <Move> GetMoves(Kyokumen ky)
        {
            List <Move> moves = new List <Move>();

            ulong hash = ky.KyokumenHash.Value;

            if (this.KyItems.ContainsKey(hash))
            {
                JosekiKyokumen josekyKy = this.KyItems[hash];

                foreach (KeyValuePair <Move, JosekiMove> entry in josekyKy.SsItems)
                {
                    moves.Add(entry.Key);
                }
            }
            return(moves);
        }
Exemple #3
0
        /// <summary>
        /// 局面データだけを追加するぜ☆(^▽^)
        /// ファイルを行単位にパースしているときに使う☆(^▽^)
        /// </summary>
        /// <param name="kyFen_before">指す前の局面の改造fen</param>
        /// <param name="kyHash_before">指す前の局面のハッシュ</param>
        /// <param name="kyTb_before">指す前の局面の手番</param>
        /// <returns></returns>
        public JosekiKyokumen ParseKyokumenLine(string kyFen_before, ulong kyHash_before, Option <Phase> optionalPhaseBeforeMove, StringBuilder syuturyoku)
        {
            JosekiKyokumen josekiKy;

            if (this.KyItems.ContainsKey(kyHash_before))
            {
                // 既存☆
                josekiKy = this.KyItems[kyHash_before];
            }
            else
            {
                // 新規☆

                /*
                 #if DEBUG
                 * {
                 *  Kyokumen ky2 = new KyokumenImpl();
                 *  int caret = 0;
                 *  ky2.ParseFen(kyFen_before, ref caret, false, syuturyoku);
                 *  ulong newHash = ky2.CreateKyokumenHash();
                 *  if (newHash != kyHash_before)
                 *  {
                 *      StringBuilder reigai = new StringBuilder();
                 *      reigai.Append("局面ハッシュが異なるぜ☆(^~^)! kyFen_before=[");
                 *      reigai.Append(kyFen_before);
                 *      reigai.Append("] newHash=[");
                 *      reigai.Append(newHash.ToString());
                 *      reigai.Append("] kyHash_before=[");
                 *      reigai.Append(kyHash_before.ToString());
                 *      reigai.Append("]");
                 *      syuturyoku.AppendLine(reigai.ToString());
                 *      Logger.Flush(syuturyoku);
                 *      throw new Exception(reigai.ToString());
                 *  }
                 * }
                 #endif
                 */

                josekiKy = new JosekiKyokumen(kyFen_before, optionalPhaseBeforeMove, this);
                this.KyItems.Add(kyHash_before, josekiKy);
                this.Edited = true;
            }

            return(josekiKy);
        }
Exemple #4
0
        /// <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//自分の手番なら 足すぜ☆
                    );
            }
        }
Exemple #5
0
        /// <summary>
        /// 定跡局面の中で、評価値が一番高い指し手を返すぜ☆(^▽^)
        /// </summary>
        /// <param name="ky"></param>
        /// <returns>なければ投了☆</returns>
        public Move GetMove(bool isSfen, Kyokumen ky, out Hyokati out_bestHyokati, StringBuilder syuturyoku
#if DEBUG
                            , out string fen_forTest
#endif
                            )
        {
            Move bestMove = Move.Toryo;

            out_bestHyokati = Hyokati.TumeTesu_GohosyuNasi;
            int bestFukasa = 0;

#if DEBUG
            fen_forTest = "";
#endif

            //Util_Machine.Assert_KyokumenSeigosei_SabunKosin("ゲット指し手 #鯨",true);
            ulong hash = ky.KyokumenHash.Value;
            if (this.KyItems.ContainsKey(hash))
            {
                JosekiKyokumen josekyKy = this.KyItems[hash];
                // 整合性の確認用だぜ☆(^~^)
#if DEBUG
                fen_forTest = josekyKy.Fen;
#endif
                foreach (KeyValuePair <Move, JosekiMove> entry in josekyKy.SsItems)
                {
                    if (out_bestHyokati < entry.Value.Hyokati)// 評価値が高い指し手を選ぶぜ☆(^▽^)
                    {
                        bestMove        = entry.Key;
                        out_bestHyokati = entry.Value.Hyokati;
                        bestFukasa      = entry.Value.Fukasa;
                    }
                    else if (out_bestHyokati == entry.Value.Hyokati && //評価値が同じ場合は、
                             bestFukasa < entry.Value.Fukasa           //深く読んでいる指し手を選ぶぜ☆(^▽^)
                             )
                    {
                        bestMove        = entry.Key;
                        out_bestHyokati = entry.Value.Hyokati;
                        bestFukasa      = entry.Value.Fukasa;
                    }
                }
            }

#if DEBUG
            // 指し手の整合性をチェックしておきたいぜ☆(^▽^)
            {
                Kyokumen      ky_forAssert = new Kyokumen();
                int           caret        = 0;
                StringBuilder sindan1      = new StringBuilder();
                ky.AppendFenTo(Option_Application.Optionlist.USI, sindan1);
                //if (!ky2.ParseFen(sindan1.ToString(), ref caret, false, syuturyoku))
                if (!ky_forAssert.ParsePositionvalue(isSfen, sindan1.ToString(), ref caret, 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 sindan2 = new StringBuilder();
                    sindan2.Append("取得: 指せない指し手を定跡から取り出そうとしたぜ☆(^~^)!:");
                    // sindan2.Append("理由:"); ConvMove.SetumeiLine(riyu,sindan2);
                    sindan2.Append("指し手:"); ConvMove.SetumeiLine(isSfen, bestMove, sindan2);
                    sindan2.Append("定跡局面 ("); ky_forAssert.AppendFenTo(Option_Application.Optionlist.USI, sindan2); sindan2.AppendLine(")");
                    Util_Information.Setumei_Lines_Kyokumen(ky_forAssert, sindan2);

                    //str2.AppendLine("以下、定跡メモリのダンプ");
                    //str2.AppendLine("┌──────────┐");
                    //str2.Append(this.ToString());
                    //str2.AppendLine("└──────────┘");

                    syuturyoku.AppendLine(sindan2.ToString());
                    var msg = syuturyoku.ToString();
                    syuturyoku.Clear();
                    Logger.Flush(msg);
                    throw new Exception(sindan2.ToString());
                }
            }
#endif

            return(bestMove);
        }
Exemple #6
0
        /// <summary>
        /// 定跡ファイルの解析☆(^~^)
        /// </summary>
        /// <param name="lines"></param>
        public void Parse(bool isSfen, string[] lines, StringBuilder syuturyoku)
        {
            this.Clear();
            Kyokumen       ky_forJoseki = new Kyokumen();//使いまわすぜ☆(^▽^)
            JosekiKyokumen josekiKy     = null;
            JosekiMove     josekiSs;
            Match          m;
            string         commandline;

            for (int iGyoBango = 0; iGyoBango < lines.Length; iGyoBango++)
            {
                commandline = lines[iGyoBango];

                if (commandline.Length < 1)
                {
                    // 空行は無視☆
                    // 半角空白とか、全角空白とか、タブとか 入れてるやつは考慮しないぜ☆(^~^)!
                }
                else if ('f' == commandline[0])// fen で始まれば局面データ☆(^▽^)// caret == commandline.IndexOf("fen ", caret)
                {
                    // キャレットは進めずに続行だぜ☆(^▽^)
                    m = Itiran_FenParser.GetJosekiKyPattern(Option_Application.Optionlist.USI).Match(commandline);//, caret
                    if (!m.Success)
                    {
                        StringBuilder reigai1 = new StringBuilder();
                        reigai1.AppendLine($@"パースに失敗だぜ☆(^~^)! #寿 定跡ファイル解析失敗
commandline=[{ commandline }]");
#if DEBUG
                        reigai1.Append(" [");
                        reigai1.Append(iGyoBango.ToString());
                        reigai1.Append("]行目");
#endif
                        syuturyoku.AppendLine(reigai1.ToString());
                        var msg = syuturyoku.ToString();
                        Logger.Flush(msg);
                        syuturyoku.Clear();
                        throw new Exception(msg);
                    }

                    // .Value は、該当しないときは空文字列か☆
                    // .Value は、該当しないときは空文字列か☆
                    if (Itiran_FenParser.STARTPOS_LABEL == m.Groups[1].Value)
                    {
                        DanStrings = Itiran_FenParser.GetStartpos(Option_Application.Optionlist.USI).Split('/');
                    }
                    else
                    {
                        DanStrings = m.Groups[1].Value.Split('/');   // N段目
                    }


                    ky_forJoseki.SetNaiyo(
                        isSfen,
                        true,              //適用
                        false,
                        Joseki.DanStrings, //1~N 段目
                        m.Groups[2].Value,
                        m.Groups[3].Value, //手番
                        syuturyoku
                        );

                    /*
                     #if DEBUG
                     * {
                     * Kyokumen ky3 = new KyokumenImpl();
                     * int caret = 0;
                     * ky3.ParseFen(commandline, ref caret, false, syuturyoku);
                     * ulong newHash = ky3.CreateKyokumenHash();
                     * if (newHash != ky2.KyokumenHash)
                     * {
                     *  StringBuilder reigai1 = new StringBuilder();
                     *  reigai1.Append("局面ハッシュが異なるぜ☆(^~^)! commandline=[");
                     *  reigai1.Append(commandline);
                     *  reigai1.Append("] ky3.AppendFenTo=[");
                     *  ky3.AppendFenTo(reigai1);
                     *  reigai1.Append("] dan1[");
                     *  reigai1.Append(JosekiImpl.DanStrings[0]);
                     *  reigai1.Append("] dan2[");
                     *  reigai1.Append(JosekiImpl.DanStrings[1]);
                     *  reigai1.Append("] dan3[");
                     *  reigai1.Append(JosekiImpl.DanStrings[2]);
                     *  reigai1.Append("] dan4[");
                     *  reigai1.Append(JosekiImpl.DanStrings[3]);
                     *  reigai1.Append("] newHash=[");
                     *  reigai1.Append(newHash.ToString());
                     *  reigai1.Append("] ky2.KyokumenHash=[");
                     *  reigai1.Append(ky2.KyokumenHash.ToString());
                     *  reigai1.Append("]");
                     *  syuturyoku.AppendLine(reigai1.ToString());
                     *  Logger.Flush(syuturyoku);
                     *  throw new Exception(reigai1.ToString());
                     * }
                     * }
                     #endif
                     */

                    josekiKy = this.ParseKyokumenLine(commandline, ky_forJoseki.KyokumenHash.Value, ky_forJoseki.CurrentOptionalPhase, syuturyoku);
                }
                else
                {
                    // それ以外は手筋☆(^▽^)
                    if (null == josekiKy)
                    {
                        throw new Exception("定跡ファイル解析失敗 定跡局面の指定なし☆");
                    }

                    // 指し手、指し手、数字、数字、数字 と並んでいるぜ☆(^▽^)
                    m = Itiran_FenParser.GetJosekiSsPattern(Option_Application.Optionlist.USI).Match(commandline);
                    if (!m.Success)
                    {
                        //*
                        // FIXME:
                        syuturyoku.AppendLine($"パースに失敗だぜ☆(^~^)! #鮪 commandline=[{ commandline }]");
                        var msg = syuturyoku.ToString();
                        syuturyoku.Clear();
                        Logger.Flush(msg);
                        throw new Exception(msg);
                        // */
                    }

                    // 高速化のために、ローカル変数を減らして、詰め込んだコードにしているぜ☆(>_<)

                    // 第1引数 B1C1 や toryo のような指し手の解析。
                    josekiSs = new JosekiMove(
                        // 1列目:指し手☆ (1:グループ,2:指し手全体,3~7:指し手各部,8:投了)
                        m.Groups[8].Success ? Move.Toryo : // "toryo" が入っている場合☆
                        Med_Parser.TryFenMove2(Option_Application.Optionlist.USI,
                                               ky_forJoseki.Sindan,
                                               m.Groups[3].Value,
                                               m.Groups[4].Value,
                                               m.Groups[5].Value,
                                               m.Groups[6].Value,
                                               m.Groups[7].Value
                                               ),

                        // 2列目:応手☆ none とか。(9:グループ,10:none,11:指し手全体,12~16:指し手各部,17:投了)
                        m.Groups[10].Success || m.Groups[17].Success ? Move.Toryo :// [10]"none" または[17]"toryo" が入っている場合☆ FIXME: none と toryo を区別してないぜ☆(^~^)
                        Med_Parser.TryFenMove2(Option_Application.Optionlist.USI,
                                               ky_forJoseki.Sindan,
                                               m.Groups[12].Value,
                                               m.Groups[13].Value,
                                               m.Groups[14].Value,
                                               m.Groups[15].Value,
                                               m.Groups[16].Value
                                               ),

                        (Hyokati)int.Parse(m.Groups[18].Value), //hyokati (18) 解析はokなはず☆
                        int.Parse(m.Groups[19].Value),          //fukasa (19) 解析はokなはず☆
                        int.Parse(m.Groups[20].Value),          //version (20) 解析はokなはず☆(旧版ではバージョンは無いこともある☆)
                        josekiKy
                        );


                    // 定跡ファイルの局面には、重複指し手データがないようにしてくれだぜ☆(^~^)チェックは省くぜ☆

                    /*
                     * if (josekiKy.SsItems.ContainsKey(josekiSs.Move))
                     * {
                     *      // FIXME:
                     *      String2 str = new String2Impl();
                     *      str.Append("局面データに重複の指し手があるぜ☆(^~^)! 局面=[");
                     *      str.Append(josekiKy.Fen);
                     *      str.Append("] 指し手=[");
                     *      ConvMove.Setumei(josekiSs.Move,str);
                     *      str.Append("]");
                     *      Util_Machine.AppendLine(str.ToString());
                     *      Logger.Flush();
                     *      throw new Exception(str.ToString());
                     * }
                     * else
                     * {
                     * // */
                    // 新規

                    //#if DEBUG
                    //                // 指し手の整合性をチェックしておきたいぜ☆(^▽^)
                    //                {
                    //                    Kyokumen ky2 = new KyokumenImpl();
                    //                    if (!ky2.ParseFen(ky.ToFen(), false))
                    //                    {
                    //                        string msg = "新規: パースに失敗だぜ☆(^~^)!";
                    //                        Face_Application.MessageLine(msg);
                    //                        Face_Application.Write();
                    //                        throw new Exception(msg);
                    //                    }

                    //                    Move bestMove;
                    //                    int caret_test = 0;
                    //                    ConvMove.TryParse(commandline, ref caret_test, ky2, out bestMove);

                    //                    MoveError reason;
                    //                    if (!ky2.CanDoMove( bestMove, out reason))
                    //                    {
                    //                        throw new Exception($"新規: 指せない指し手を定跡に登録しようとしたぜ☆(^~^)!:{ConvMove.Setumei(reason)}");
                    //                    }
                    //                }
                    //#endif

                    josekiKy.SsItems.Add(josekiSs.Move, josekiSs);
                    this.Edited = true;
                    //}
                }
            }
        }
Exemple #7
0
 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;
 }