/// <summary> /// 局面を、テキストファイルに書き出します。 /// /// 19路盤、9路盤 両用です。 /// </summary> /// <param name="taikyoku"></param> public static void Save(Taikyoku taikyoku) { StringBuilder sb = new StringBuilder(); //fp = fopen("gnugo.dat", "w"); // 盤設定を保存します。 for (int m = 0; m < taikyoku.GobanBounds.BoardSize; m++) { for (int n = 0; n < taikyoku.GobanBounds.BoardSize; n++) { sb.Append(Conv_StoneColor.ToNumber(taikyoku.Goban.At(new GobanPointImpl(m, n)))); //fprintf(fp, "%c", Util_GlobalVar.P[m,n]); } } // コンピューターの色、お互いの取ったピース sb.Append(Conv_StoneColor.ToNumber(taikyoku.MyColor)); sb.Append(" "); sb.Append(taikyoku.Count_MyCaptured); sb.Append(" "); sb.Append(taikyoku.Count_YourCaptured); sb.Append(" "); //fprintf(fp, "%d %d %d ", Util_GlobalVar.Mymove, Util_GlobalVar.Mk, Util_GlobalVar.Uk); // 序盤定跡フラグ for (int index = 0; index < 9; index++) { sb.Append(taikyoku.OpeningZyosekiFlag[index] ? 1 : 0); sb.Append(" "); //fprintf(fp, "%d ", Util_GlobalVar.Opn[m]); } //fclose(fp); File.WriteAllText(taikyoku.SaveFileName, sb.ToString()); }
/// <summary> /// 盤上の石を数えます。 /// </summary> public static void CountPieces ( out int out_myTotal, // Gnugo1.2 では mtot という変数名。my total の略だろうか? out int out_yourTotal, // Gnugo1.2 では utot という変数名。your total の略だろうか? Taikyoku taikyoku ) { out_myTotal = 0; out_yourTotal = 0; for (int i = 0; i < taikyoku.GobanBounds.BoardSize; i++) { for (int j = 0; j < taikyoku.GobanBounds.BoardSize; j++) { GobanPoint ijLocation = new GobanPointImpl(i, j); if (taikyoku.Goban.At(ijLocation) == taikyoku.MyColor) { ++out_myTotal; } else if (taikyoku.Goban.At(ijLocation) == taikyoku.YourColor) { ++out_yourTotal; } } } }
/// <summary> /// ハンディーキャップを尋ねます。 /// /// Gnugo1.2 では、main.c の main関数。 /// </summary> public void DoScene(Taikyoku taikyoku) { // ハンディーキャップを尋ねます。 Console.Write("Number of handicap for black (0 to 17)? "); // 数字を入れてください。 int handicap_temp; while (!int.TryParse(Console.ReadLine(), out handicap_temp)) { // もう1回 Console.Write("Number of handicap for black (0 to 17)? "); } this.Handicap = handicap_temp; //scanf("%d", ref i); //getchar(); switch (taikyoku.GobanBounds.BoardSize) { case 9: Util_Handicap_9ziban.DoHandicap(this.Handicap, taikyoku); break; default: Util_Handicap_19ziban.DoHandicap(this.Handicap, taikyoku); break; } // ハンディーキャップを選択したところで、ゲーム盤を表示します。 ((BoardPrinterB)taikyoku.BoardPrinter).ShowBoard(taikyoku); }
/// <summary> /// 星のない水平線です。 /// </summary> /// <param name="i"></param> /// <param name="taikyoku"></param> /// <returns></returns> private string CreateBoardLine_Normal(int i, Taikyoku taikyoku) { StringBuilder sb = new StringBuilder(); for (int j = 0; j < 9; j++) { GobanPoint location = new GobanPointImpl(i, j); if (taikyoku.Goban.At(location) == StoneColor.Empty) { sb.Append(" -"); } else if (taikyoku.Goban.At(location) == StoneColor.White) { sb.Append(" O"); } else { sb.Append(" X"); } } int ii = taikyoku.GobanBounds.BoardSize - i; sb.Append(String.Format("{0,2}", ii)); return(sb.ToString()); }
/// <summary> /// 盤上の全交点に、その場所の石(または連)の総呼吸点の数を埋めます。 /// /// Gnugo1.2 では、eval 関数。 /// </summary> /// <param name="libertyOfNodes"> /// Gnugo1.2 では、l という名前のグローバル変数。liberty の略だろうか? /// eval で内容が設定され、その内容は exambord、findsavr、findwinr、suicideで使用されます。 /// </param> /// <param name="color">黒 or 白</param> public static void CountAll ( out int[,] libertyOfNodes, StoneColor color, Taikyoku taikyoku ) { int banSize = taikyoku.GobanBounds.BoardSize; // 何路盤 libertyOfNodes = new int[taikyoku.GobanBounds.BoardSize, taikyoku.GobanBounds.BoardSize]; // それぞれのピースの総呼吸点の数を数えます。 for (int i = 0; i < banSize; i++) { for (int j = 0; j < banSize; j++) { GobanPoint iLocation = new GobanPointImpl(i, j); if (taikyoku.Goban.At(iLocation) == color) // 指定の色の石のみ { int liberty; // Gnugo1.2 では、グローバル変数 lib = 0 でした。 Util_CountLiberty.Count(out liberty, iLocation, color, taikyoku); libertyOfNodes[i, j] = liberty; } } } }
/// <summary> /// 人間の入力したコマンドに対応した処理を行います。 /// 間違った入力があった場合、再帰的に呼び出されます。 /// /// Gnugo1.2 では、getmove関数。 /// </summary> /// <param name="move_charArray">入力した文字列。a1やT19などの指し手。</param> /// <param name="out_sasite">指し手。石を置く位置</param> /// <param name="taikyoku"></param> public static void DoCommand ( string command_str, out GobanPoint out_sasite, Taikyoku taikyoku ) { if (command_str == "stop") // ゲームを終了します。 { taikyoku.PlayState = GameState.Stop; out_sasite = new GobanPointImpl(-1, -1);// 2015-11-26 追加 } else { if (command_str == "save") // データを保存して、ゲームを終了します。 { // 局面を、テキストファイルに書き出します。 Util_Save.Save(taikyoku); taikyoku.PlayState = GameState.Saved; // i が -1 のときは、パスのシグナルです。 out_sasite = new GobanPointImpl(-1, -1); // 2015-11-26 追加 } else if (command_str == "pass") // 人間のパス { taikyoku.Pass++; // i が -1 のときは、パスのシグナルです。 out_sasite = new GobanPointImpl(-1, -1);// 2015-11-26 追加 } else { taikyoku.Pass = 0; if ( // 例えば、 a1 や、 T19 といった入力文字を解析し、盤上の位置に変換します。 !PointFugoImpl.TryParse(command_str, out out_sasite, taikyoku) || (taikyoku.Goban.At(out_sasite) != StoneColor.Empty) || Util_Suicide.Aa_Suicide(out_sasite, taikyoku) ) { // // 非合法手だった場合、再入力を促します。 // Console.WriteLine("illegal move !"); // [" + command_str + "] 2015-11-26 入力されたコマンドを表示するように拡張 Console.Write("your move? "); // 続けて、再帰的に処理実行。 string command_str2 = Console.ReadLine(); //scanf("%s", move); Util_CommandDriven.DoCommand(command_str2, out out_sasite, taikyoku); } } } }
/// <summary> /// シーンを進行。 /// /// つながったデッド・ピースを、コンソールから1つ1つ手入力し、 /// 整地をしたのち、勝者をアナウンスします。 /// /// Gnugo1.2 では、endgame関数。 /// </summary> /// <param name="taikyoku"></param> public void DoScene(Taikyoku taikyoku) { //---------------------------------------- // 石の数え方を、3ステップに分けて進めます。 //---------------------------------------- // // (1)死んでいる石を盤上から全て取り除く。 // (2)どちらの陣地でもないところを埋める。 // (3)石を数えて、勝者をアナウンスする。 // // まず、全体の説明と、1ステップ目の説明を表示します。 // Console.WriteLine(); Console.WriteLine("To count score, we need the following steps:"); Console.WriteLine("First, I need you to remove all dead pieces on the board."); Console.WriteLine("Second, I need you to fill in neutral territories with pieces."); Console.WriteLine("Last, I will fill in all pieces and announce the winner."); Console.WriteLine(); Console.WriteLine("First, you should enter the dead pieces (black and white) to be removed. Enter"); Console.WriteLine(" 'stop' when you have finished."); //---------------------------------------- // 死んでいる石のつながりを、盤上から削除します。 //---------------------------------------- Util_EndOfGame.Remove_DeadPieces(taikyoku); //---------------------------------------- // どちらの地(陣地)でもない交点を、黒か白の石で交互に埋めます。 //---------------------------------------- Console.WriteLine("Next, you need to fill in pieces (black and white) in all neutral territories."); Console.WriteLine("Enter your and my pieces alternately and enter 'stop' when finish"); Util_EndOfGame.FillNeutralTerritories(taikyoku); // この時点で、整地を済ませたとします。 // 空きスペースを、どちらの陣地か判定し、その陣地の石に変換します。 Util_EndOfGame.FillStones(taikyoku); // 盤上の石を数えます。 int myTotal; // Gnugo1.2 では mtot という変数名。my total の略だろうか? int yourTotal; // Gnugo1.2 では utot という変数名。your total の略だろうか? Util_EndOfGame.CountPieces(out myTotal, out yourTotal, taikyoku); //---------------------------------------- // 整地後の碁盤を表示し、勝者をアナウンスします。 //---------------------------------------- ((BoardPrinterB)taikyoku.BoardPrinter).ShowBoard(taikyoku); Console.WriteLine("Your total number of pieces {0}", yourTotal); Console.WriteLine("My total number of pieces {0}", myTotal); Console.ReadLine(); }
/// <summary> /// もし四角形 (i1,j1)〜(i2,j2)がオープン(全て空っぽ)なら、調べます。 /// /// Gnugo1.2 では、 openregion関数。 /// </summary> /// <param name="corner1">Gnugo1.2 では、i1,j1 引数。</param> /// <param name="corner2">Gnugo1.2 では、i2,j2 引数。</param> /// <param name="taikyoku"></param> /// <returns></returns> public static bool IsEmptyRectangle ( GobanPoint corner1, GobanPoint corner2, Taikyoku taikyoku ) { int minx, maxx, miny, maxy, x, y; // 上下の限界を差替えます。 if (corner1.I < corner2.I) { miny = corner1.I; maxy = corner2.I; } else { miny = corner2.I; maxy = corner1.I; } if (corner1.J < corner2.J) { minx = corner1.J; maxx = corner2.J; } else { minx = corner2.J; maxx = corner1.J; } // 空っぽ領域を調べます。 for (y = miny; y <= maxy; y++) { for (x = minx; x <= maxx; x++) { if (taikyoku.Goban.At(new GobanPointImpl(y, x)) != StoneColor.Empty) { return(false); } } } return(true); }
/// <summary> /// 碁盤の指定の交点 i,j にある石を起点に、つながっている同じ色の(1つ、または連の)石(color piece)の総リバーティを数えます。 /// /// Gnugo1.2 では、countlib関数です。 /// </summary> /// <param name="out_count">Gnugo1.2 では、グローバル変数 lib でした。</param> /// <param name="startLocation_inPiece">Gnugo1.2では、 行番号 m = 0〜18、列番号 n = 0〜18。</param> /// <param name="color">黒 or 白</param> public static void Count ( out int out_count, GobanPoint startLocation_inPiece, StoneColor color, Taikyoku taikyoku ) { out_count = 0;// Gnugo1.2 では、countlib関数の呼び出し元で グローバル変数を lib = 0 していました。 // 全てのピースを数えなおせるように、リセットします。 taikyoku.CountedBoard.FillAll_WeCan(taikyoku.GobanBounds.BoardSize); // カレント・ピースのリバティーを数えます。 Util_CountLiberty.Count_Recursive(ref out_count, startLocation_inPiece, color, taikyoku); }
/// <summary> /// 空きスペースを、どちらの陣地か判定し、その陣地の石に変換します。 /// </summary> public static void FillStones ( Taikyoku taikyoku ) { for (int i = 0; i < taikyoku.GobanBounds.BoardSize; i++) { for (int j = 0; j < taikyoku.GobanBounds.BoardSize; j++) { GobanPoint ijLocation = new GobanPointImpl(i, j); if (taikyoku.Goban.At(ijLocation) == StoneColor.Empty) { taikyoku.Goban.Put(ijLocation, Util_SeitiZi.Test_SeitiZi(ijLocation, taikyoku)); } } } }
/// <summary> /// ゲームツリーから序盤のための動きを取得します。 /// </summary> /// <param name="p"></param> /// <param name="ref_nodeNo">Gnugo1.2 では 引数cnd。</param> /// <param name="moveType"></param> /// <param name="taikyoku"></param> /// <returns></returns> public static bool Opening ( out GobanPoint p, ref int ref_nodeNo, MoveType moveType, Taikyoku taikyoku ) { int m; p = new GobanPointImpl(); /* get i, j */ if (moveType == MoveType.Inverted || moveType == MoveType.Inverted_And_Reflected) { p.I = taikyoku.GobanBounds.BoardEnd - OpeningZyosekiImpl.ZyosekiTree[ref_nodeNo].P.I; /* inverted */ } else { p.I = OpeningZyosekiImpl.ZyosekiTree[ref_nodeNo].P.I; } if (moveType == MoveType.Reflected || moveType == MoveType.Inverted_And_Reflected) { p.J = taikyoku.GobanBounds.BoardEnd - OpeningZyosekiImpl.ZyosekiTree[ref_nodeNo].P.J; /* reflected */ } else { p.J = OpeningZyosekiImpl.ZyosekiTree[ref_nodeNo].P.J; } if (OpeningZyosekiImpl.ZyosekiTree[ref_nodeNo].Next.Length != 0) // 定石に、次の指し手がまだあるなら。 { // 次にどの定石を進むかはランダム(等確率)。 m = taikyoku.Random.Next() % OpeningZyosekiImpl.ZyosekiTree[ref_nodeNo].Next.Length; ref_nodeNo = OpeningZyosekiImpl.ZyosekiTree[ref_nodeNo].Next[m]; // 定石グラフ図の新しいノード番号へ。 return(true); } else { return(false); } }
/// <summary> /// 星のない水平線です。 /// </summary> /// <param name="i"></param> /// <param name="taikyoku"></param> /// <returns></returns> private string CreateBoardLine_Normal(int i, Taikyoku taikyoku) { StringBuilder sb = new StringBuilder(); for (int j = 0; j < taikyoku.GobanBounds.BoardSize; j++) { GobanPoint stoneLocation = new GobanPointImpl(i, j); if (taikyoku.Goban.At(stoneLocation) == StoneColor.Empty) { sb.Append(" -"); } else if (taikyoku.Goban.At(stoneLocation) == StoneColor.White) { sb.Append(" O"); } else { sb.Append(" X"); } } return(sb.ToString()); }
/// <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> /// 弱っている石を助ける手を探します。 /// 助けるというのは、(襲われそうな)自分の石の 横にツケることです。 /// /// 位置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> /// 盤上の各場所について、隣四方に同じ色の石があるかを調べ、 /// あれば その場所を記憶します。 /// /// Gnugo1.2 では createlist関数。二次元配列を使用していたが、Dictionary、List に変更した。 /// </summary> /// <param name="color"></param> /// <param name="out_list_neswStones_asNode_eachPoint">Gnugo1.2 では、 movelist という名称。</param> /// <param name="taikyoku"></param> private static void GetNeswStones_AsNode_EachPoint( StoneColor color, out Dictionary <int, List <int> > out_list_neswStones_asNode_eachPoint, Taikyoku taikyoku ) { //---------------------------------------- // 実装の説明 //---------------------------------------- // // 各場所について、隣四方に同じ色の石があるかを調べ、 // あれば その場所を記憶します。 // out_list_neswStones_asNode_eachPoint = new Dictionary <int, List <int> >(); 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) == color) //指定した色の石について { int node = Util_AboutBoard.GetNodeByLocation(location, taikyoku.GobanBounds); //盤上の場所の通し番号 // 北東南西の場所。石がある場合のみ。 List <int> neswNodes = new List <int>(); // まず、その場所の四方の様子を記憶するためのリストを用意。 out_list_neswStones_asNode_eachPoint.Add(node, neswNodes); // 北隣を調べる if (!location.IsNorthEnd())//北端ではないなら。 { if (taikyoku.Goban.NorthOf(location) == color) { neswNodes.Add(Util_AboutBoard.GetNodeByLocation(location.ToNorth(), taikyoku.GobanBounds));//北隣の場所を追加。 } } // 東隣を調べる if (!location.IsEastEnd(taikyoku.GobanBounds))//東端ではないなら。 { if (taikyoku.Goban.EastOf(location) == color) { neswNodes.Add(Util_AboutBoard.GetNodeByLocation(location.ToEast(), taikyoku.GobanBounds)); } } // 南隣を調べる if (!location.IsSouthEnd(taikyoku.GobanBounds))//南端ではないなら { if (taikyoku.Goban.SouthOf(location) == color) { neswNodes.Add(Util_AboutBoard.GetNodeByLocation(location.ToSouth(), taikyoku.GobanBounds)); } } // 西隣を調べる if (!location.IsWestEnd())//西端ではないなら。 { if (taikyoku.Goban.WestOf(location) == color) { neswNodes.Add(Util_AboutBoard.GetNodeByLocation(location.ToWest(), taikyoku.GobanBounds)); } } } // end if for color } // End j loop } // End i loop }
/// <summary> /// どちらの地(陣地)でもない交点を、黒か白の石で交互に埋めます。 /// </summary> public static void FillNeutralTerritories ( Taikyoku taikyoku ) { bool isContinuePhase = true; // Gnugo1.2 では cont という変数名。continueの略だろうか? int youMeCounter = 0; //白黒を反転するためのカウンター GobanPoint location; // Gnugo1.2 では、 i, j という変数名。 do { if (youMeCounter % 2 == 0) { // // 指定した場所を、コンピューター側の石に置き換える処理です。 // Console.Write("Your piece? "); string an_str = Console.ReadLine(); //scanf("%s", an); //---------------------------------------- // 妥当な入力があるまで、くるくる回します。 //---------------------------------------- {//2015-11-27 追加 bool valid = false; if (an_str == "stop") { valid = true; location = null; } else { valid = PointFugoImpl.TryParse(an_str, out location, taikyoku); } if (!valid) { // 入力が不妥当なので、ループし直し。 goto gt_PlayerPieceContinue; } } // ここで入力が妥当と分かった。このあと処理。 if (an_str == "stop") { // ループから抜けます。 isContinuePhase = false; goto gt_PlayerPieceContinue; } else { taikyoku.Goban.Put(location, taikyoku.YourColor); ((BoardPrinterB)taikyoku.BoardPrinter).ShowBoard(taikyoku); } } else { // // 指定した場所を、相手(人間)の石に置き換える処理です。 // Console.Write("My piece? "); string an_str = Console.ReadLine(); //scanf("%s", an); //---------------------------------------- // 妥当な入力があるまで、くるくる回します。 //---------------------------------------- {//2015-11-27 追加 bool valid = false; if (an_str == "stop") { valid = true; location = null; } else { valid = PointFugoImpl.TryParse(an_str, out location, taikyoku); } if (!valid) { // 入力が不妥当なので、ループし直し。 goto gt_PlayerPieceContinue; } } // ここで入力が妥当と分かった。このあと処理。 if (an_str == "stop") { // ループから抜けます。 isContinuePhase = false; goto gt_PlayerPieceContinue; } else { taikyoku.Goban.Put(location, taikyoku.MyColor); ((BoardPrinterB)taikyoku.BoardPrinter).ShowBoard(taikyoku); } } youMeCounter++; gt_PlayerPieceContinue: ; }while (isContinuePhase); }
/// <summary> /// 入力文字列を、i,j 座標へ変換します。 /// /// Gnugo1.2 では、getij 関数だったものを改造。 /// </summary> /// <param name="move_str"></param> /// <param name="out_location"></param> /// <returns></returns> public static bool TryParse ( string move_str, // 2桁、または3桁の指し手文字列。Gnugo1.2では move という引数名。 out GobanPoint out_location, // 指し手の 行、列番号 Taikyoku taikyoku ) { // move[0] from A〜T // move[1] move[2] from 1〜19 // 指し手を座標に変換します。 char[] move = move_str.ToCharArray(); int k; out_location = new GobanPointImpl(-1, -1); // 2015-11-27 追加 if (move.Length < 2) // 2015-11-26 追加 { // 2文字未満なら非妥当。 return(false); } // 1文字目 if ( // A〜H なら (move[0] >= 'A') && (move[0] <= 'H') ) { // 0〜7列 に変換 out_location.J = move[0] - 'A'; } else { if ( // J〜T なら (move[0] >= 'J') && (move[0] <= 'T') ) { // 8〜18列 に変換 out_location.J = move[0] - 'B'; } else { // a〜h なら if ((move[0] >= 'a') && (move[0] <= 'h')) { // 0〜7列 に変換 out_location.J = move[0] - 'a'; } else { // j〜t なら if ((move[0] >= 'j') && (move[0] <= 't')) { // 8〜18列に変換 out_location.J = move[0] - 'b'; } else { out_location.MoveToVanish();// 2015-11-26 追加 return(false); } } } } // 2文字目は、段に使う k = move[1] - '0'; // 3文字目は段 if (2 < move.Length) { k = k * 10 + move[2] - '0'; } out_location.I = taikyoku.GobanBounds.BoardSize - k; if (out_location.ContainsI(0, taikyoku.GobanBounds.BoardEnd)) { return(true); } else { return(false); } }
/// <summary> /// 指定した交点(a)から、四方に接続している石を全て数え上げて、返します。 /// /// aの交点は、人間がコンソールから入力して指定します。 /// </summary> /// <param name="out_connectedStones_asNode">Gnugo1.2 では、listpt という名前のグローバル配列。</param> /// <param name="humanInput_location">Gnugo1.2 では、i,j という変数名。人間がコンソールに入力した交点が入っている。</param> /// <param name="list_neswStones_asNode_eachPoint">Gnugo1.2 では、 movelist という名称。</param> private static void GetConnectedStones_AsNode_FromPoint ( out List <int> out_connectedStones_asNode, GobanPoint humanInput_location, Dictionary <int, List <int> > list_neswStones_asNode_eachPoint, Taikyoku taikyoku ) { out_connectedStones_asNode = new List <int>(); // // この交点は数えたかどうかのフラグです。 // // Gnugo1.2 では color という変数名だったが、石の色と紛らわしいので名称を変更した。 // CheckFlag_Ending[] counted_onBoard = new CheckFlag_Ending[taikyoku.GobanBounds.Nodes]; // // 全ての交点を、まだ数えていないという設定にします。 // for (int node = 0; node < taikyoku.GobanBounds.Nodes; node++) { counted_onBoard[node] = CheckFlag_Ending.Yet; } // // 人間がコンソール入力した交点にある石と、四方がつながっている同じ色の石が // このキューに入っては出て、を連鎖します。 // // Gnugo1.2 では、キューも自作していたが、C#盤では 既存のものを使うように変更。 // Queue queue_connectedNodes = new Queue(150); // 人間が指定した交点は チェック済みにし、キューに追加します。 counted_onBoard[Util_AboutBoard.GetNodeByLocation(humanInput_location, taikyoku.GobanBounds)] = CheckFlag_Ending.Working; queue_connectedNodes.Enqueue(Util_AboutBoard.GetNodeByLocation(humanInput_location, taikyoku.GobanBounds)); #if DEBUG Console.WriteLine("Survived first enqueue in bfslist."); #endif // // キューが空になるまで、処理の連鎖を繰り返します。 // while (queue_connectedNodes.Count != 0) { // まず、人間に指定された交点。(ループの2週目からは、その隣接する石) int node_a = (int)queue_connectedNodes.Dequeue(); // 指定された交点の、存在する北東南西隣の石。(既に調べて配列に入れてあります) for (int nesw = 0; nesw < list_neswStones_asNode_eachPoint[node_a].Count; nesw++)// { // その北東南西隣の石について int node_b = list_neswStones_asNode_eachPoint[node_a][nesw]; // まだ数えていなければ if (counted_onBoard[node_b] == CheckFlag_Ending.Yet) { // その交点には作業中フラグを立て、 // その交点(隣の石)を、次に判定する石としてキューに追加します。連鎖的な動きになります。 counted_onBoard[node_b] = CheckFlag_Ending.Working; queue_connectedNodes.Enqueue(node_b); // } } #if DEBUG Console.WriteLine("Just prior to first dequeue!."); #endif // 人間に指定された交点(ループの2週目からは、その隣接する石)は、 // 数え上げる対象から外し、返却用のリストに追加します。 counted_onBoard[node_a] = CheckFlag_Ending.Finished; out_connectedStones_asNode.Add(node_a); } }
/// <summary> /// 死んでいる石のつながりを、盤上から削除します。 /// /// Gnugo1.2 では、endgame関数。 /// </summary> /// <param name="taikyoku"></param> public static void Remove_DeadPieces(Taikyoku taikyoku) { bool isContinuePhase; // Gnugo1.2 では cont という変数名。continueの略だろうか? // // 最初にコンピューター側を調べ、次に人間側を調べます。 // 盤上の各点の石が、どの方向に隣接する石を持っているかを調べています。 // // コンピューター側 Dictionary <int, List <int> > myList_neswStones_asNode_eachPoint;// Gnugo1.2 では、mymovelist という変数名。int mymovelist[NODES][5]。 Util_EndOfGame.GetNeswStones_AsNode_EachPoint(taikyoku.MyColor, out myList_neswStones_asNode_eachPoint, taikyoku); // 人間側 Dictionary <int, List <int> > yourList_neswStones_asNode_eachPoint;// Gnugo1.2 では、umovelist という変数名。int umovelist[NODES][5];。 Util_EndOfGame.GetNeswStones_AsNode_EachPoint(taikyoku.YourColor, out yourList_neswStones_asNode_eachPoint, taikyoku); isContinuePhase = true; GobanPoint location;// Gnugo1.2 では、 i, j という変数名。 do { Console.Write("Dead piece? "); // 死んでいる石の場所を入力してください。 string an_str = Console.ReadLine(); //scanf("%s", an); //---------------------------------------- // 妥当な入力があるまで、くるくる回します。 //---------------------------------------- {//2015-11-27 追加 bool valid = false; if (an_str == "stop") { valid = true; location = null; } else { valid = PointFugoImpl.TryParse(an_str, out location, taikyoku); } if (!valid) { // 入力が不妥当なので、ループし直し。 goto gt_DeadPieceContinue; } } if (an_str == "stop") { // ループから抜けます。 isContinuePhase = false; goto gt_DeadPieceContinue; } else { if (taikyoku.Goban.At(location) == taikyoku.MyColor) { #if DEBUG Console.WriteLine("Just before bfslist."); #endif List <int> nodeList; Util_EndOfGame.GetConnectedStones_AsNode_FromPoint(out nodeList, location, myList_neswStones_asNode_eachPoint, taikyoku); #if DEBUG Console.WriteLine("Survived first bfslist."); #endif // 示された場所を空にしていき、コンピューターの取られた石カウントを増やします。 foreach (int node in nodeList) { Util_AboutBoard.GetLocationByNode(out location, node, taikyoku.GobanBounds); taikyoku.Goban.Put(location, StoneColor.Empty); taikyoku.Count_MyCaptured++; } } else if (taikyoku.Goban.At(location) == taikyoku.YourColor) { #if DEBUG Console.WriteLine("Just before second bfslist."); #endif List <int> nodeList; Util_EndOfGame.GetConnectedStones_AsNode_FromPoint(out nodeList, location, yourList_neswStones_asNode_eachPoint, taikyoku); // 示された場所を空にしていき、人間の取られた石カウントを増やします。 foreach (int node in nodeList) { Util_AboutBoard.GetLocationByNode(out location, node, taikyoku.GobanBounds); taikyoku.Goban.Put(location, StoneColor.Empty); taikyoku.Count_YourCaptured++; } } ((BoardPrinterB)taikyoku.BoardPrinter).ShowBoard(taikyoku); } gt_DeadPieceContinue: ; }while (isContinuePhase); }
/// <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); } }
/// <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> /// 星のある水平線です。 /// </summary> /// <param name="i"></param> /// <param name="taikyoku"></param> /// <returns></returns> private string CreateBoardLine_Star(int i, Taikyoku taikyoku) { StringBuilder sb = new StringBuilder(); for (int j = 0; j < 3; j++) { GobanPoint location = new GobanPointImpl(i, j); if (taikyoku.Goban.At(location) == StoneColor.Empty) { sb.Append(" -"); } else if (taikyoku.Goban.At(location) == StoneColor.White) { sb.Append(" O"); } else { sb.Append(" X"); } } { int j = 3; GobanPoint location = new GobanPointImpl(i, j); if (taikyoku.Goban.At(location) == StoneColor.Empty) { sb.Append(" +"); } else if (taikyoku.Goban.At(location) == StoneColor.White) { sb.Append(" O"); } else { sb.Append(" X"); } } for (int j = 4; j < 9; j++) { GobanPoint location = new GobanPointImpl(i, j); if (taikyoku.Goban.At(location) == StoneColor.Empty) { sb.Append(" -"); } else if (taikyoku.Goban.At(location) == StoneColor.White) { sb.Append(" O"); } else { sb.Append(" X"); } } { int j = 9; GobanPoint location = new GobanPointImpl(i, j); if (taikyoku.Goban.At(location) == StoneColor.Empty) { sb.Append(" +"); } else if (taikyoku.Goban.At(location) == StoneColor.White) { sb.Append(" O"); } else { sb.Append(" X"); } } for (int j = 10; j < 15; j++) { GobanPoint location = new GobanPointImpl(i, j); if (taikyoku.Goban.At(location) == StoneColor.Empty) { sb.Append(" -"); } else if (taikyoku.Goban.At(location) == StoneColor.White) { sb.Append(" O"); } else { sb.Append(" X"); } } { int j = 15; GobanPoint location = new GobanPointImpl(i, j); if (taikyoku.Goban.At(location) == StoneColor.Empty) { sb.Append(" +"); } else if (taikyoku.Goban.At(location) == StoneColor.White) { sb.Append(" O"); } else { sb.Append(" X"); } } for (int j = 16; j < taikyoku.GobanBounds.BoardSize; j++) { GobanPoint location = new GobanPointImpl(i, j); if (taikyoku.Goban.At(location) == StoneColor.Empty) { sb.Append(" -"); } else if (taikyoku.Goban.At(location) == StoneColor.White) { sb.Append(" O"); } else { sb.Append(" X"); } } return(sb.ToString()); }
/// <summary> /// 取るか、攻撃する相手のピースを探します。 /// /// Gnugo1.2 では findwinner 関数。 /// </summary> /// <param name="out_bestLocation">次の動きの 行、列番号</param> /// <param name="out_bestScore">Gnugo1.2 では *val 引数。評価値</param> /// <param name="libertyOfNodes"> /// カレント色の石のリバティー(四方の石を置けるところ) /// /// Gnugo1.2 では、l という名前のグローバル変数。liberty の略だろうか? /// eval で内容が設定され、その内容は exambord、findsavr、findwinr、suicideで使用されます。 /// </param> /// <param name="taikyoku"></param> /// <returns></returns> public static bool FindBestLocation ( out GobanPoint out_bestLocation, out int out_bestScore, int[,] libertyOfNodes, Taikyoku taikyoku ) { int banSize = taikyoku.GobanBounds.BoardSize; // 要素数 3 以下のリスト。 List <GobanPoint> adj3Locations = new List <GobanPoint>(3); // Gnugo1.2 では、それぞれ要素数[3]の ti配列、tj配列。 int tryScore; // Gnugo1.2 では tval 変数。 out_bestLocation = new GobanPointImpl(-1, -1); // 位置i,j out_bestScore = -1; // 評価値 // // リバティー(四方の置けるところ)が3つ以下の相手(人間)の石を探します。 // つまり、つながっている石(色が異なる石とつながっている場合もあり)か、端にある石ということです。 // for (int m = 0; m < banSize; m++) { for (int n = 0; n < banSize; n++) { GobanPoint iLocation = new GobanPointImpl(m, n); if ( // 相手(人間)の石で、 taikyoku.Goban.At(iLocation) == taikyoku.YourColor && // この石(あるいは連全体)で、呼吸点が3以下のものを選びます。 // 少なくとも 石か枠につながっている石であることを想定しています。 libertyOfNodes[m, n] < 4 ) { // これからフラグを立てていくためにクリアーします。 taikyoku.MarkingBoard.Initmark(taikyoku.GobanBounds.BoardSize); if ( // この石(連ではなく)の開いている方向(1方向〜3方向あるはずです) Util_FindOpen.FindOpen3Locations(adj3Locations, iLocation, taikyoku.YourColor, libertyOfNodes[m, n], taikyoku) ) { if (libertyOfNodes[m, n] == 1) { // アタリの状態なので、積極的に狙っていきます。(呼吸点が、どこか1方向しかない状態) if (out_bestScore < 120) // 評価値が 120 未満なら { // アタリの評価値は 120 点はあります。 // この位置の評価を上げ、ベストムーブとして更新します。 out_bestScore = 120; out_bestLocation.SetLocation(adj3Locations[0]); } } else { // アタリではなくとも。 // 呼吸点の数(2〜たくさん)に応じて。 int opens = libertyOfNodes[m, n]; // わたし(コンピューター)が置いたときと、相手(人間)に置き返されたときの // 全パターンについて // 配列のインデックスが 0,1 や、0,2 や、 1,2 など、異なるペア com,man になるもの // 全てについて。 for (int iCom = 0; iCom < opens; iCom++) //わたし(コンピューター)という想定 { for (int iMan = 0; iMan < opens; iMan++) //相手(人間)という想定 { if (iCom != iMan) { // 置く位置 GobanPoint adjLocation_com = adj3Locations[iCom]; // 置き返す位置 GobanPoint adjLocation_man = adj3Locations[iMan]; // わたしの(連または)石のリバティ int liberty_com; // Gnugo1.2 では、グローバル変数 lib = 0 でした。 Util_CountLiberty.Count(out liberty_com, adjLocation_com, taikyoku.MyColor, taikyoku); if (0 < liberty_com) // 妥当性チェック { // コンピューターの色の石を 位置 a に(試しに)置きます。 taikyoku.Goban.Put(adjLocation_com, taikyoku.MyColor); // look ahead opponent move int liberty_man; // Gnugo1.2 では、グローバル変数 lib = 0 でした。 Util_CountLiberty.Count(out liberty_man, adjLocation_man, taikyoku.YourColor, taikyoku); if ( 1 == liberty_com // 隣接する私(コンピューター)側の(連または)石の呼吸点は1個。 && 0 < liberty_man // 隣接するあなた(人間)側の(連または)石の呼吸点は1個以上。 ) { // 人間側の呼吸点の方が、コンピューター側と同じ、あるいは多いので、 // 位置 a に置く価値なし。 tryScore = 0; } else { // コンピューターが置いた手より、 // 人間が置く手に、呼吸点が同じ、また多い手がない場合、置く価値あり。 tryScore = 120 - 20 * liberty_man; } if (out_bestScore < tryScore) { // より評価値の高い指し手を見つけました。ベストムーブの位置を更新します。 out_bestScore = tryScore; out_bestLocation.SetLocation(adjLocation_com); } // (試しに置いた)石を取り除きます。盤上を元に戻すだけです。 taikyoku.Goban.Put(adjLocation_com, StoneColor.Empty); } } } //v } //u } } } } //n } //m if (0 < out_bestScore) // 指し手を見つけた。 { return(true); } else // 勝者の指し手を見つけるのには失敗した。 { return(false); } }
/// <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> /// セーブファイルを読み込み、局面を復元します。 /// </summary> /// <param name="taikyoku"></param> /// <param name="boardSize">19路盤なら19、9路盤なら9と入れてください。</param> public static void Load(out Taikyoku taikyoku, int boardSize) { BoardPrinterB boardPrinterB; switch (boardSize) { case 9: boardPrinterB = new N9zibanPrinterImpl(); break; default: boardPrinterB = new N19zibanPrinterImpl(); break; } taikyoku = new TaikyokuImpl( boardSize, new ComputerPlayerBImpl(), new BoardImpl(boardSize), new MarkingBoardImpl(boardSize), new CountedBoardImpl(boardSize), boardPrinterB ); string gnugoDatText = File.ReadAllText(taikyoku.SaveFileName); // 盤設定を読み込みます。 for (int i = 0; i < taikyoku.GobanBounds.BoardSize; i++) { for (int j = 0; j < taikyoku.GobanBounds.BoardSize; j++) { taikyoku.Goban.Put(new GobanPointImpl(i, j), Conv_StoneColor.FromNumber(int.Parse(gnugoDatText.Substring(0, 1)))); gnugoDatText = gnugoDatText.Substring(1); //fscanf(fp, "%c", ref ; } } // コンピューターの色、取ったピースズを読み込みます。 int ix; ix = gnugoDatText.IndexOf(" "); taikyoku.MyColor = Conv_StoneColor.FromNumber(int.Parse(gnugoDatText.Substring(0, ix))); gnugoDatText = gnugoDatText.Substring(ix + 1//空白の次へ ); ix = gnugoDatText.IndexOf(" "); taikyoku.Count_MyCaptured = int.Parse(gnugoDatText.Substring(0, ix)); gnugoDatText = gnugoDatText.Substring(ix + 1); ix = gnugoDatText.IndexOf(" "); taikyoku.Count_YourCaptured = int.Parse(gnugoDatText.Substring(0, ix)); gnugoDatText = gnugoDatText.Substring(ix + 1); //fscanf(fp, "%d %d %d ", ref Util_GlobalVar.Mymove, // ref Util_GlobalVar.Mk, ref Util_GlobalVar.Uk); // 序盤定跡フラグを読み込みます。 for (int index = 0; index < 9; index++) { ix = gnugoDatText.IndexOf(" "); taikyoku.OpeningZyosekiFlag[index] = int.Parse(gnugoDatText.Substring(0, ix)) != 0; gnugoDatText = gnugoDatText.Substring(ix + 1); //fscanf(fp, "%d ", ref Util_GlobalVar.Opn[i]); } //fclose(fp); taikyoku.YourColor = Conv_StoneColor.FromNumber(3 - (int)taikyoku.MyColor); }
/// <summary> /// 次の動きのためにマッチする定石(パターン)を探します。 /// /// Gnugo1.2 では findpatn関数。 /// </summary> /// <param name="out_location">次の動きの 行、列番号</param> /// <param name="out_score">Gnugo1.2 では val 引数。次の指し手の評価値</param> /// <param name="taikyoku"></param> /// <returns></returns> public static bool FindPattern ( out GobanPoint out_location, out int out_score, Taikyoku taikyoku ) { GobanPoint tryLocation; // Gnugo1.2 では、ti,tj という変数名 int tryScore; // Gnugo1.2 では、tval という変数名。 // // オープニングの定石は、盤面全体のものです。 // // まず、序盤で占領(オキュパイ;occupy)できる角(corners)を狙い、 // 次に、開いている四辺を狙っていきます。 // //---------------------------------------- // 定石[4] 最後の動きの続き //---------------------------------------- // // 初回はOFFです。他の定石が順調に進んでいるとき、このフラグが立っています。 // if (taikyoku.OpeningZyosekiFlag[4]) { taikyoku.OpeningZyosekiFlag[4] = false; // この定石をOFFにします。 // 前回のデータを取り出します。 int cnd = ((ComputerPlayerB)taikyoku.ComputerPlayer).NodeNo; MoveType movetype = ((ComputerPlayerB)taikyoku.ComputerPlayer).Movetype; if (OpeningZyosekiImpl.Opening(out out_location, ref cnd, movetype, taikyoku)) { taikyoku.OpeningZyosekiFlag[4] = true; // もっと動くなら、この定石をONにリセットします。 } ((ComputerPlayerB)taikyoku.ComputerPlayer).NodeNo = cnd; if (taikyoku.Goban.At(out_location) == StoneColor.Empty) // 置けるなら { out_score = Util_FindOpeningZyoseki.ZYOSEKI_SCORE; // 定石の評価値 return(true); } else { // 石を置けなかったら、この定石も終わります。 taikyoku.OpeningZyosekiFlag[4] = false; } } //---------------------------------------- // 定石[0] 西北の角 //---------------------------------------- if (taikyoku.OpeningZyosekiFlag[0]) { taikyoku.OpeningZyosekiFlag[0] = false; // フラグをクリアー。 if (Util_EmptyRectangle.IsEmptyRectangle(new GobanPointImpl(0, 0), new GobanPointImpl(5, 5), taikyoku)) { int cnd = 0; MoveType movetype = MoveType.Basic; OpeningZyosekiImpl.Opening(out out_location, ref cnd, movetype, taikyoku); // 次の手のための新しいノードを取得します。 if (OpeningZyosekiImpl.Opening(out out_location, ref cnd, movetype, taikyoku)) { taikyoku.OpeningZyosekiFlag[4] = true; } ((ComputerPlayerB)taikyoku.ComputerPlayer).NodeNo = cnd; ((ComputerPlayerB)taikyoku.ComputerPlayer).Movetype = movetype; out_score = Util_FindOpeningZyoseki.ZYOSEKI_SCORE; // 評価値 return(true); } } //---------------------------------------- // 定石[1] 南西の角 //---------------------------------------- if (taikyoku.OpeningZyosekiFlag[1]) { taikyoku.OpeningZyosekiFlag[1] = false; if (Util_EmptyRectangle.IsEmptyRectangle(new GobanPointImpl(13, 0), new GobanPointImpl(18, 5), taikyoku)) { int cnd = 0; MoveType movetype = MoveType.Inverted; OpeningZyosekiImpl.Opening(out out_location, ref cnd, movetype, taikyoku); // 次の手のための新しいノードを取得します。 if (OpeningZyosekiImpl.Opening(out out_location, ref cnd, movetype, taikyoku)) { taikyoku.OpeningZyosekiFlag[4] = true; } ((ComputerPlayerB)taikyoku.ComputerPlayer).NodeNo = cnd; ((ComputerPlayerB)taikyoku.ComputerPlayer).Movetype = movetype; out_score = Util_FindOpeningZyoseki.ZYOSEKI_SCORE; // 評価値 return(true); } } //---------------------------------------- // 定石[2] 北東の角 //---------------------------------------- if (taikyoku.OpeningZyosekiFlag[2]) { taikyoku.OpeningZyosekiFlag[2] = false; if (Util_EmptyRectangle.IsEmptyRectangle(new GobanPointImpl(0, 13), new GobanPointImpl(5, 18), taikyoku)) { int cnd = 0; MoveType movetype = MoveType.Reflected; OpeningZyosekiImpl.Opening(out out_location, ref cnd, movetype, taikyoku); // 次の手のための新しいノードを取得します。 if (OpeningZyosekiImpl.Opening(out out_location, ref cnd, movetype, taikyoku)) { taikyoku.OpeningZyosekiFlag[4] = true; } ((ComputerPlayerB)taikyoku.ComputerPlayer).NodeNo = cnd; ((ComputerPlayerB)taikyoku.ComputerPlayer).Movetype = movetype; out_score = Util_FindOpeningZyoseki.ZYOSEKI_SCORE; // 評価値 return(true); } } //---------------------------------------- // 定石[3] 南東の角 //---------------------------------------- if (taikyoku.OpeningZyosekiFlag[3]) { taikyoku.OpeningZyosekiFlag[3] = false; if (Util_EmptyRectangle.IsEmptyRectangle(new GobanPointImpl(13, 13), new GobanPointImpl(18, 18), taikyoku)) { int cnd = 0; MoveType movetype = MoveType.Inverted_And_Reflected; OpeningZyosekiImpl.Opening(out out_location, ref cnd, movetype, taikyoku); // 次の手のための新しいノードを取得します。 if (OpeningZyosekiImpl.Opening(out out_location, ref cnd, movetype, taikyoku)) { taikyoku.OpeningZyosekiFlag[4] = true; } ((ComputerPlayerB)taikyoku.ComputerPlayer).NodeNo = cnd; ((ComputerPlayerB)taikyoku.ComputerPlayer).Movetype = movetype; out_score = Util_FindOpeningZyoseki.ZYOSEKI_SCORE; // 評価値 return(true); } } // // 辺(edges)のオキュパイ(occupy) // //---------------------------------------- // 定石[5] 北辺 //---------------------------------------- // // 碁番の北側の矩形領域が空っぽなら、打ち込む場所の定石が1つあります。この定石はこの1箇所だけです。 // if (taikyoku.OpeningZyosekiFlag[5]) { taikyoku.OpeningZyosekiFlag[5] = false; if (Util_EmptyRectangle.IsEmptyRectangle(new GobanPointImpl(0, 6), new GobanPointImpl(4, 11), taikyoku)) { out_location = new GobanPointImpl(3, 9); // 次の指し手の位置i,j out_score = Util_FindOpeningZyoseki.ZYOSEKI_SCORE; // 評価値 return(true); } } //---------------------------------------- // 定石[6] 南辺 //---------------------------------------- // // 碁番の南側の矩形領域が空っぽなら、打ち込む場所の定石が1つあります。この定石はこの1箇所だけです。 // if (taikyoku.OpeningZyosekiFlag[6]) { taikyoku.OpeningZyosekiFlag[6] = false; if (Util_EmptyRectangle.IsEmptyRectangle(new GobanPointImpl(18, 6), new GobanPointImpl(14, 11), taikyoku)) { out_location = new GobanPointImpl(15, 9); // 次の指し手の位置i,j out_score = Util_FindOpeningZyoseki.ZYOSEKI_SCORE; // 評価値 return(true); } } //---------------------------------------- // 定石[7] 西辺 //---------------------------------------- // // 碁番の西側の矩形領域が空っぽなら、打ち込む場所の定石が1つあります。この定石はこの1箇所だけです。 // if (taikyoku.OpeningZyosekiFlag[7]) { taikyoku.OpeningZyosekiFlag[7] = false; if (Util_EmptyRectangle.IsEmptyRectangle(new GobanPointImpl(6, 0), new GobanPointImpl(11, 4), taikyoku)) { out_location = new GobanPointImpl(9, 3); // 次の指し手の位置i,j out_score = Util_FindOpeningZyoseki.ZYOSEKI_SCORE; // 評価値 return(true); } } //---------------------------------------- // 定石[8] 東辺 //---------------------------------------- // // 碁番の東側の矩形領域が空っぽなら、打ち込む場所の定石が1つあります。この定石はこの1箇所だけです。 // if (taikyoku.OpeningZyosekiFlag[8]) { taikyoku.OpeningZyosekiFlag[8] = false; if (Util_EmptyRectangle.IsEmptyRectangle(new GobanPointImpl(6, 18), new GobanPointImpl(11, 14), taikyoku)) { out_location = new GobanPointImpl(9, 15); // 次の指し手の位置i,j out_score = Util_FindOpeningZyoseki.ZYOSEKI_SCORE; // 評価値 return(true); } } // // 序盤定石のどれにも当てはまらなければ。 // out_location = new GobanPointImpl(-1, -1); out_score = -1; // // 局地的な定石を探します。 // for (int m = 0; m < taikyoku.GobanBounds.BoardSize; m++) { for (int n = 0; n < taikyoku.GobanBounds.BoardSize; n++) { GobanPoint mnLocation = new GobanPointImpl(m, n); if ( taikyoku.Goban.At(mnLocation) == taikyoku.MyColor // コンピューターの石 && Util_FindLocalZyoseki.FindPattern(out tryLocation, out tryScore, mnLocation, taikyoku) && out_score < tryScore // 評価値が高ければ ) { out_score = tryScore; // 評価値 out_location.SetLocation(tryLocation); // 次の指し手の位置i,j } } } if (out_score > 0) // 定石(パターン)を見つけました。 { return(true); } else // 定石は見つかりませんでした。 { return(false); } }
/// <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); } }
/// <summary> /// もし、幾つかのピースズが脅かされているなら、動きを探します。 /// /// Gnugo1.2 では findsaver 関数。 /// </summary> /// <param name="out_bestLocation">次の指し手の 行、列番号</param> /// <param name="out_maxScore">Gnugo1.2 では、val 引数。次の指し手の評価値</param> /// <param name="libertyOfNodes"> /// カレント色の(1つ、または連の)石のリバティー(四方の石を置けるところ) /// /// Gnugo1.2 では、l という名前のグローバル変数。liberty の略だろうか? /// eval で内容が設定され、その内容は exambord、findsavr、findwinr、suicideで使用されます。 /// </param> /// <param name="taikyoku"></param> /// <returns></returns> public static bool FindLocation_LibertyWeak ( out GobanPoint out_bestLocation, out int out_maxScore, int[,] libertyOfNodes, Taikyoku taikyoku ) { Board ban = taikyoku.Goban; // 碁盤 int banSize = taikyoku.GobanBounds.BoardSize; //何路盤 out_bestLocation = new GobanPointImpl(-1, -1); // 位置i,j out_maxScore = -1; // 評価値 // // まず リバティが1つ、 // 次に リバティが2つ、 // と、リバティの少ない方から順に評価を付けていきます。 // 盤面を4回探し回ることになります。 // for (int iExpectedLiberty = 1; iExpectedLiberty < 4; iExpectedLiberty++)// リバティー 1〜3 のループカウンター。Gnugo1.2 では minlib 変数。 { // 最小リバティーといっしょのピースを数えます。 for (int m = 0; m < banSize; m++) { for (int n = 0; n < banSize; n++) { GobanPoint iLocation = new GobanPointImpl(m, n);//検索中の位置。 if ( ban.At(iLocation) == taikyoku.MyColor // 脅かされているかもしれない自分(コンピューター)の色 && libertyOfNodes[m, n] == iExpectedLiberty // 呼吸点の数が少ないかもしれない ) { GobanPoint bestLocation; // Gnugo1.2 では、ti,tj (try i,j)という変数名。 int bestScore; // Gnugo1.2 では、tval 変数。評価値 // セーブ・ピースズへの動きを探します。 taikyoku.MarkingBoard.Initmark(taikyoku.GobanBounds.BoardSize); if ( Util_SasiteNext.FindStone_LibertyWeak(out bestLocation, out bestScore, iLocation, iExpectedLiberty, taikyoku) && (out_maxScore < bestScore) // 評価値が高い(リバティーが少なくて危険)ならば ) { out_maxScore = bestScore; // 評価値 out_bestLocation.SetLocation(bestLocation); // 位置i,j } } } } } if (0 < out_maxScore) // 動きが見つかれば { return(true); } else // 動きが見つからなかったら { return(false); } }
/// <summary> /// ハンディーキャップ・ピースズをセットアップします。 /// /// Gnugo1.2 では、 sethand という関数です。 /// </summary> /// <param name="handicap"></param> /// <param name="taikyoku"></param> public static void DoHandicap(int handicap, Taikyoku taikyoku) { if (0 < handicap) { taikyoku.Goban.Put(new GobanPointImpl(2, 2), StoneColor.Black); } else { goto gt_EndMethod; } if (1 < handicap) { taikyoku.Goban.Put(new GobanPointImpl(6, 6), StoneColor.Black); } else { goto gt_EndMethod; } if (2 < handicap) { taikyoku.Goban.Put(new GobanPointImpl(2, 6), StoneColor.Black); } else { goto gt_EndMethod; } if (3 < handicap) { taikyoku.Goban.Put(new GobanPointImpl(6, 2), StoneColor.Black); } else { goto gt_EndMethod; } if (handicap == 5) { taikyoku.Goban.Put(new GobanPointImpl(4, 4), StoneColor.Black); goto gt_EndMethod; } if (5 < handicap) { taikyoku.Goban.Put(new GobanPointImpl(4, 6), StoneColor.Black); taikyoku.Goban.Put(new GobanPointImpl(4, 2), StoneColor.Black); } else { goto gt_EndMethod; } if (7 == handicap) { taikyoku.Goban.Put(new GobanPointImpl(4, 4), StoneColor.Black); goto gt_EndMethod; } if (7 < handicap) { // ハンディキャップ 8以上 は、 9,9 に置く前に 15,9、3,9 の位置。 taikyoku.Goban.Put(new GobanPointImpl(6, 4), StoneColor.Black); taikyoku.Goban.Put(new GobanPointImpl(2, 4), StoneColor.Black); } else { goto gt_EndMethod; } if (8 < handicap) { taikyoku.Goban.Put(new GobanPointImpl(4, 4), StoneColor.Black); } else { goto gt_EndMethod; } if (9 < handicap) { taikyoku.Goban.Put(new GobanPointImpl(1, 1), StoneColor.Black); } else { goto gt_EndMethod; } if (10 < handicap) { taikyoku.Goban.Put(new GobanPointImpl(7, 7), StoneColor.Black); } else { goto gt_EndMethod; } if (11 < handicap) { taikyoku.Goban.Put(new GobanPointImpl(1, 7), StoneColor.Black); } else { goto gt_EndMethod; } if (12 < handicap) { taikyoku.Goban.Put(new GobanPointImpl(7, 1), StoneColor.Black); } else { goto gt_EndMethod; } if (13 < handicap) { taikyoku.Goban.Put(new GobanPointImpl(3, 3), StoneColor.Black); } else { goto gt_EndMethod; } if (14 < handicap) { taikyoku.Goban.Put(new GobanPointImpl(5, 5), StoneColor.Black); } else { goto gt_EndMethod; } if (15 < handicap) { taikyoku.Goban.Put(new GobanPointImpl(3, 5), StoneColor.Black); } else { goto gt_EndMethod; } if (16 < handicap) { taikyoku.Goban.Put(new GobanPointImpl(5, 3), StoneColor.Black); } gt_EndMethod: ; }
/// <summary> /// 碁盤を見せます。19路盤です。 /// /// Gnugo1.2 では showboard という関数です。 /// </summary> /// <param name="taikyoku"></param> public void ShowBoard(Taikyoku taikyoku) { // p = 0 for empty , // p = 1 for white piece, // p = 2 for black piece Console.WriteLine(" A B C D E F G H J K L M N O P Q R S T"); // 行 19〜17 for (int i = 0; i < 3; i++) { int ii = taikyoku.GobanBounds.BoardSize - i; Console.Write("{0,2}", ii); Console.Write(this.CreateBoardLine_Normal(i, taikyoku)); Console.WriteLine("{0,2}", ii); } //---------------------------------------- // 行 16 //---------------------------------------- // // 16行目には、星があるのでいったん区切ります。また、「あなたの色は〜」の表記があります。 // Console.Write("16"); Console.Write(this.CreateBoardLine_Star(taikyoku.GobanBounds.BoardSize - 16, taikyoku)); Console.Write("16"); if (taikyoku.YourColor == StoneColor.White) { Console.WriteLine(" Your color: White O"); } else if (taikyoku.YourColor == StoneColor.Black) { Console.WriteLine(" Your color: Black X"); } else { Console.WriteLine(); } //---------------------------------------- // 行 15〜11 //---------------------------------------- // // 15行目には、「わたしの色は〜」の表記があります。 // for (int i = 4; i < 9; i++) { int ii = taikyoku.GobanBounds.BoardSize - i; Console.Write("{0,2}", ii); Console.Write(this.CreateBoardLine_Normal(i, taikyoku)); Console.Write("{0,2}", ii); if (i == 4) { if (taikyoku.MyColor == StoneColor.White) { Console.WriteLine(" My color: White O"); } else if (taikyoku.MyColor == StoneColor.Black) { Console.WriteLine(" My color: Black X"); } else { Console.WriteLine(); } } else if (i == 8) { Console.WriteLine(" You have captured {0} pieces", taikyoku.Count_MyCaptured); } else { Console.WriteLine(); } } //---------------------------------------- // 行 10 //---------------------------------------- // // 10行目には、星があるのでいったん区切ります。また、「わたしの取った駒は〜」の表記があります。 // Console.Write("10"); Console.Write(this.CreateBoardLine_Star(taikyoku.GobanBounds.BoardSize - 10, taikyoku)); Console.Write("10"); Console.WriteLine(" I have captured {0} pieces", taikyoku.Count_YourCaptured); //---------------------------------------- // 行 9〜5 //---------------------------------------- for (int i = 10; i < 15; i++) { int ii = taikyoku.GobanBounds.BoardSize - i; Console.Write("{0,2}", ii); Console.Write(this.CreateBoardLine_Normal(i, taikyoku)); Console.WriteLine("{0,2}", ii); } // 行 4 Console.Write(" 4"); Console.Write(this.CreateBoardLine_Star(taikyoku.GobanBounds.BoardSize - 4, taikyoku)); Console.Write(" 4"); Console.WriteLine(); // 行 3〜1 for (int i = 16; i < taikyoku.GobanBounds.BoardSize; i++) { int ii = taikyoku.GobanBounds.BoardSize - i; Console.Write("{0,2}", ii); Console.Write(this.CreateBoardLine_Normal(i, taikyoku)); Console.Write("{0,2}", ii); Console.WriteLine(); } Console.WriteLine(" A B C D E F G H J K L M N O P Q R S T"); Console.WriteLine(); }