00001
00002
00003
00004
00005 #ifndef GOUCT_UTIL_H
00006 #define GOUCT_UTIL_H
00007
00008 #include <iosfwd>
00009 #include "GoBoard.h"
00010 #include "GoBoardUtil.h"
00011 #include "GoEyeUtil.h"
00012 #include "GoModBoard.h"
00013 #include "GoUctBoard.h"
00014 #include "SgBlackWhite.h"
00015 #include "SgPoint.h"
00016 #include "SgRandom.h"
00017 #include "SgUctSearch.h"
00018 #include "SgUtil.h"
00019
00020 class SgBWSet;
00021 template<typename T,int N> class SgArrayList;
00022 class SgUctNode;
00023 class SgUctTree;
00024
00025
00026
00027
00028
00029
00030 namespace GoUctUtil
00031 {
00032
00033 const bool REMOVE_SELF_ATARI = false;
00034
00035
00036 const bool REMOVE_MUTUAL_ATARI = true;
00037
00038 const int SELF_ATARI_LIMIT = 8;
00039
00040 const int MUTUAL_ATARI_LIMIT = 2;
00041
00042
00043
00044
00045 const bool CONSERVATIVE_CLUMP = true;
00046
00047
00048 const int LINE_1_LIMIT = CONSERVATIVE_CLUMP ? 4 : 3;
00049
00050
00051 const int LINE_2_OR_MORE_LIMIT = CONSERVATIVE_CLUMP ? 6 : 5;
00052
00053 void ClearStatistics(SgPointArray<SgUctStatistics>& stats);
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075 template<class BOARD>
00076 bool DoSelfAtariCorrection(const BOARD& bd, SgPoint& p);
00077
00078
00079
00080
00081
00082 template<class BOARD>
00083 bool DoClumpCorrection(const BOARD& bd, SgPoint& p);
00084
00085
00086
00087
00088 template<class BOARD>
00089 bool GainsLiberties(const BOARD& bd, SgPoint anchor, SgPoint lib);
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105 SgPoint GenForcedOpeningMove(const GoBoard& bd);
00106
00107
00108
00109
00110
00111
00112
00113 template<class BOARD>
00114 bool GeneratePoint(const BOARD& bd, SgBalancer& balancer, SgPoint p,
00115 SgBlackWhite toPlay);
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125 void GfxBestMove(const SgUctSearch& search, SgBlackWhite toPlay,
00126 std::ostream& out);
00127
00128
00129
00130
00131
00132
00133
00134 void GfxCounts(const SgUctTree& tree, std::ostream& out);
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144 void GfxMoveValues(const SgUctSearch& search, SgBlackWhite toPlay,
00145 std::ostream& out);
00146
00147
00148 void GfxSequence(const SgUctSearch& search, SgBlackWhite toPlay,
00149 std::ostream& out);
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164 void GfxStatus(const SgUctSearch& search, std::ostream& out);
00165
00166
00167
00168
00169
00170 void GfxTerritoryStatistics(
00171 const SgPointArray<SgUctStatistics>& territoryStatistics,
00172 const GoBoard& bd, std::ostream& out);
00173
00174
00175 template<class BOARD>
00176 bool IsMutualAtari(const BOARD& bd, SgBalancer& balancer, SgPoint p,
00177 SgBlackWhite toPlay);
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189 void SaveTree(const SgUctTree& tree, int boardSize, const SgBWSet& stones,
00190 SgBlackWhite toPlay, std::ostream& out, int maxDepth = -1);
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205 template<class BOARD>
00206 SgPoint SelectRandom(const BOARD& bd, SgBlackWhite toPlay,
00207 GoPointList& emptyPts,
00208 SgRandom& random, SgBalancer& balancer);
00209
00210
00211 template<class BOARD>
00212 void SetEdgeCorrection(const BOARD& bd, SgPoint p, int& edgeCorrection);
00213
00214
00215
00216
00217
00218 std::string ChildrenStatistics(const SgUctSearch& search,
00219 bool bSort, const SgUctNode& node);
00220
00221
00222 template<class BOARD>
00223 bool SubsetOfBlocks(const BOARD& bd, const SgPoint anchor[], SgPoint nb);
00224 }
00225
00226
00227
00228 template<class BOARD>
00229 bool GoUctUtil::DoClumpCorrection(const BOARD& bd, SgPoint& p)
00230 {
00231
00232 if (bd.NumEmptyNeighbors(p) != 1)
00233 return false;
00234 const SgBlackWhite toPlay = bd.ToPlay();
00235 if (bd.Line(p) == 1)
00236 {
00237 if ( bd.Num8Neighbors(p, toPlay) < LINE_1_LIMIT
00238 || bd.NumNeighbors(p, toPlay) != 2
00239 )
00240 return false;
00241 }
00242 else if ( bd.Num8Neighbors(p, toPlay) < LINE_2_OR_MORE_LIMIT
00243 || bd.NumNeighbors(p, toPlay) != 3
00244 )
00245 return false;
00246
00247
00248 const SgPoint nb = GoEyeUtil::EmptyNeighbor(bd, p);
00249 int edgeCorrection_p = 0;
00250 int edgeCorrection_nb = 0;
00251 SetEdgeCorrection(bd, p, edgeCorrection_p);
00252 SetEdgeCorrection(bd, nb, edgeCorrection_nb);
00253 if ( bd.Num8Neighbors(nb, toPlay) + edgeCorrection_nb <
00254 bd.Num8Neighbors(p, toPlay) + edgeCorrection_p
00255 && bd.NumNeighbors(nb, toPlay) <= bd.NumNeighbors(p, toPlay)
00256 &&
00257 ( bd.NumEmptyNeighbors(nb) >= 2
00258 || ! GoBoardUtil::SelfAtari(bd, nb)
00259 )
00260 )
00261 {
00262 if (CONSERVATIVE_CLUMP)
00263 {
00264 p = nb;
00265 return true;
00266 }
00267 else
00268 {
00269
00270
00271 SgPoint anchor[4 + 1];
00272 bd.NeighborBlocks(p, toPlay, anchor);
00273 SG_ASSERT(anchor[0] != SG_ENDPOINT);
00274 if (anchor[1] == SG_ENDPOINT
00275 || SubsetOfBlocks<BOARD>(bd, anchor, nb))
00276 {
00277 p = nb;
00278 return true;
00279 }
00280 }
00281 }
00282 return false;
00283 }
00284
00285 template<class BOARD>
00286 inline bool GoUctUtil::DoSelfAtariCorrection(const BOARD& bd, SgPoint& p)
00287 {
00288
00289
00290
00291 const SgBlackWhite toPlay = bd.ToPlay();
00292
00293 if (bd.NumEmptyNeighbors(p) >= 2)
00294 return false;
00295 if (bd.NumNeighbors(p, toPlay) > 0)
00296 {
00297 if (! GoBoardUtil::SelfAtari(bd, p))
00298 return false;
00299 SgBlackWhite opp = SgOppBW(toPlay);
00300 SgPoint replaceMove = SG_NULLMOVE;
00301
00302 for (SgNb4Iterator it(p); it; ++it)
00303 {
00304 SgBoardColor c = bd.GetColor(*it);
00305 if (c == SG_EMPTY)
00306 replaceMove = *it;
00307 else if (c == toPlay)
00308 {
00309 for (typename BOARD::LibertyIterator it2(bd, *it); it2; ++it2)
00310 if (*it2 != p)
00311 {
00312 replaceMove = *it2;
00313 break;
00314 }
00315 }
00316 else if (c == opp && bd.InAtari(*it))
00317 replaceMove = *it;
00318 if (replaceMove != SG_NULLMOVE)
00319 break;
00320 }
00321 SG_ASSERT(replaceMove != SG_NULLMOVE);
00322 if ( bd.IsLegal(replaceMove)
00323 && ! GoBoardUtil::SelfAtari(bd, replaceMove)
00324 )
00325 {
00326 p = replaceMove;
00327 return true;
00328 }
00329 }
00330 else if (bd.NumEmptyNeighbors(p) > 0 && ! bd.CanCapture(p, toPlay))
00331
00332 {
00333
00334 const SgPoint nb = GoEyeUtil::EmptyNeighbor(bd, p);
00335
00336
00337 if ( bd.IsLegal(nb)
00338 && ( bd.NumEmptyNeighbors(nb) >= 2
00339 || bd.CanCapture(nb, toPlay)
00340 )
00341 )
00342 {
00343
00344 p = nb;
00345 return true;
00346 }
00347 }
00348
00349 return false;
00350 }
00351
00352 template<class BOARD>
00353 bool GoUctUtil::GainsLiberties(const BOARD& bd, SgPoint anchor, SgPoint lib)
00354 {
00355 SG_ASSERT(bd.IsEmpty(lib));
00356 SG_ASSERT(bd.Anchor(anchor) == anchor);
00357 const SgBlackWhite color = bd.GetStone(anchor);
00358 int nu = -2;
00359 for (SgNb4Iterator it(lib); it; ++it)
00360 {
00361 SgEmptyBlackWhite c = bd.GetColor(*it);
00362 if (c == SG_EMPTY)
00363 {
00364 if (! bd.IsLibertyOfBlock(*it, anchor))
00365 if (++nu >= 0)
00366 return true;
00367 }
00368 else if (c == color)
00369 {
00370 const SgPoint anchor2 = bd.Anchor(*it);
00371 if (anchor != anchor2)
00372 for (typename BOARD::LibertyIterator it(bd, anchor2); it;
00373 ++it)
00374 if (! bd.IsLibertyOfBlock(*it, anchor))
00375 if (++nu >= 0)
00376 return true;
00377 }
00378
00379 }
00380 return false;
00381 }
00382
00383 template<class BOARD>
00384 inline bool GoUctUtil::IsMutualAtari(const BOARD& bd, SgBalancer& balancer,
00385 SgPoint p, SgBlackWhite toPlay)
00386 {
00387 int nuStones = 0;
00388 if ( GoBoardUtil::SelfAtari(bd, p, nuStones)
00389 && nuStones > MUTUAL_ATARI_LIMIT
00390 && ( nuStones > GoEyeUtil::NAKADE_LIMIT
00391 || ! GoEyeUtil::MakesNakadeShape(bd, p, toPlay)
00392 )
00393 )
00394 {
00395 SG_ASSERT(bd.ToPlay() == toPlay);
00396 SgBlackWhite opp = SgOppBW(toPlay);
00397 bool selfatari =
00398 bd.HasNeighbors(p, opp) &&
00399 GoBoardUtil::SelfAtariForColor(bd, p, opp);
00400 if (selfatari && balancer.Play(toPlay))
00401 {
00402
00403
00404
00405
00406
00407 return true;
00408 }
00409 }
00410 return false;
00411 }
00412
00413 template<class BOARD>
00414 inline bool GoUctUtil::GeneratePoint(const BOARD& bd, SgBalancer& balancer,
00415 SgPoint p, SgBlackWhite toPlay)
00416 {
00417 SG_ASSERT(bd.IsEmpty(p));
00418 SG_ASSERT(bd.ToPlay() == toPlay);
00419 if ( GoBoardUtil::IsCompletelySurrounded(bd, p)
00420
00421 || ! bd.IsLegal(p, toPlay)
00422 )
00423 return false;
00424 if (REMOVE_SELF_ATARI)
00425 {
00426 int nuStones = 0;
00427 if ( GoBoardUtil::SelfAtari(bd, p, nuStones)
00428 && nuStones > SELF_ATARI_LIMIT
00429
00430 )
00431 {
00432
00433
00434 return false;
00435 }
00436 }
00437
00438 if (REMOVE_MUTUAL_ATARI && IsMutualAtari(bd, balancer, p, toPlay))
00439 return false;
00440 return true;
00441 }
00442
00443 template<class BOARD>
00444 inline SgPoint GoUctUtil::SelectRandom(const BOARD& bd,
00445 SgBlackWhite toPlay,
00446 GoPointList& emptyPts,
00447 SgRandom& random,
00448 SgBalancer& balancer)
00449 {
00450 while (true)
00451 {
00452 int length = emptyPts.Length();
00453 if (length == 0)
00454 break;
00455 int index = random.SmallInt(length);
00456 SgPoint p = emptyPts[index];
00457 SG_ASSERT(bd.IsEmpty(p));
00458 if (GeneratePoint(bd, balancer, p, toPlay))
00459 return p;
00460 emptyPts[index] = emptyPts[length - 1];
00461 emptyPts.PopBack();
00462 }
00463 return SG_NULLMOVE;
00464 }
00465
00466 template<class BOARD>
00467 void GoUctUtil::SetEdgeCorrection(const BOARD& bd, SgPoint p,
00468 int& edgeCorrection)
00469 {
00470 if (bd.Line(p) == 1)
00471 {
00472 edgeCorrection += 3;
00473 if (bd.Pos(p) == 1)
00474 edgeCorrection += 2;
00475 }
00476 }
00477
00478
00479 template<class BOARD>
00480 bool GoUctUtil::SubsetOfBlocks(const BOARD& bd, const SgPoint anchor[],
00481 SgPoint nb)
00482 {
00483 SgPoint nbanchor[4 + 1];
00484 bd.NeighborBlocks(nb, bd.ToPlay(), nbanchor);
00485 if (nbanchor[0] == SG_ENDPOINT)
00486 return false;
00487 for (int i = 0; anchor[i] != SG_ENDPOINT; ++i)
00488 if (! GoBoardUtil::ContainsAnchor(nbanchor, anchor[i]))
00489 return false;
00490 return true;
00491 }
00492
00493
00494
00495 #endif // GOUCT_UTIL_H