/// <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> /// 指定した交点(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> /// 序盤定石以外の、局地的な定石にあてはまるかをしらべ、定石があれば置く場所を取得します。 /// </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); } }