00001
00002
00003
00004
00005
00006 #include "Time.hpp"
00007 #include "BitsetIterator.hpp"
00008 #include "ICEngine.hpp"
00009 #include "BoardUtils.hpp"
00010
00011 #include "boost/filesystem/path.hpp"
00012
00013 using namespace benzene;
00014
00015
00016
00017 namespace {
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 bitset_t ComputeEdgeUnreachableRegions(const StoneBoard& brd, HexColor c,
00029 const bitset_t& stopSet,
00030 bool flowFrom1=true,
00031 bool flowFrom2=true)
00032 {
00033 bitset_t reachable1, reachable2;
00034 bitset_t flowSet = (brd.GetEmpty() | brd.GetColor(c))
00035 & brd.Const().GetCells();
00036 if (flowFrom1)
00037 {
00038 bitset_t flowSet1 = flowSet;
00039 flowSet1.set(HexPointUtil::colorEdge1(c));
00040 reachable1
00041 = BoardUtils::ReachableOnBitset(brd.Const(), flowSet1, stopSet,
00042 HexPointUtil::colorEdge1(c));
00043 }
00044 if (flowFrom2)
00045 {
00046 bitset_t flowSet2 = flowSet;
00047 flowSet2.set(HexPointUtil::colorEdge2(c));
00048 reachable2
00049 = BoardUtils::ReachableOnBitset(brd.Const(), flowSet2, stopSet,
00050 HexPointUtil::colorEdge2(c));
00051 }
00052 return brd.GetEmpty() - (reachable1 | reachable2);
00053 }
00054
00055
00056
00057
00058
00059 bitset_t ComputeDeadRegions(const Groups& groups)
00060 {
00061 const StoneBoard& brd = groups.Board();
00062 if (groups.IsGameOver())
00063 return brd.GetEmpty();
00064
00065 bitset_t dead;
00066 for (GroupIterator i(groups, NOT_EMPTY); i; ++i)
00067 {
00068
00069
00070
00071 if (i->Size() == 1)
00072 continue;
00073
00074 HexColor c = i->Color();
00075 HexAssert(HexColorUtil::isBlackWhite(c));
00076
00077
00078
00079
00080
00081 bitset_t cliqueCutset = i->Nbs() & brd.GetEmpty();
00082 dead |= ComputeEdgeUnreachableRegions(brd, c, cliqueCutset,
00083 i->Captain() != HexPointUtil::colorEdge1(c),
00084 i->Captain() != HexPointUtil::colorEdge2(c));
00085 }
00086
00087
00088 HexAssert(BitsetUtil::IsSubsetOf(dead, brd.GetEmpty()));
00089 return dead;
00090 }
00091
00092
00093
00094
00095 bitset_t FindType1Cliques(const Groups& groups)
00096 {
00097 bitset_t dead;
00098 const StoneBoard& brd = groups.Board();
00099 bitset_t empty = brd.GetEmpty();
00100
00101
00102 for (BitsetIterator x(empty); x; ++x) {
00103 for (BitsetIterator y(empty); *y != *x; ++y) {
00104 if (brd.Const().Adjacent(*x, *y)) continue;
00105 bitset_t xyNbs
00106 = groups.Nbs(*x, NOT_EMPTY) & groups.Nbs(*y, NOT_EMPTY);
00107 if (xyNbs.none()) continue;
00108
00109
00110
00111 for (BitsetIterator z(empty); z; ++z) {
00112 if (!brd.Const().Adjacent(*x, *z)) continue;
00113 if (!brd.Const().Adjacent(*y, *z)) continue;
00114 HexAssert(*x != *z);
00115 HexAssert(*y != *z);
00116 bitset_t xyExclusiveNbs = xyNbs - groups.Nbs(*z, NOT_EMPTY);
00117 if (xyExclusiveNbs.none()) continue;
00118
00119
00120 bitset_t clique;
00121 clique.set(*x);
00122 clique.set(*y);
00123 clique.set(*z);
00124
00125
00126
00127 if ((xyExclusiveNbs & brd.GetBlack()).any()) {
00128 dead |= ComputeEdgeUnreachableRegions(brd, BLACK, clique);
00129 HexAssert(BitsetUtil::IsSubsetOf(dead, empty));
00130 }
00131 if ((xyExclusiveNbs & brd.GetWhite()).any()) {
00132 dead |= ComputeEdgeUnreachableRegions(brd, WHITE, clique);
00133 HexAssert(BitsetUtil::IsSubsetOf(dead, empty));
00134 }
00135 }
00136 }
00137 }
00138 HexAssert(BitsetUtil::IsSubsetOf(dead, empty));
00139 return dead;
00140 }
00141
00142
00143
00144
00145
00146 bitset_t FindType2Cliques(const Groups& groups)
00147 {
00148 const StoneBoard& brd = groups.Board();
00149 bitset_t dead;
00150 bitset_t empty = brd.GetEmpty();
00151
00152
00153
00154 for (BWIterator c; c; ++c) {
00155 for (GroupIterator g1(groups, *c); g1; ++g1) {
00156 if (HexPointUtil::isEdge(g1->Captain())) continue;
00157 bitset_t g1_nbs = groups.Nbs(*g1, EMPTY);
00158
00159 for (GroupIterator g2(groups, *c); &*g2 != &*g1; ++g2) {
00160 if (HexPointUtil::isEdge(g2->Captain())) continue;
00161 bitset_t g2_nbs = groups.Nbs(*g2, EMPTY);
00162 if ((g1_nbs & g2_nbs).none()) continue;
00163
00164 bitset_t g1Exclusive = g1_nbs - g2_nbs;
00165 if (g1Exclusive.none()) continue;
00166 bitset_t g2Exclusive = g2_nbs - g1_nbs;
00167 if (g2Exclusive.none()) continue;
00168
00169
00170
00171 for (BitsetIterator x(g1Exclusive); x; ++x) {
00172 for (BitsetIterator y(g2Exclusive); y; ++y) {
00173 if (!brd.Const().Adjacent(*x, *y)) continue;
00174
00175
00176
00177 bitset_t clique = g1_nbs & g2_nbs;
00178 clique.set(*x);
00179 clique.set(*y);
00180 dead |= ComputeEdgeUnreachableRegions(brd, *c, clique);
00181 HexAssert(BitsetUtil::IsSubsetOf(dead, empty));
00182 }
00183 }
00184 }
00185 }
00186 }
00187 HexAssert(BitsetUtil::IsSubsetOf(dead, empty));
00188 return dead;
00189 }
00190
00191
00192
00193
00194 bitset_t FindType3Cliques(const Groups& groups)
00195 {
00196 const StoneBoard& brd = groups.Board();
00197 bitset_t dead;
00198 bitset_t empty = brd.GetEmpty();
00199
00200
00201
00202 for (BWIterator c; c; ++c) {
00203 for (GroupIterator g1(groups, *c); g1; ++g1) {
00204 if (HexPointUtil::isEdge(g1->Captain())) continue;
00205 bitset_t g1_nbs = groups.Nbs(*g1, EMPTY);
00206
00207 for (GroupIterator g2(groups, *c); &*g2 != &*g1; ++g2) {
00208 if (HexPointUtil::isEdge(g2->Captain())) continue;
00209 bitset_t g2_nbs = groups.Nbs(*g2, EMPTY);
00210 if ((g1_nbs & g2_nbs).none()) continue;
00211
00212 for (GroupIterator g3(groups, *c); &*g3 != &*g2; ++g3) {
00213 if (HexPointUtil::isEdge(g3->Captain())) continue;
00214 bitset_t g3_nbs = groups.Nbs(*g3, EMPTY);
00215 if ((g1_nbs & g3_nbs).none()) continue;
00216 if ((g2_nbs & g3_nbs).none()) continue;
00217
00218
00219
00220 bitset_t clique;
00221 clique = (g1_nbs & g2_nbs) |
00222 (g1_nbs & g3_nbs) |
00223 (g2_nbs & g3_nbs);
00224 dead |= ComputeEdgeUnreachableRegions(brd, *c, clique);
00225 HexAssert(BitsetUtil::IsSubsetOf(dead, empty));
00226 }
00227 }
00228 }
00229 }
00230 HexAssert(BitsetUtil::IsSubsetOf(dead, empty));
00231 return dead;
00232 }
00233
00234
00235
00236
00237
00238
00239
00240
00241 bitset_t FindThreeSetCliques(const Groups& groups)
00242 {
00243 if (groups.IsGameOver())
00244 return groups.Board().GetEmpty();
00245
00246 bitset_t dead1 = FindType1Cliques(groups);
00247 bitset_t dead2 = FindType2Cliques(groups);
00248 bitset_t dead3 = FindType3Cliques(groups);
00249
00250 return dead1 | dead2 | dead3;
00251 }
00252
00253
00254
00255
00256
00257
00258 bool IsClique(const ConstBoard& brd, const std::vector<HexPoint>& vn,
00259 HexPoint exclude=INVALID_POINT)
00260 {
00261 for (unsigned a=0; a<vn.size(); ++a) {
00262 if (vn[a] == exclude) continue;
00263 for (unsigned b=a+1; b<vn.size(); ++b) {
00264 if (vn[b] == exclude) continue;
00265 if (!brd.Adjacent(static_cast<HexPoint>(vn[a]),
00266 static_cast<HexPoint>(vn[b])))
00267 return false;
00268 }
00269 }
00270 return true;
00271 }
00272
00273
00274
00275
00276 void UseGraphTheoryToFindDeadVulnerable(HexColor color, Groups& groups,
00277 PatternState& pastate,
00278 InferiorCells& inf)
00279 {
00280 StoneBoard& brd = groups.Board();
00281 bitset_t simplicial;
00282 bitset_t adj_to_both_edges =
00283 groups.Nbs(HexPointUtil::colorEdge1(color), EMPTY) &
00284 groups.Nbs(HexPointUtil::colorEdge2(color), EMPTY);
00285 bitset_t consider = brd.GetEmpty();
00286 consider = consider - adj_to_both_edges;
00287
00288
00289 for (BitsetIterator p(consider); p; ++p)
00290 {
00291 std::set<HexPoint> enbs, cnbs;
00292 bitset_t empty_adj_to_group;
00293 bool adj_to_edge = false;
00294 HexPoint edgeNbr = INVALID_POINT;
00295
00296
00297 for (BoardIterator nb(brd.Const().Nbs(*p)); nb; ++nb)
00298 {
00299 HexColor ncolor = brd.GetColor(*nb);
00300 if (ncolor == EMPTY)
00301 {
00302 enbs.insert(*nb);
00303 }
00304 else if (ncolor == color)
00305 {
00306 HexPoint cap = groups.CaptainOf(*nb);
00307 bitset_t adj = groups.Nbs(cap, EMPTY);
00308 adj.reset(*p);
00309
00310
00311
00312
00313
00314
00315
00316 if (HexPointUtil::isColorEdge(cap, color))
00317 {
00318 HexAssert(!adj_to_edge || edgeNbr == cap);
00319 adj_to_edge = true;
00320 edgeNbr = cap;
00321 cnbs.insert(cap);
00322 empty_adj_to_group |= adj;
00323 }
00324 else if (adj.count() == 1)
00325 {
00326 enbs.insert(static_cast<HexPoint>
00327 (BitsetUtil::FindSetBit(adj)));
00328 }
00329 else if (adj.count() >= 2)
00330 {
00331 cnbs.insert(cap);
00332 empty_adj_to_group |= adj;
00333 }
00334 }
00335 }
00336
00337
00338 std::set<HexPoint>::iterator it;
00339 for (it = enbs.begin(); it != enbs.end(); )
00340 {
00341 if (empty_adj_to_group.test(*it))
00342 {
00343 enbs.erase(it);
00344 it = enbs.begin();
00345 }
00346 else
00347 ++it;
00348 }
00349
00350
00351
00352
00353 if (enbs.size() + cnbs.size() <= 1)
00354 simplicial.set(*p);
00355
00356
00357
00358
00359
00360 else if (adj_to_edge || cnbs.size() >= 2)
00361 {
00362 if (enbs.size() >= 2)
00363 continue;
00364
00365 if (cnbs.size() == 1)
00366 {
00367 HexAssert(adj_to_edge && enbs.size() == 1);
00368 inf.AddVulnerable(*p, *enbs.begin());
00369 }
00370 else
00371 {
00372 HexAssert(!adj_to_edge ||
00373 HexPointUtil::isColorEdge(edgeNbr, color));
00374
00375 bitset_t killers_bs;
00376 bool isPreSimp = false;
00377
00378
00379 for (std::set<HexPoint>::iterator i = cnbs.begin();
00380 i != cnbs.end(); ++i)
00381 {
00382
00383
00384 if (adj_to_edge && *i != edgeNbr) continue;
00385
00386 bitset_t remainingNbs =
00387 empty_adj_to_group - groups.Nbs(*i, EMPTY);
00388
00389 if (remainingNbs.count() == 0)
00390 {
00391 if (enbs.size() == 0)
00392 simplicial.set(*p);
00393 else
00394 {
00395 HexAssert(enbs.size() == 1);
00396 isPreSimp = true;
00397 killers_bs.set(*enbs.begin());
00398 }
00399 }
00400 else if (remainingNbs.count() == 1 && enbs.size() == 0)
00401 {
00402 isPreSimp = true;
00403 killers_bs.set(BitsetUtil::FindSetBit(remainingNbs));
00404 }
00405 }
00406
00407 if (!simplicial.test(*p) && isPreSimp)
00408 {
00409 HexAssert(killers_bs.any());
00410 for (BitsetIterator k(killers_bs); k; ++k)
00411 inf.AddVulnerable(*p, *k);
00412 }
00413 }
00414
00415 }
00416
00417
00418 else if (enbs.size() + cnbs.size() >= 4)
00419 {
00420
00421 }
00422
00423
00424 else if (cnbs.size() == 1)
00425 {
00426 if (enbs.size() > 1)
00427 continue;
00428
00429 HexAssert(enbs.size() == 1);
00430 HexAssert(empty_adj_to_group.count() >= 2);
00431
00432
00433 inf.AddVulnerable(*p, *enbs.begin());
00434
00435 if (empty_adj_to_group.count() == 2)
00436 {
00437
00438
00439
00440
00441 HexPoint omit = *enbs.begin();
00442 for (BitsetIterator i(empty_adj_to_group); i; ++i)
00443 enbs.insert(*i);
00444
00445
00446
00447 std::vector<HexPoint> vn(enbs.begin(), enbs.end());
00448 for (unsigned ex=0; ex<vn.size(); ++ex)
00449 {
00450 if (vn[ex] == omit)
00451 continue;
00452 if (IsClique(brd.Const(), vn, vn[ex]))
00453 inf.AddVulnerable(*p, vn[ex]);
00454 }
00455 }
00456 }
00457 else
00458 {
00459
00460
00461 HexAssert(cnbs.size() == 0);
00462 std::vector<HexPoint> vn(enbs.begin(), enbs.end());
00463
00464 if (IsClique(brd.Const(), vn))
00465 simplicial.set(*p);
00466 else
00467 {
00468 for (unsigned ex=0; ex<vn.size(); ++ex)
00469 if (IsClique(brd.Const(), vn, vn[ex]))
00470 inf.AddVulnerable(*p, vn[ex]);
00471 }
00472 }
00473 }
00474
00475 if (simplicial.any())
00476 {
00477 inf.AddDead(simplicial);
00478 brd.AddColor(DEAD_COLOR, simplicial);
00479 pastate.Update(simplicial);
00480 GroupBuilder::Build(brd, groups);
00481 }
00482 }
00483
00484
00485
00486 }
00487
00488
00489
00490 ICEngine::ICEngine()
00491 : m_find_presimplicial_pairs(true),
00492 m_find_permanently_inferior(true),
00493 m_find_mutual_fillin(false),
00494 m_find_all_pattern_killers(true),
00495 m_find_all_pattern_reversers(false),
00496 m_find_all_pattern_dominators(false),
00497 m_use_handcoded_patterns(true),
00498 m_backup_opponent_dead(false),
00499 m_find_three_sided_dead_regions(false),
00500 m_iterative_dead_regions(false)
00501 {
00502 LoadHandCodedPatterns();
00503 LoadPatterns();
00504 }
00505
00506 ICEngine::~ICEngine()
00507 {
00508 }
00509
00510
00511
00512
00513 void ICEngine::LoadHandCodedPatterns()
00514 {
00515 HandCodedPattern::CreatePatterns(m_hand_coded);
00516 LogFine() << "ICEngine: " << m_hand_coded.size()
00517 << " hand coded patterns.\n";
00518 }
00519
00520
00521 void ICEngine::LoadPatterns()
00522 {
00523 #ifdef ABS_TOP_SRCDIR
00524 m_patterns.LoadPatterns(boost::filesystem::path(ABS_TOP_SRCDIR)
00525 / "share" / "ice-patterns.txt");
00526 #else
00527 LogWarning() << "**** NO ICE PATTERNS LOADED ***\n";
00528 #endif
00529 }
00530
00531
00532
00533 std::size_t ICEngine::ComputeDeadCaptured(Groups& groups, PatternState& pastate,
00534 InferiorCells& inf,
00535 HexColorSet colors_to_capture) const
00536 {
00537 StoneBoard& brd = groups.Board();
00538
00539 std::size_t count = 0;
00540 while (true)
00541 {
00542
00543
00544 while (true)
00545 {
00546
00547 bitset_t dead = FindDead(pastate, brd.GetEmpty());
00548 if (dead.none())
00549 break;
00550 count += dead.count();
00551 inf.AddDead(dead);
00552 brd.AddColor(DEAD_COLOR, dead);
00553 pastate.Update(dead);
00554 }
00555
00556
00557
00558 {
00559 bitset_t black;
00560 if (HexColorSetUtil::InSet(BLACK, colors_to_capture))
00561 black = FindCaptured(pastate, BLACK, brd.GetEmpty());
00562 if (black.any())
00563 {
00564 count += black.count();
00565 inf.AddCaptured(BLACK, black);
00566 brd.AddColor(BLACK, black);
00567 pastate.Update(black);
00568 continue;
00569 }
00570 }
00571
00572
00573
00574 {
00575 bitset_t white;
00576 if (HexColorSetUtil::InSet(WHITE, colors_to_capture))
00577 white = FindCaptured(pastate, WHITE, brd.GetEmpty());
00578 if (white.any())
00579 {
00580 count += white.count();
00581 inf.AddCaptured(WHITE, white);
00582 brd.AddColor(WHITE, white);
00583 pastate.Update(white);
00584 continue;
00585 }
00586 }
00587
00588 break;
00589 }
00590 if (count)
00591 GroupBuilder::Build(brd, groups);
00592 return count;
00593 }
00594
00595
00596
00597 std::size_t ICEngine::FillinPermanentlyInferior(Groups& groups,
00598 PatternState& pastate,
00599 HexColor color, InferiorCells& out,
00600 HexColorSet colors_to_capture) const
00601 {
00602 if (!m_find_permanently_inferior)
00603 return 0;
00604 if (!HexColorSetUtil::InSet(color, colors_to_capture))
00605 return 0;
00606 StoneBoard& brd = groups.Board();
00607 bitset_t carrier;
00608 bitset_t perm = FindPermanentlyInferior(pastate, color, brd.GetEmpty(),
00609 carrier);
00610 if (perm.any())
00611 {
00612 out.AddPermInf(color, perm, carrier);
00613 brd.AddColor(color, perm);
00614 pastate.Update(perm);
00615 GroupBuilder::Build(brd, groups);
00616 }
00617 return perm.count();
00618 }
00619
00620
00621
00622 std::size_t ICEngine::FillInMutualFillin(Groups& groups, PatternState& pastate,
00623 HexColor color, InferiorCells& out,
00624 HexColorSet colors_to_capture) const
00625 {
00626 if (!m_find_mutual_fillin)
00627 return 0;
00628
00629 if (!HexColorSetUtil::InSet(BLACK, colors_to_capture) ||
00630 !HexColorSetUtil::InSet(WHITE, colors_to_capture))
00631 return 0;
00632 StoneBoard& brd = groups.Board();
00633 bitset_t carrier;
00634 bitset_t mut[BLACK_AND_WHITE];
00635 FindMutualFillin(pastate, color, brd.GetEmpty(), carrier, mut);
00636 if (mut[BLACK].any())
00637 {
00638 HexAssert(mut[WHITE].any());
00639 HexAssert((mut[BLACK] & mut[WHITE]).none());
00640
00641 out.AddMutualFillin(BLACK, mut[BLACK], carrier);
00642 brd.AddColor(BLACK, mut[BLACK]);
00643 pastate.Update(mut[BLACK]);
00644 out.AddMutualFillin(WHITE, mut[WHITE], carrier);
00645 brd.AddColor(WHITE, mut[WHITE]);
00646 pastate.Update(mut[WHITE]);
00647 GroupBuilder::Build(brd, groups);
00648 }
00649 else
00650 HexAssert(mut[WHITE].none());
00651 return (mut[BLACK] | mut[WHITE]).count();
00652 }
00653
00654
00655
00656
00657 std::size_t ICEngine::FillInVulnerable(HexColor color, Groups& groups,
00658 PatternState& pastate, InferiorCells& inf,
00659 HexColorSet colors_to_capture) const
00660 {
00661 std::size_t count = 0;
00662 inf.ClearVulnerable();
00663
00664 UseGraphTheoryToFindDeadVulnerable(color, groups, pastate, inf);
00665
00666
00667
00668
00669 bitset_t consider = groups.Board().GetEmpty() - inf.Dead();
00670 FindVulnerable(pastate, color, consider, inf);
00671
00672
00673
00674 if (HexColorSetUtil::InSet(!color, colors_to_capture))
00675 {
00676 bitset_t captured = inf.FindPresimplicialPairs();
00677 if (captured.any())
00678 {
00679 inf.AddCaptured(!color, captured);
00680 groups.Board().AddColor(!color, captured);
00681 pastate.Update(captured);
00682 GroupBuilder::Build(groups.Board(), groups);
00683 }
00684 count += captured.count();
00685 }
00686 return count;
00687 }
00688
00689
00690
00691 std::size_t ICEngine::CliqueCutsetDead(Groups& groups, PatternState& pastate,
00692 InferiorCells& out) const
00693 {
00694 bitset_t notReachable = ComputeDeadRegions(groups);
00695 if (m_find_three_sided_dead_regions)
00696 notReachable |= FindThreeSetCliques(groups);
00697 if (notReachable.any())
00698 {
00699 out.AddDead(notReachable);
00700 groups.Board().AddColor(DEAD_COLOR, notReachable);
00701 pastate.Update(notReachable);
00702 GroupBuilder::Build(groups.Board(), groups);
00703 }
00704 return notReachable.count();
00705 }
00706
00707 void ICEngine::ComputeFillin(HexColor color, Groups& groups,
00708 PatternState& pastate, InferiorCells& out,
00709 HexColorSet colors_to_capture) const
00710 {
00711 out.Clear();
00712 bool considerCliqueCutset = true;
00713 while(true)
00714 {
00715 std::size_t count;
00716 int iterations = 0;
00717 for (;; ++iterations)
00718 {
00719 count = 0;
00720 count += ComputeDeadCaptured(groups, pastate, out,
00721 colors_to_capture);
00722 count += FillinPermanentlyInferior(groups, pastate, color, out,
00723 colors_to_capture);
00724 count += FillinPermanentlyInferior(groups, pastate, !color, out,
00725 colors_to_capture);
00726 count += FillInMutualFillin(groups, pastate, color, out,
00727 colors_to_capture);
00728 count += FillInMutualFillin(groups, pastate, !color, out,
00729 colors_to_capture);
00730 count += FillInVulnerable(!color, groups, pastate, out,
00731 colors_to_capture);
00732 count += FillInVulnerable(color, groups, pastate, out,
00733 colors_to_capture);
00734 if (0 == count)
00735 break;
00736 considerCliqueCutset = true;
00737 }
00738 if (m_iterative_dead_regions && considerCliqueCutset)
00739 count = CliqueCutsetDead(groups, pastate, out);
00740 if (0 == count)
00741 break;
00742 considerCliqueCutset = false;
00743 }
00744 if (!m_iterative_dead_regions)
00745 CliqueCutsetDead(groups, pastate, out);
00746 }
00747
00748 void ICEngine::ComputeInferiorCells(HexColor color, Groups& groups,
00749 PatternState& pastate,
00750 InferiorCells& out) const
00751 {
00752 #ifndef NDEBUG
00753 HexAssert(groups.Board() == pastate.Board());
00754 StoneBoard oldBoard(groups.Board());
00755 #endif
00756 double startTime = Time::Get();
00757
00758 ComputeFillin(color, groups, pastate, out);
00759
00760 {
00761
00762
00763
00764 bitset_t consider = groups.Board().GetEmpty();
00765 FindReversible(pastate, color, consider, out);
00766 }
00767
00768 {
00769 bitset_t consider = groups.Board().GetEmpty()
00770 - out.Vulnerable()
00771 - out.Reversible();
00772 FindDominated(pastate, color, consider, out);
00773 }
00774
00775
00776
00777 if (m_backup_opponent_dead)
00778 {
00779 int found = BackupOpponentDead(color, groups.Board(), pastate, out);
00780 if (found) {
00781 LogFine() << "Found " << found
00782 << " cells vulnerable to opponent moves.\n";
00783 }
00784 }
00785
00786 double endTime = Time::Get();
00787 LogFine() << " " << (endTime - startTime)
00788 << "s to find inferior cells.\n";
00789 #ifndef NDEBUG
00790 HexAssert(groups.Board().Hash() == oldBoard.Hash());
00791 #endif
00792 }
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803 std::size_t ICEngine::BackupOpponentDead(HexColor color,
00804 const StoneBoard& board,
00805 PatternState& pastate,
00806 InferiorCells& out) const
00807 {
00808 StoneBoard brd(board);
00809 PatternState ps(brd);
00810 ps.CopyState(pastate);
00811
00812 bitset_t reversible = out.Reversible();
00813 bitset_t dominated = out.Dominated();
00814
00815 std::size_t found = 0;
00816 for (BitsetIterator p(board.GetEmpty()); p; ++p)
00817 {
00818 brd.StartNewGame();
00819 brd.SetColor(BLACK, board.GetBlack());
00820 brd.SetColor(WHITE, board.GetWhite());
00821 brd.PlayMove(!color, *p);
00822 ps.Update();
00823 Groups groups;
00824 GroupBuilder::Build(brd, groups);
00825
00826 InferiorCells inf;
00827 ComputeFillin(color, groups, ps, inf);
00828 bitset_t filled = inf.Fillin(BLACK) | inf.Fillin(WHITE);
00829
00830 for (BitsetIterator d(inf.Dead()); d; ++d)
00831 {
00832
00833 if (!out.Vulnerable().test(*d)
00834 && !reversible.test(*d)
00835 && !dominated.test(*d))
00836 {
00837 bitset_t carrier = filled;
00838 carrier.reset(*d);
00839 carrier.reset(*p);
00840 out.AddVulnerable(*d, VulnerableKiller(*p, carrier));
00841 found++;
00842 }
00843 }
00844 }
00845 return found;
00846 }
00847
00848
00849
00850 bitset_t ICEngine::FindDead(const PatternState& pastate,
00851 const bitset_t& consider) const
00852 {
00853 return pastate.MatchOnBoard(consider, m_patterns.HashedDead());
00854 }
00855
00856 bitset_t ICEngine::FindCaptured(const PatternState& pastate, HexColor color,
00857 const bitset_t& consider) const
00858 {
00859 bitset_t captured;
00860 for (BitsetIterator p(consider); p; ++p)
00861 {
00862 if (captured.test(*p))
00863 continue;
00864
00865 PatternHits hits;
00866 pastate.MatchOnCell(m_patterns.HashedCaptured(color), *p,
00867 PatternState::STOP_AT_FIRST_HIT, hits);
00868
00869
00870
00871 if (!hits.empty())
00872 {
00873 HexAssert(hits.size() == 1);
00874 const std::vector<HexPoint>& moves = hits[0].moves2();
00875
00876 bitset_t carrier;
00877 for (unsigned i = 0; i < moves.size(); ++i)
00878 carrier.set(moves[i]);
00879 carrier.set(*p);
00880 if ((carrier & captured).none())
00881 captured |= carrier;
00882 }
00883 }
00884 return captured;
00885 }
00886
00887 bitset_t ICEngine::FindPermanentlyInferior(const PatternState& pastate,
00888 HexColor color,
00889 const bitset_t& consider,
00890 bitset_t& carrier) const
00891 {
00892 std::vector<PatternHits> hits(FIRST_INVALID);
00893 bitset_t ret = pastate.MatchOnBoard(consider,
00894 m_patterns.HashedPermInf(color),
00895 PatternState::STOP_AT_FIRST_HIT, hits);
00896 for (BitsetIterator p(ret); p; ++p)
00897 {
00898 HexAssert(hits[*p].size() == 1);
00899 const std::vector<HexPoint>& moves = hits[*p][0].moves2();
00900 for (unsigned i=0; i<moves.size(); ++i)
00901 carrier.set(moves[i]);
00902 }
00903 return ret;
00904 }
00905
00906 void ICEngine::FindMutualFillin(const PatternState& pastate,
00907 HexColor color,
00908 const bitset_t& consider,
00909 bitset_t& carrier,
00910 bitset_t *mut) const
00911 {
00912 bitset_t altered;
00913 for (BitsetIterator p(consider); p; ++p)
00914 {
00915 PatternHits hits;
00916 pastate.MatchOnCell(m_patterns.HashedMutualFillin(color), *p,
00917 PatternState::STOP_AT_FIRST_HIT, hits);
00918 if (hits.empty())
00919 continue;
00920
00921
00922
00923
00924 HexAssert(hits.size() == 1);
00925 bitset_t willAlter;
00926 willAlter.set(*p);
00927 const std::vector<HexPoint>& moves1 = hits[0].moves1();
00928 for (unsigned i = 0; i < moves1.size(); ++i)
00929 willAlter.set(moves1[i]);
00930 const std::vector<HexPoint>& moves2 = hits[0].moves2();
00931 for (unsigned i = 0; i < moves2.size(); ++i)
00932 willAlter.set(moves2[i]);
00933 if ((willAlter & altered).any())
00934 continue;
00935
00936
00937 altered |= willAlter;
00938 carrier.set(*p);
00939 for (unsigned i = 0; i < moves1.size(); ++i)
00940 mut[color].set(moves1[i]);
00941 for (unsigned i = 0; i < moves2.size(); ++i)
00942 mut[!color].set(moves2[i]);
00943 }
00944 }
00945
00946 void ICEngine::FindVulnerable(const PatternState& pastate, HexColor color,
00947 const bitset_t& consider,
00948 InferiorCells& inf) const
00949 {
00950 PatternState::MatchMode matchmode = PatternState::STOP_AT_FIRST_HIT;
00951 if (m_find_all_pattern_killers)
00952 matchmode = PatternState::MATCH_ALL;
00953
00954 std::vector<PatternHits> hits(FIRST_INVALID);
00955 bitset_t vul = pastate.MatchOnBoard(consider,
00956 m_patterns.HashedVulnerable(color),
00957 matchmode, hits);
00958
00959
00960 for (BitsetIterator p(vul); p; ++p)
00961 {
00962 for (unsigned j=0; j<hits[*p].size(); ++j)
00963 {
00964 const std::vector<HexPoint>& moves1 = hits[*p][j].moves1();
00965 HexAssert(moves1.size() == 1);
00966 HexPoint killer = moves1[0];
00967
00968 bitset_t carrier;
00969 const std::vector<HexPoint>& moves2 = hits[*p][j].moves2();
00970 for (unsigned i=0; i<moves2.size(); ++i) {
00971 carrier.set(moves2[i]);
00972 }
00973 inf.AddVulnerable(*p, VulnerableKiller(killer, carrier));
00974 }
00975 }
00976 }
00977
00978 void ICEngine::FindReversible(const PatternState& pastate, HexColor color,
00979 const bitset_t& consider,
00980 InferiorCells& inf) const
00981 {
00982 PatternState::MatchMode matchmode = PatternState::STOP_AT_FIRST_HIT;
00983 if (m_find_all_pattern_reversers)
00984 matchmode = PatternState::MATCH_ALL;
00985
00986
00987 std::vector<PatternHits> hits(FIRST_INVALID);
00988 bitset_t rev = pastate.MatchOnBoard(consider,
00989 m_patterns.HashedReversible(color),
00990 matchmode, hits);
00991
00992 for (BitsetIterator p(rev); p; ++p)
00993 {
00994 for (unsigned j=0; j<hits[*p].size(); ++j)
00995 {
00996 const std::vector<HexPoint>& moves1 = hits[*p][j].moves1();
00997 HexAssert(moves1.size() == 1);
00998 HexPoint reverser = moves1[0];
00999
01000
01001
01002 HexAssert(hits[*p][j].moves2().size() != 0);
01003 bitset_t carrier;
01004 const std::vector<HexPoint>& moves2 = hits[*p][j].moves2();
01005 for (unsigned i=0; i<moves2.size(); ++i) {
01006 carrier.set(moves2[i]);
01007 }
01008 inf.AddReversible(*p, carrier, reverser);
01009 }
01010 }
01011 }
01012
01013 void ICEngine::FindDominated(const PatternState& pastate, HexColor color,
01014 const bitset_t& consider,
01015 InferiorCells& inf) const
01016 {
01017 PatternState::MatchMode matchmode = PatternState::STOP_AT_FIRST_HIT;
01018 if (m_find_all_pattern_dominators)
01019 matchmode = PatternState::MATCH_ALL;
01020
01021
01022 std::vector<PatternHits> hits(FIRST_INVALID);
01023 bitset_t dom = pastate.MatchOnBoard(consider,
01024 m_patterns.HashedDominated(color),
01025 matchmode, hits);
01026
01027 for (BitsetIterator p(dom); p; ++p)
01028 {
01029 for (unsigned j=0; j<hits[*p].size(); ++j)
01030 {
01031 const std::vector<HexPoint>& moves1 = hits[*p][j].moves1();
01032 HexAssert(moves1.size() == 1);
01033 inf.AddDominated(*p, moves1[0]);
01034
01035
01036
01037
01038 HexAssert(hits[*p][j].moves2().size() == 0);
01039 }
01040 }
01041
01042 if (m_use_handcoded_patterns)
01043 FindHandCodedDominated(pastate.Board(), color, consider, inf);
01044 }
01045
01046 void ICEngine::FindDominatedOnCell(const PatternState& pastate,
01047 HexColor color,
01048 HexPoint cell,
01049 PatternHits& hits) const
01050 {
01051 PatternState::MatchMode matchmode = PatternState::MATCH_ALL;
01052 pastate.MatchOnCell(m_patterns.HashedDominated(color), cell,
01053 matchmode, hits);
01054 }
01055
01056 void ICEngine::FindHandCodedDominated(const StoneBoard& board,
01057 HexColor color,
01058 const bitset_t& consider,
01059 InferiorCells& inf) const
01060 {
01061
01062
01063
01064 if (board.Width() != board.Height())
01065 return;
01066 for (unsigned i=0; i<m_hand_coded.size(); ++i)
01067 CheckHandCodedDominates(board, color, m_hand_coded[i],
01068 consider, inf);
01069 }
01070
01071
01072
01073 void ICEngine::CheckHandCodedDominates(const StoneBoard& brd,
01074 HexColor color,
01075 const HandCodedPattern& pattern,
01076 const bitset_t& consider,
01077 InferiorCells& inf) const
01078 {
01079 if (brd.Width() < 4 || brd.Height() < 3)
01080 return;
01081 HandCodedPattern pat(pattern);
01082
01083 if (color == WHITE)
01084 {
01085 pat.mirror(brd.Const());
01086 pat.flipColors();
01087 }
01088
01089 if (consider.test(pat.dominatee()) && pat.check(brd))
01090 inf.AddDominated(pat.dominatee(), pat.dominator());
01091
01092 pat.rotate(brd.Const());
01093 if (consider.test(pat.dominatee()) && pat.check(brd))
01094 inf.AddDominated(pat.dominatee(), pat.dominator());
01095 }
01096
01097
01098
01099 void IceUtil::Update(InferiorCells& out, const InferiorCells& in)
01100 {
01101
01102 out.ClearVulnerable();
01103 out.ClearReversible();
01104 out.ClearDominated();
01105 out.AddVulnerableFrom(in);
01106 out.AddReversibleFrom(in);
01107 out.AddDominatedFrom(in);
01108
01109
01110 for (BWIterator c; c; ++c)
01111 {
01112 out.AddCaptured(*c, in.Captured(*c));
01113 out.AddPermInfFrom(*c, in);
01114 out.AddMutualFillinFrom(*c, in);
01115 }
01116
01117
01118 out.AddDead(in.Dead());
01119 }
01120
01121