/// <summary>
        /// コンピューターの動きを作ります。
        ///
        /// Gnugo1.2 では genmove関数。
        /// </summary>
        /// <param name="out_bestMove">コンピューターが選んだ、一番いい石の置き場所</param>
        /// <param name="taikyoku"></param>
        public static void Generate_BestMove
        (
            out GobanPoint out_bestMove,
            Taikyoku taikyoku
        )
        {
            int bestScore; // Gnugo1.2 では val変数。評価値。
            int try_ = 0;  // トライの数

            // ムーブと評価値を初期化します。
            out_bestMove = new GobanPointImpl(-1, -1);
            bestScore    = -1;

            // カレント色の石(または連)のリバティー(四方の石を置けるところ)
            //
            // Gnugo1.2 では、l という名前のグローバル変数。liberty の略だろうか?
            // eval で内容が設定され、その内容は exambord、findsavr、findwinr、suicideで使用されます。
            int[,] libertyOfNodes;

            // 相手(人間)の呼吸点の数 を再び数えます。
            Util_LibertyAtNode.CountAll(out libertyOfNodes, taikyoku.YourColor, taikyoku);

            // 相手のピースを取ったり、攻めたりする手を探します。
            {
                GobanPoint foundLocation; // Gnugo1.2 では、 ti, tj という変数名。
                int        foundScore;    // Gnugo1.2 では tval変数。試して算出した評価値。

                if (Util_FindWinner.FindBestLocation(out foundLocation, out foundScore, libertyOfNodes, taikyoku))
                {
                    if (bestScore < foundScore) // 新しい最善手を見つけたなら
                    {
                        bestScore = foundScore; // 最善の評価値と置き場所を、更新します。
                        out_bestMove.SetLocation(foundLocation);
                    }
                }
            }

            // もし脅かされていれば、幾つかのピースを守ります。
            {
                GobanPoint foundLocation; // Gnugo1.2 では、 ti, tj という変数名。
                int        foundScore;    // Gnugo1.2 では tval変数。試して算出した評価値。

                if (Util_SasiteSaver.FindLocation_LibertyWeak(out foundLocation, out foundScore, libertyOfNodes, taikyoku))
                {
                    if (bestScore < foundScore) // 新しい最善手を見つけたなら
                    {
                        bestScore = foundScore; // 最善の評価値と置き場所を、更新します。
                        out_bestMove.SetLocation(foundLocation);
                    }
                }
            }

            // 新しい動きのためのローカル・プレー・パターンに一致するか試します。
            {
                GobanPoint foundLocation; // Gnugo1.2 では、 ti, tj という変数名。
                int        foundScore;    // Gnugo1.2 では tval変数。試して算出した評価値。

                if (Util_FindOpeningZyoseki.FindPattern(out foundLocation, out foundScore, taikyoku))
                {
                    if (bestScore < foundScore) // 新しい最善手を見つけたなら
                    {
                        bestScore = foundScore; // 最善の評価値と置き場所を、更新します。
                        out_bestMove.SetLocation(foundLocation);
                    }
                }
            }

            // いい手が無ければ、ランダムに打ちます。
            if (bestScore < 0)
            {
                int count_libertyOfPiece;// Gnugo1.2 では、静的グローバル変数 lib でした。

                // くり返し。
                do
                {
                    // 行は 盤幅でランダム。
                    out_bestMove.I = taikyoku.Random.Next() % taikyoku.GobanBounds.BoardSize;

                    // 低いラインを避ける、中央の領域
                    if
                    (
                        out_bestMove.OutOfI(2, 16)    //0〜1行、または 17〜18行だ。
                        ||
                        out_bestMove.ContainsI(6, 12) //6〜12行のどこかにある。
                    )
                    {
                        // 振りなおし
                        out_bestMove.I = taikyoku.Random.Next() % taikyoku.GobanBounds.BoardSize;
                        if (out_bestMove.OutOfI(2, 16))//0〜1行、または 17〜18行だ。
                        {
                            // 振りなおし
                            out_bestMove.I = taikyoku.Random.Next() % taikyoku.GobanBounds.BoardSize;
                        }
                    }

                    // 列は 盤幅 でランダム。
                    out_bestMove.J = taikyoku.Random.Next() % taikyoku.GobanBounds.BoardSize;

                    // 低いラインを避ける、中央の領域
                    if
                    (
                        out_bestMove.OutOfJ(2, 16)    //0〜1列、または 17〜18列だ。
                        ||                            // または、
                        out_bestMove.ContainsJ(6, 12) //6〜12列のどこかにある。
                    )
                    {
                        // 振りなおし
                        out_bestMove.J = taikyoku.Random.Next() % taikyoku.GobanBounds.BoardSize;

                        if (out_bestMove.OutOfJ(2, 16))//0〜1列、または 17〜18列だ。
                        {
                            // 振りなおし
                            out_bestMove.J = taikyoku.Random.Next() % taikyoku.GobanBounds.BoardSize;
                        }
                    }

                    // リバティーを数えなおし。
                    Util_CountLiberty.Count(out count_libertyOfPiece, out_bestMove, taikyoku.MyColor, taikyoku);
                    ++try_;
                }while
                (
                    try_ < MAXTRY // まだ次もトライできます。
                    &&
                    (
                        // 次の3つの条件のどれかを満たすようなら、再トライします。
                        // (1)ベストムーブか空っぽだ。非合法手かも。
                        // (2)ピースのリバティーが 0〜1 しかない。
                        taikyoku.Goban.At(out_bestMove) != StoneColor.Empty
                        ||
                        count_libertyOfPiece < 2
                        ||
                        // (3)自分の目を埋める手なら。
                        Util_OwnEye.IsThis(out_bestMove, taikyoku)
                    )
                );
            }

            if (MAXTRY <= try_)  // 最大試行回数を超えていたら、コンピューターはパス。
            {
                taikyoku.Pass++;

                //----------------------------------------
                // コンピューターの指し手を表示します。
                //----------------------------------------
                Console.WriteLine("I pass.");
                out_bestMove.SetPass();
            }
            else   // 妥当な指し手を指します。
            {
                taikyoku.Pass = 0;

                //----------------------------------------
                // コンピューターの指し手を表示します。
                //----------------------------------------
                Console.Write("my move: ");
                // 座標の列番号を、アスキー文字コードに変換します。
                char a;
                if (out_bestMove.J < 8)
                {
                    a = (char)(out_bestMove.J + 65);
                }
                else
                {
                    a = (char)(out_bestMove.J + 66);
                }
                Console.Write(a);

                int ii; // Gnugo1.2 では、行i を反転させた変数名が ii。
                ii = taikyoku.GobanBounds.BoardSize - out_bestMove.I;
                if (ii < 10)
                {
                    Console.WriteLine("{0,1}", ii);
                }
                else
                {
                    Console.WriteLine("{0,2}", ii);
                }
            }
        }
Esempio n. 2
0
        /// <summary>
        /// 弱っている石を助ける手を探します。
        /// 助けるというのは、(襲われそうな)自分の石の 横にツケることです。
        ///
        /// 位置m,nを含むグループから、
        /// 上下左右に隣接する石(または連)の呼吸点を調べ、
        /// 最もスコアの高い石(または連)の場所 i,j と、評価値を探します。(連の場合、どこか1つの石の場所)
        ///
        /// Gnugo1.2 では findnextmove 関数。
        /// </summary>
        /// <param name="out_bestLocation">次の動きの   行、列番号</param>
        /// <param name="out_bestScore">Gnugo1.2では val という名前のポインター変数。次の指し手の評価値</param>
        /// <param name="myStone_location">(脅かされているかもしれない)コンピューターの石の 行番号 m、列番号 n</param>
        /// <param name="currentLiberty">現在のリバティーの数。1〜3を、脅かされていると考えます。Gnugo1.2 では minlib 変数。</param>
        /// <param name="taikyoku"></param>
        /// <returns></returns>
        public static bool FindStone_LibertyWeak
        (
            out GobanPoint out_bestLocation,
            out int out_bestScore,
            GobanPoint myStone_location,
            int currentLiberty,
            Taikyoku taikyoku
        )
        {
            out_bestLocation = new GobanPointImpl(-1, -1);
            out_bestScore    = -1;

            // カレント位置をマークします。
            taikyoku.MarkingBoard.Done_Current(myStone_location);

            //
            // 東西南北のどこかに 空きスペース (がないと助けられません)があるはずです。
            //

            //--------------------------------------------------------------------------
            // 北隣を調べます。
            {
                GobanPoint tryLocation = new GobanPointImpl(0, 0); // Gnugo1.2 では ti,tj という変数名。// 初期値は 2015-11-26 追加
                int        tryScore    = 0;                        // Gnugo1.2 では tval 変数。 隣位置の評価値。    // 2015-11-26 追加 0 で初期化。
                bool       found       = false;

                if (!myStone_location.IsNorthEnd()) // 北端でない石のみ。
                {
                    if (taikyoku.Goban.NorthOf(myStone_location) == StoneColor.Empty)
                    {
                        // わたしの石の北隣にある空きスペースの位置。
                        tryLocation.SetLocation(myStone_location.ToNorth());

                        // 空きスペースに石を置いたと考えて、石を置いた局面のその自分の石(または連)の呼吸点を数えます。
                        int futureLiberty; // Gnugo1.2 では、グローバル変数 lib = 0 でした。
                        Util_CountLiberty.Count(out futureLiberty, tryLocation, taikyoku.MyColor, taikyoku);

                        // 評価値計算
                        tryScore = Util_SasiteNext.Evaluate_LibertyWeak(futureLiberty, currentLiberty);

                        found = true;
                    }
                    else if
                    (
                        taikyoku.Goban.NorthOf(myStone_location) == taikyoku.MyColor // 北隣がコンピューターの石で、
                        &&
                        taikyoku.MarkingBoard.CanDo_North(myStone_location)          // 北隣のマーキングが 0 なら
                    )
                    {
                        if (Util_SasiteNext.FindStone_LibertyWeak(out tryLocation, out tryScore, myStone_location.ToNorth(), currentLiberty, taikyoku))    // 再帰的に検索
                        {
                            found = true;
                        }
                    }
                }

                if (found)  // 見つかったら1
                {
                    found = false;
                    if (out_bestScore < tryScore && !Util_OwnEye.IsThis(tryLocation, taikyoku))
                    {
                        out_bestScore = tryScore;                  // 高い方の評価値を残している?
                        out_bestLocation.SetLocation(tryLocation); // 高い方の交点i,jを残している?
                    }
                }
            }

            //--------------------------------------------------------------------------
            // 南ネイバーを調べます。
            {
                GobanPoint tryLocation = new GobanPointImpl(0, 0); // Gnugo1.2 では ti,tj という変数名。// 初期値は 2015-11-26 追加
                int        tryScore    = 0;                        // Gnugo1.2 では tval 変数。 隣位置の評価値。    // 2015-11-26 追加 0 で初期化。
                bool       found       = false;

                if (!myStone_location.IsSouthEnd(taikyoku.GobanBounds))    // 南端でなければ。
                {
                    if (taikyoku.Goban.SouthOf(myStone_location) == StoneColor.Empty)
                    {
                        // 南隣の石(または連)の呼吸点の数を調べ、
                        // 期待する呼吸点の数より 大きいほど高い評価値を付けます。
                        tryLocation.SetLocation(myStone_location.ToSouth());

                        int futureLiberty; // Gnugo1.2 では、グローバル変数 lib = 0 でした。
                        Util_CountLiberty.Count(out futureLiberty, tryLocation, taikyoku.MyColor, taikyoku);
                        tryScore = Util_SasiteNext.Evaluate_LibertyWeak(futureLiberty, currentLiberty);
                        found    = true;
                    }
                    else if
                    (
                        taikyoku.Goban.SouthOf(myStone_location) == taikyoku.MyColor
                        &&
                        taikyoku.MarkingBoard.CanDo_South(myStone_location) // 南側
                    )
                    {
                        if (Util_SasiteNext.FindStone_LibertyWeak(out tryLocation, out tryScore, myStone_location.ToSouth(), currentLiberty, taikyoku))
                        {
                            found = true;
                        }
                    }
                }

                if (found)  // 見つかったら1
                {
                    found = false;
                    if (out_bestScore < tryScore && !Util_OwnEye.IsThis(tryLocation, taikyoku))
                    {
                        out_bestScore = tryScore;
                        out_bestLocation.SetLocation(tryLocation);
                    }
                }
            }

            //--------------------------------------------------------------------------
            // 西ネイバーを調べます。
            {
                GobanPoint tryLocation = new GobanPointImpl(0, 0); // Gnugo1.2 では ti,tj という変数名。// 初期値は 2015-11-26 追加
                int        tryScore    = 0;                        // Gnugo1.2 では tval 変数。 隣位置の評価値。    // 2015-11-26 追加 0 で初期化。
                bool       found       = false;

                if (!myStone_location.IsWestEnd()) // 西端でなければ。
                {
                    if (taikyoku.Goban.WestOf(myStone_location) == StoneColor.Empty)
                    {
                        tryLocation.SetLocation(myStone_location.ToWest());

                        int futureLiberty; // Gnugo1.2 では、グローバル変数 lib = 0 でした。
                        Util_CountLiberty.Count(out futureLiberty, tryLocation, taikyoku.MyColor, taikyoku);
                        tryScore = Util_SasiteNext.Evaluate_LibertyWeak(futureLiberty, currentLiberty);
                        found    = true;
                    }
                    else
                    {
                        if (
                            taikyoku.Goban.WestOf(myStone_location) == taikyoku.MyColor
                            &&
                            taikyoku.MarkingBoard.CanDo_West(myStone_location) // 西側
                            )
                        {
                            if (Util_SasiteNext.FindStone_LibertyWeak(out tryLocation, out tryScore, myStone_location.ToWest(), currentLiberty, taikyoku))
                            {
                                found = true;
                            }
                        }
                    }
                }

                if (found)  // 見つかっていれば 1
                {
                    found = false;
                    if (tryScore > out_bestScore && !Util_OwnEye.IsThis(tryLocation, taikyoku))
                    {
                        out_bestScore = tryScore;
                        out_bestLocation.SetLocation(tryLocation);
                    }
                }
            }

            //--------------------------------------------------------------------------
            // 東ネイバーを調べます。
            {
                GobanPoint tryLocation = new GobanPointImpl(0, 0); // Gnugo1.2 では ti,tj という変数名。// 初期値は 2015-11-26 追加
                int        tryScore    = 0;                        // Gnugo1.2 では tval 変数。 隣位置の評価値。    // 2015-11-26 追加 0 で初期化。
                bool       found       = false;

                if (!myStone_location.IsEastEnd(taikyoku.GobanBounds))    // 東端でなければ。
                {
                    if (taikyoku.Goban.EastOf(myStone_location) == StoneColor.Empty)
                    {
                        tryLocation.SetLocation(myStone_location.ToEast());

                        int futureLiberty; // Gnugo1.2 では、グローバル変数 lib = 0 でした。
                        Util_CountLiberty.Count(out futureLiberty, tryLocation, taikyoku.MyColor, taikyoku);
                        tryScore = Util_SasiteNext.Evaluate_LibertyWeak(futureLiberty, currentLiberty);
                        found    = true;
                    }
                    else
                    {
                        if
                        (
                            taikyoku.Goban.EastOf(myStone_location) == taikyoku.MyColor
                            &&
                            taikyoku.MarkingBoard.CanDo_East(myStone_location) // 東側
                        )
                        {
                            if (Util_SasiteNext.FindStone_LibertyWeak(out tryLocation, out tryScore, myStone_location.ToEast(), currentLiberty, taikyoku))
                            {
                                found = true;
                            }
                        }
                    }
                }

                if (found)  // Gnugo1.2では、見つかっていれば 1 でした。
                {
                    found = false;
                    if (out_bestScore < tryScore && !Util_OwnEye.IsThis(tryLocation, taikyoku))
                    {
                        out_bestScore = tryScore;
                        out_bestLocation.SetLocation(tryLocation);
                    }
                }
            }

            //--------------------------------------------------------------------------
            if (0 < out_bestScore)   // 次の動きを見つけた。
            {
                return(true);
            }
            else    // 次の動きは失敗。
            {
                return(false);
            }
        }