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