예제 #1
0
        /// <summary>
        /// コンピューターの思考の開始だぜ☆(^▽^)
        /// ここが入り口だぜ☆(^~^)
        ///
        /// 最善手は yomisuji[0] に入っているぜ☆(^▽^)
        /// </summary>
        /// <returns></returns>
        public static bool TryFail_Go(StringBuilder hyoji)
        {
            tmp_bestHyokaSu.Clear();
            if (PureMemory.gky_ky.shogiban.yomiIbashoBan_yoko.IsEmpty(Med_Koma.KomasyuruiAndTaikyokusyaToKoma(Komasyurui.R, PureMemory.kifu_teban)))
            {
                // 自分のらいおんがいない局面の場合、投了☆
#if DEBUG
                PureMemory.tnsk_syuryoRiyu = TansakuSyuryoRiyu.JibunRaionInai;
                PureMemory.tnsk_kohoMove   = Move.Toryo;
                tmp_bestHyokaSu.tumeSu     = Conv_Tumesu.Stalemate;
#endif
            }
            else
            {
                //────────────────────────────────────────
                // 反復深化ループ☆(^~^)
                //────────────────────────────────────────
                Move currMove = Move.Toryo;
                tmp_currHyokaSu.Clear();
                for (HanpukuSinka.happaenoFukasa = 1;
                     // まだ思考に時間を使っていい
                     !ComSettei.timeManager.IsTimeOver_IterationDeeping()
                     ; HanpukuSinka.happaenoFukasa++)
                {
                    Debug.Assert(0 <= HanpukuSinka.happaenoFukasa && HanpukuSinka.happaenoFukasa < PureMemory.ssss_moveList.Length, "");

                    if (ComSettei.saidaiFukasa < HanpukuSinka.happaenoFukasa)
                    {
                        // 最大深さを超えた場合
                        Util_Joho.JohoMatome(
                            HanpukuSinka.happaenoFukasa,
                            tmp_bestHyokaSu,
                            hyoji
#if DEBUG
                            , "SaidaiFukasaGoe"
#endif
                            );
                        break;
                    }

                    // ここでは現在の局面に盤面を戻してあると思えだぜ☆(^~^)

                    Debug.Assert(1 <= HanpukuSinka.happaenoFukasa && HanpukuSinka.happaenoFukasa < PureMemory.ssss_moveList.Length, "");
                    ComSettei.SetSikoJikan_KonkaiNoTansaku();//思考時間(ランダム込み)を確定させるぜ☆(^~^)

                    PureMemory.SetTnskHyoji(hyoji);
                    //カウントダウン式の数字☆(^▽^) 反復深化探索の1週目は 1、2週目は 2 だぜ☆(^▽^)
                    PureMemory.SetTnskFukasa(HanpukuSinka.happaenoFukasa);
                    Tansaku_(
                        out currMove,
                        out tmp_currHyokaSu// 相手番の指し手の評価値が入ってくるぜ☆(^~^)
                        );

                    // TODO: 1手も読めていなければ、さっさと投了したいぜ☆(^~^)

                    if (tmp_currHyokaSu.isHaki)
                    {
                        // 時間切れ等の中途半端探索のとき☆
                        // この計算結果は、無視するぜ☆(^~^)

                        // ここに来るときは探索終了だぜ☆(^~^)
                        break;// 読みを終了しようなんだぜ☆
                    }
                    else
                    {
                        // 更新☆(^▽^)

                        PureMemory.tnsk_itibanFukaiNekkoKaranoFukasa_JohoNoTameni = HanpukuSinka.happaenoFukasa;
                        PureMemory.tnsk_kohoMove = currMove;
                        tmp_bestHyokaSu.ToSet(tmp_currHyokaSu);

                        if (Conv_Tumesu.CatchRaion == tmp_bestHyokaSu.tumeSu)
                        {
                            // 「0手詰められ」が返ってきているなら、負けました、をいう場面だぜ☆
#if DEBUG
                            PureMemory.tnsk_syuryoRiyu = TansakuSyuryoRiyu.Minus2TeTumerare;
#endif
                            break;// 読みを終了しようなんだぜ☆
                        }
                    }
                }//ループ

                // ストップウォッチ
                ComSettei.timeManager.stopwatch_Tansaku.Stop();
            }

            //────────────────────────────────────────
            // 詰め、詰められ
            //────────────────────────────────────────
            {
                Util_Taikyoku.Update(
                    tmp_bestHyokaSu,
                    PureMemory.kifu_teban
                    );
            }

            //────────────────────────────────────────
            // 指し手は決まった☆(^~^)
            // 指して、局面を進めておくぜ☆(^~^)
            //────────────────────────────────────────
            // 何これ
            if (DoMoveOpe.TryFailDoMoveAll(
                    PureMemory.tnsk_kohoMove,
                    MoveType.N00_Karappo
#if DEBUG
                    , PureSettei.fenSyurui
                    , (IDebugMojiretu)hyoji
                    , true//アサート抑制
                    , "TryFail_Go(1)"
#endif
                    ))
            {
                return(Pure.FailTrue("GenkyokuOpe.Try_DoMove(1)"));
            }
            // 手番を進めるぜ☆(^~^)
            MoveGenAccessor.AddKifu(PureMemory.tnsk_kohoMove, MoveType.N00_Karappo, PureMemory.dmv_ks_c);
#if DEBUG
            Util_Tansaku.Snapshot("Go(1)確定指し", PureMemory.tnsk_kohoMove);
#endif


            // 指し手が決まったときにも、強制情報表示
            {
                if (0 == PureMemory.tnsk_itibanFukaiNekkoKaranoFukasa_JohoNoTameni)
                {
#if DEBUG
                    hyoji.AppendLine($@"0手投了してないかだぜ☆?(^~^)
tansakuSyuryoRiyu=[{PureMemory.tnsk_syuryoRiyu}]
Option_Application.Optionlist.SaidaiFukasa=[{ComSettei.saidaiFukasa}]
Option_Application.Optionlist.SikoJikan_KonkaiNoTansaku=[{ComSettei.sikoJikan_KonkaiNoTansaku}]
Option_Application.Optionlist.SikoJikan=[{ComSettei.sikoJikan}]
Option_Application.Optionlist.SikoJikanRandom=[{ComSettei.sikoJikanRandom}]
");
                    return(Pure.FailTrue("0手投了"));
#endif
                }
            }

#if DEBUG
            hyoji.AppendLine(string.Format("bestMove: [{0}] ss={1}",
                                           PureMemory.tnsk_kaisiTeme,
                                           SpkMove.ToString_Fen(PureSettei.fenSyurui, PureMemory.tnsk_kohoMove)
                                           ));
#endif
            return(Pure.SUCCESSFUL_FALSE);
        }
예제 #2
0
        /// <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;//枝を戻る(正常終了)
            }
        }