/// <summary> /// 囲われた石を、盤上から除外します。コウにならないかどうか、注意します。 /// /// Gnugo1.2 では、exambord関数。 /// </summary> /// <param name="colorKo">取られた方の、黒 or 白</param> /// <param name="taikyoku"></param> public static void RemoveStones_Surrounded ( StoneColor colorKo, Taikyoku taikyoku ) { // 盤上の全てのポイントに、呼吸点の数を記憶させます。 int[,] libertyOfNodes; Util_LibertyAtNode.CountAll(out libertyOfNodes, colorKo, taikyoku); // 取った石の位置を初期化します。(コウで戻さなくてはならない石の位置を覚えていたもの) if (colorKo == taikyoku.MyColor) { taikyoku.MyKo.MoveToVanish(); } else { taikyoku.YourKo.MoveToVanish(); } // コウの動きで取れる石の数。 int countOfDelete = 0; // リバティーのない石は全て碁番から削除します。 // つまり四方を全て囲まれたピース(石のあつまり)です。 for (int i = 0; i < taikyoku.GobanBounds.BoardSize; i++) { for (int j = 0; j < taikyoku.GobanBounds.BoardSize; j++) { GobanPoint location = new GobanPointImpl(i, j); if ( // 取られる側の石であり、 taikyoku.Goban.At(location) == colorKo && // ピースのリバティーが記録されていないなら libertyOfNodes[i, j] == 0 ) { // 石を除外します。 taikyoku.Goban.Put(location, StoneColor.Empty); // (後で元に戻すこともあるので)取った石の位置を記憶し、取られた石の数をカウントアップします。 if (colorKo == taikyoku.MyColor) { // コンピューター側 taikyoku.MyKo.SetLocation(location); ++taikyoku.Count_MyCaptured; } else { // 人間側 taikyoku.YourKo.SetLocation(location); ++taikyoku.Count_YourCaptured; } ++countOfDelete; // この指し手で取った駒の数? } // 取った石が2つ以上なら、コウ(Ko)の可能性がなくなります。石の位置の記憶をリセットします。 if (colorKo == taikyoku.MyColor && 1 < countOfDelete) { // コンピューターが取った石の位置(コウになるかもしれない)をクリアー。 taikyoku.MyKo.MoveToVanish(); } else if (1 < countOfDelete) // TODO: こっちは 1 < countOfDelete しなくていいのか? { // 人間が取った石の位置(コウになるかもしれない)をクリアー。 taikyoku.YourKo.MoveToVanish(); } } //j } //i }
/// <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); } } }
/// <summary> /// 相手の盤上i,jの動きが自殺手でないか調べます。 /// </summary> /// <param name="location">Gnugo1.2 では、i,j という引数名。</param> /// <param name="taikyoku"></param> /// <returns></returns> public static bool Aa_Suicide( GobanPoint location, Taikyoku taikyoku ) { int banSize = taikyoku.GobanBounds.BoardSize; // 新しい動きのリバティーを数えなおします。 int liberty; // Gnugo1.2 では、グローバル変数 lib = 0 でした。 Util_CountLiberty.Count(out liberty, location, taikyoku.YourColor, taikyoku); if (liberty == 0) // 調べて、もしコンピューターのピースズを殺して、コの可能性があれば、 // 新しい動きは自殺手です。 { // assume alive taikyoku.Goban.Put(location, taikyoku.YourColor); // カレント色の石のリバティー(四方の石を置けるところ) // // Gnugo1.2 では、l という名前のグローバル変数。liberty の略だろうか? // eval で内容が設定され、その内容は exambord、findsavr、findwinr、suicideで使用されます。 int[,] libertyOfNodes; // コンピューターの呼吸点の数を数えます。 Util_LibertyAtNode.CountAll(out libertyOfNodes, taikyoku.MyColor, taikyoku); int k = 0; for (int m = 0; m < banSize; m++) { for (int n = 0; n < banSize; n++) { // 殺されるかもしれないピースズを数えます。 if ( (taikyoku.Goban.At(new GobanPointImpl(m, n)) == taikyoku.MyColor) && libertyOfNodes[m, n] == 0 ) { ++k; } if ( (k == 0) || ( k == 1 && ( (location.I == taikyoku.YourKo.I) && (location.J == taikyoku.YourKo.J) ) ) ) // either no effect on my pieces or an illegal Ko take back { taikyoku.Goban.Put(location, StoneColor.Empty); /* restore to open */ return(true); } else { /* good move */ return(false); } } } return(false);// 2015-11-26 追加 } else { /* valid move */ return(false); } }