/// <summary> /// 整地された地かどうかを、確認します。 /// /// 場所を1つ指定し、 /// その4方向は 石がないか、同じ色の石だけで構成されている、 /// そういう場所は 整地されている自分の陣地として正しい。 /// /// Gnugo1.2 では findcolr 関数。 /// </summary> /// <param name="location">Gnugo1.2 では、 行番号 i = 0〜18、列番号 j = 0〜18。</param> /// <param name="taikyoku"></param> /// <returns></returns> public static StoneColor Test_SeitiZi ( GobanPoint location, Taikyoku taikyoku ) { //---------------------------------------- // 実装の説明 //---------------------------------------- // // 盤上の交点を1つ指定します。 // // そこに石があれば、その色を返します。 // // 石がなければ、4方向の直線上で最初に突き当たる石の色を調べます。 // (まるで、将棋の飛車の動きのように) // StoneColor result = StoneColor.Empty; // 色 // 2015-11-26 追加 Emptyで初期化。 /// [0]北、[1]南、[2]西、[3]東 StoneColor[] color = new StoneColor[4]; // // 指定した盤上の位置に石があれば、その色を返します。 // if (taikyoku.Goban.At(location) != StoneColor.Empty) { return(taikyoku.Goban.At(location)); } // 北ネイバーを、石に突き当たるまで調べます。 if (!location.IsNorthEnd())//北端でなければ { // 指定の行番号 〜 0 まで。突き当たらなければ k は 北端 まで。 int k = location.I; do { --k; }while ( taikyoku.Goban.At(new GobanPointImpl(k, location.J)) == StoneColor.Empty && 0 < k ); color[0] = taikyoku.Goban.At(new GobanPointImpl(k, location.J)); } else { // 空っぽ。 color[0] = StoneColor.Empty; } // 南ネイバーを、石に突き当たるまで調べます。 if (!location.IsSouthEnd(taikyoku.GobanBounds)) { // (18より小さい、指定の行番号)〜 南端 まで。 int k = location.I; do { ++k; }while ( taikyoku.Goban.At(new GobanPointImpl(k, location.J)) == StoneColor.Empty && k < taikyoku.GobanBounds.BoardEnd ); color[1] = taikyoku.Goban.At(new GobanPointImpl(k, location.J)); } else { // 空っぽ。 color[1] = StoneColor.Empty; } // 西ネイバーを、石に突き当たるまで調べます。 if (!location.IsWestEnd()) { // (0より大きい、指定の列番号)〜 1 まで。 int k = location.J; do { --k; }while ( taikyoku.Goban.At(new GobanPointImpl(location.I, k)) == StoneColor.Empty && k > 0 ); color[2] = taikyoku.Goban.At(new GobanPointImpl(location.I, k)); } else { // 空っぽ。 color[2] = StoneColor.Empty; } // 東ネイバーを、石に突き当たるまで調べます。 if (!location.IsEastEnd(taikyoku.GobanBounds)) { // (18より小さい、指定の列番号)〜 17 まで。 int k = location.J; do { ++k; }while ( taikyoku.Goban.At(new GobanPointImpl(location.I, k)) == StoneColor.Empty && k < taikyoku.GobanBounds.BoardEnd ); color[3] = taikyoku.Goban.At(new GobanPointImpl(location.I, k)); } else { // 空っぽ。 color[3] = StoneColor.Empty; } // 4方向のうち、空っぽでない交点の色を1つだけ知りたい。 for (int k = 0; k < 4; k++) { if (color[k] == StoneColor.Empty) { continue; } else { result = color[k]; break; } } // クロスチェックします。 // もし わたしたちがエラーを見つけたなら、全ての死ピースは盤から取らない。 // わたしたちはこれを修正するようプレイヤーたちに促す。 for (int k = 0; k < 4; k++) { // 色が設定されているのに、返す結果の色が違っていたらエラーです。問題です。 if ( color[k] != StoneColor.Empty && color[k] != result ) { return(StoneColor.Empty);// 0; } } // もし、わたしたちが全てのチェックにOKすれば、結果をレポートします。 return(result); }
/// <summary> /// 碁盤の指定の交点 i,j にある石を起点に、つながっている同じ色の石の(1つ、または連の)総リバーティを数えます。 /// 再帰的に呼び出されます。 /// Countlib関数から呼び出してください。 /// /// Gnugo1.2 では、count関数です。 /// </summary> /// <param name="count">Gnugo1.2 では、グローバル変数 lib でした。</param> /// <param name="location">Gnugo1.2では、行番号 i = 0〜18、列番号 j = 0〜18。</param> /// <param name="color">黒 or 白</param> /// <param name="taikyoku"></param> private static void Count_Recursive( ref int count, GobanPoint location, StoneColor color, Taikyoku taikyoku ) { //---------------------------------------- // 実装の解説 //---------------------------------------- // 石の周り4方向について、 // 数えていない空き交点であれば リバティーを 1加算します。 // 数えていなくて、指定した色(主に同じ色)の石であれば、その石から同メソッドを再帰呼び出しします。 // // 指定した位置は、調査済みとしてマークします。 taikyoku.CountedBoard.Done_Current(location); // 北隣の石を調べます。 if (!location.IsNorthEnd())//北端でなければ { if ( taikyoku.Goban.NorthOf(location) == StoneColor.Empty && taikyoku.CountedBoard.CanDo_North(location) ) { // 北隣が空いていて まだ数えていないなら、 // リバティーを1つ数え上げます。次からは重複して数えません。 ++count; taikyoku.CountedBoard.Done_North(location); } else if ( taikyoku.Goban.NorthOf(location) == color && taikyoku.CountedBoard.CanDo_North(location) ) { // 北隣に 指定色の石が置いてあり、まだ数えていないなら、 // その石からさらにカウントを続けます。 Util_CountLiberty.Count_Recursive(ref count, location.ToNorth(), color, taikyoku); } // 指定した色でない石が置いてあれば何もしない。 } // 南隣を調べます。 if (!location.IsSouthEnd(taikyoku.GobanBounds))//南端でなければ { // もう、だいたい分かるだろう☆(^▽^) if ( taikyoku.Goban.SouthOf(location) == StoneColor.Empty && taikyoku.CountedBoard.CanDo_South(location) ) { ++count; taikyoku.CountedBoard.Done_South(location); } else if ( taikyoku.Goban.SouthOf(location) == color && taikyoku.CountedBoard.CanDo_South(location) ) { Util_CountLiberty.Count_Recursive(ref count, location.ToSouth(), color, taikyoku); } } // 西隣を調べます。 if (!location.IsWestEnd())//西端でなければ { if ( taikyoku.Goban.WestOf(location) == StoneColor.Empty && taikyoku.CountedBoard.CanDo_West(location) ) { ++count; taikyoku.CountedBoard.Done_West(location); } else if ( taikyoku.Goban.WestOf(location) == color && taikyoku.CountedBoard.CanDo_West(location) ) { Util_CountLiberty.Count_Recursive(ref count, location.ToWest(), color, taikyoku); } } // 東隣を調べます。 if (!location.IsEastEnd(taikyoku.GobanBounds))//東端でなければ { if ( (taikyoku.Goban.EastOf(location) == StoneColor.Empty) && taikyoku.CountedBoard.CanDo_East(location) ) { ++count; taikyoku.CountedBoard.Done_East(location); } else if ( taikyoku.Goban.EastOf(location) == color && taikyoku.CountedBoard.CanDo_East(location) ) { Util_CountLiberty.Count_Recursive(ref count, location.ToEast(), color, taikyoku); } } }
/// <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); } }
/// <summary> /// 自分(コンピューター)の目へ打ち込んだとき、真。(非合法手) /// </summary> /// <param name="location">Gnugo1.2 では、石の 行番号 i = 0〜18、列番号 j = 0〜18。</param> /// <param name="taikyoku"></param> /// <returns></returns> public static bool IsThis ( GobanPoint location, Taikyoku taikyoku ) { Board ban = taikyoku.Goban; // 碁盤 // 上辺を調べます。 if (location.IsNorthEnd()) { if ( location.IsWestEnd() // 北西の角 && // 北西の隅を囲む2つの石が自分(コンピューター)の色なら。 ban.At(new GobanPointImpl(1, 0)) == taikyoku.MyColor && ban.At(new GobanPointImpl(0, 1)) == taikyoku.MyColor ) { return(true); } if ( location.IsEastEnd(taikyoku.GobanBounds) // 北東角 && // 北東の隅を囲む2つの石が自分(コンピューター)の色なら。 ban.At(new GobanPointImpl(1, taikyoku.GobanBounds.BoardEnd)) == taikyoku.MyColor && ban.At(new GobanPointImpl(0, taikyoku.GobanBounds.BoardEnd - 1)) == taikyoku.MyColor ) { return(true); } if ( // 上辺で、3方向がコンピューターの石なら ban.At(new GobanPointImpl(1, location.J)) == taikyoku.MyColor // コンピューターの石 && // 左右ともコンピューターの石 ban.At(new GobanPointImpl(0, location.J - 1)) == taikyoku.MyColor && ban.At(new GobanPointImpl(0, location.J + 1)) == taikyoku.MyColor ) { return(true); } else { return(false); } } // 下辺を調べます。 if (location.IsSouthEnd(taikyoku.GobanBounds)) { if ( location.IsWestEnd() // 南西角 && // 南西の隅を囲む2つの石がコンピューターの色なら。 ban.At(new GobanPointImpl(taikyoku.GobanBounds.BoardEnd - 1, 0)) == taikyoku.MyColor && ban.At(new GobanPointImpl(taikyoku.GobanBounds.BoardEnd, 1)) == taikyoku.MyColor ) { return(true); } if ( location.IsEastEnd(taikyoku.GobanBounds) // 南東 && // 南東の隅を囲む2つの石がコンピューターの色なら。 ban.At(new GobanPointImpl(taikyoku.GobanBounds.BoardEnd - 1, taikyoku.GobanBounds.BoardEnd)) == taikyoku.MyColor && ban.At(new GobanPointImpl(taikyoku.GobanBounds.BoardEnd, taikyoku.GobanBounds.BoardEnd - 1)) == taikyoku.MyColor ) { return(true); } if ( // 下辺で、3方向がコンピューターの石なら ban.At(new GobanPointImpl(taikyoku.GobanBounds.BoardEnd - 1, location.J)) == taikyoku.MyColor && ban.At(new GobanPointImpl(taikyoku.GobanBounds.BoardEnd, location.J - 1)) == taikyoku.MyColor && ban.At(new GobanPointImpl(taikyoku.GobanBounds.BoardEnd, location.J + 1)) == taikyoku.MyColor ) { return(true); } else { return(false); } } // 左辺を調べます。 if (location.IsWestEnd()) { if ( // 左辺で、3方向がコンピューターの石なら ban.At(new GobanPointImpl(location.I, 1)) == taikyoku.MyColor && ban.At(new GobanPointImpl(location.I - 1, 0)) == taikyoku.MyColor && ban.At(new GobanPointImpl(location.I + 1, 0)) == taikyoku.MyColor ) { return(true); } else { return(false); } } // 右辺を調べます。 if (location.IsEastEnd(taikyoku.GobanBounds)) { if ( // 右辺で、3方向がコンピューターの石なら ban.At(new GobanPointImpl(location.I, taikyoku.GobanBounds.BoardEnd - 1)) == taikyoku.MyColor && ban.At(new GobanPointImpl(location.I - 1, taikyoku.GobanBounds.BoardEnd)) == taikyoku.MyColor && ban.At(new GobanPointImpl(location.I + 1, taikyoku.GobanBounds.BoardEnd)) == taikyoku.MyColor ) { return(true); } else { return(false); } } // 中央のピースを調べます。 if ( // 4方向がコンピューターの石なら ban.NorthOf(location) == taikyoku.MyColor && ban.EastOf(location) == taikyoku.MyColor && ban.SouthOf(location) == taikyoku.MyColor && ban.WestOf(location) == taikyoku.MyColor ) { return(true); } else { return(false); } }