/// <summary>
 /// 中央からどれだけ離れているか。
 ///
 /// Gnugo1.2 では line 関数。
 /// </summary>
 /// <param name="x"></param>
 /// <returns></returns>
 public static int DistanceFromCenter(int x, GobanRectangleA gobanBounds)
 {
     return(Util_FindLocalZyoseki.Abs(x - gobanBounds.BoardCenter));
 }
        /// <summary>
        /// 序盤定石以外の、局地的な定石にあてはまるかをしらべ、定石があれば置く場所を取得します。
        /// </summary>
        /// <param name="out_location">次の手の 行、列番号</param>
        /// <param name="out_score">Gnugo1.2 では val 引数。評価値</param>
        /// <param name="origin_location">Gnugo1.2 では、 原点の   行 m、列 n 引数。</param>
        /// <param name="taikyoku"></param>
        /// <returns></returns>
        public static bool FindPattern
        (
            out GobanPoint out_location,
            out int out_score,
            GobanPoint origin_location,
            Taikyoku taikyoku
        )
        {
            GobanPoint tryLocation = new GobanPointImpl(0, 0); // Gnugo1.2 では、ti,tj という変数名。// 2015-11-26 追加 0,0 で初期化。

            out_location = new GobanPointImpl(-1, -1);
            out_score    = -1;

            for (int ptnNo = 0; ptnNo < Util_LocalZyoseki.Patterns.Length; ptnNo++)      // それぞれのパターンを試します。
            {
                for (int ll = 0; ll < Util_LocalZyoseki.Patterns[ptnNo].LastTrfNo; ll++) /* try each orientation transformation */
                {
                    int  k = 0;
                    bool isContinueLoop = true; // Gnugo1.2 では cont変数。continueの略か?

                    //
                    // 条件に一致していないものを、ふるい落としていきます。
                    // 条件に一致しているものは、どんどん次のループに進みます。
                    //
                    while (
                        k != Util_LocalZyoseki.Patterns[ptnNo].Stones.Length
                        &&
                        isContinueLoop
                        )/* いくつかのポイントに一致 */
                    {
                        //
                        // 変形(transform)して、盤上の座標に変換します。
                        //
                        int nx =
                            origin_location.J
                            +
                            Util_FindLocalZyoseki.Trf[ll, 0, 0] * Util_LocalZyoseki.Patterns[ptnNo].Stones[k].P.X
                            +
                            Util_FindLocalZyoseki.Trf[ll, 0, 1] * Util_LocalZyoseki.Patterns[ptnNo].Stones[k].P.Y
                        ;

                        int my =
                            origin_location.I
                            +
                            Util_FindLocalZyoseki.Trf[ll, 1, 0] * Util_LocalZyoseki.Patterns[ptnNo].Stones[k].P.X
                            +
                            Util_FindLocalZyoseki.Trf[ll, 1, 1] * Util_LocalZyoseki.Patterns[ptnNo].Stones[k].P.Y
                        ;

                        /* outside the board */
                        if (
                            !Util_AboutBoard.In_Board(my, taikyoku.GobanBounds)
                            ||
                            !Util_AboutBoard.In_Board(nx, taikyoku.GobanBounds)
                            )
                        {
                            isContinueLoop = false;
                            break;
                        }

                        GobanPoint mnLocation = new GobanPointImpl(my, nx);
                        switch (Util_LocalZyoseki.Patterns[ptnNo].Stones[k].Att)
                        {
                        case LocalZyoseki_StoneAttribute._0_Empty:
                            if (taikyoku.Goban.At(mnLocation) == StoneColor.Empty)        /* open */
                            {
                                break;
                            }
                            else
                            {
                                isContinueLoop = false;
                                break;
                            }

                        case LocalZyoseki_StoneAttribute._1_YourPiece:
                            if (taikyoku.Goban.At(mnLocation) == taikyoku.YourColor)      /* your piece */
                            {
                                break;
                            }
                            else
                            {
                                isContinueLoop = false;
                                break;
                            }

                        case LocalZyoseki_StoneAttribute._2_MyPiece:
                            if (taikyoku.Goban.At(mnLocation) == taikyoku.MyColor)      /* my piece */
                            {
                                break;
                            }
                            else
                            {
                                isContinueLoop = false;
                                break;
                            }

                        case LocalZyoseki_StoneAttribute._3_MyNextMove:
                            if (taikyoku.Goban.At(mnLocation) == StoneColor.Empty)                                   /* open for new move */
                            {
                                int libertyOfPiece;                                                                  // Gnugo1.2 では、グローバル変数 lib = 0 でした。
                                Util_CountLiberty.Count(out libertyOfPiece, mnLocation, taikyoku.MyColor, taikyoku); /* check liberty */
                                if (1 < libertyOfPiece)                                                              /* move o.k. */
                                {
                                    tryLocation.SetLocation(my, nx);
                                    break;
                                }
                                else
                                {
                                    isContinueLoop = false;
                                    break;
                                }
                            }
                            else
                            {
                                isContinueLoop = false;
                                break;
                            }

                        case LocalZyoseki_StoneAttribute._4_EmptyOnEdge:
                            if
                            (
                                taikyoku.Goban.At(mnLocation) == StoneColor.Empty      /* open on edge */
                                &&
                                (
                                    Util_AboutBoard.On_Edge(my, taikyoku.GobanBounds) || Util_AboutBoard.On_Edge(nx, taikyoku.GobanBounds)
                                )
                            )
                            {
                                break;
                            }
                            else
                            {
                                isContinueLoop = false;
                                break;
                            }

                        case LocalZyoseki_StoneAttribute._5_YourPieceOnEdge:
                            if
                            (
                                taikyoku.Goban.At(mnLocation) == taikyoku.YourColor      /* your piece on edge */
                                &&
                                (
                                    Util_AboutBoard.On_Edge(my, taikyoku.GobanBounds) || Util_AboutBoard.On_Edge(nx, taikyoku.GobanBounds)
                                )
                            )
                            {
                                break;
                            }
                            else
                            {
                                isContinueLoop = false;
                                break;
                            }

                        case LocalZyoseki_StoneAttribute._6_MyPieceOnEdge:
                            if
                            (
                                taikyoku.Goban.At(mnLocation) == taikyoku.MyColor      /* my piece on edge */
                                &&
                                (
                                    Util_AboutBoard.On_Edge(my, taikyoku.GobanBounds) || Util_AboutBoard.On_Edge(nx, taikyoku.GobanBounds)
                                )
                            )
                            {
                                break;
                            }
                            else
                            {
                                isContinueLoop = false;
                                break;
                            }
                        }
                        ++k;
                    }

                    if (isContinueLoop)                                         // パターンに一致しています。
                    {
                        int tryScore = Util_LocalZyoseki.Patterns[ptnNo].Score; // Gnugo1.2 では、tval 変数。


                        if (
                            // パターン番号 8〜13 には、報酬とペナルティーを付けます。
                            8 <= ptnNo && ptnNo <= 13    /* patterns for expand region */
                            )
                        {
                            if (7 < Util_FindLocalZyoseki.DistanceFromCenter(tryLocation.I, taikyoku.GobanBounds))
                            {
                                // 中心から 8以上離れている(端と、その隣ぐらいの位置)ならば、ペナルティーを付けます。
                                tryScore--;
                            }
                            else if ((Util_FindLocalZyoseki.DistanceFromCenter(tryLocation.I, taikyoku.GobanBounds) == 6) || (Util_FindLocalZyoseki.DistanceFromCenter(tryLocation.I, taikyoku.GobanBounds) == 7))
                            {
                                // 中心から 6〜7 離れている位置(端から3,4番目ぐらい)には、報酬を与えます。
                                tryScore++;
                            }

                            if (7 < Util_FindLocalZyoseki.DistanceFromCenter(tryLocation.J, taikyoku.GobanBounds))  /* penalty on line 1, 2 */
                            {
                                tryScore--;
                            }
                            else if ((Util_FindLocalZyoseki.DistanceFromCenter(tryLocation.J, taikyoku.GobanBounds) == 6) || (Util_FindLocalZyoseki.DistanceFromCenter(tryLocation.J, taikyoku.GobanBounds) == 7))
                            {
                                tryScore++;    /* reward on line 3, 4 */
                            }
                        }

                        if (tryScore > out_score)
                        {
                            out_score = tryScore;
                            out_location.SetLocation(tryLocation);
                        }
                    }
                }//for
            }

            if (0 < out_score)   // パターンにマッチしました。
            {
                return(true);
            }
            else    // マッチに失敗しました。
            {
                return(false);
            }
        }