00001 //---------------------------------------------------------------------------- 00002 /** @file InferiorCells.cpp 00003 00004 @todo Handle a sink in the dominated component graph being 00005 partially outside the mustplay -- in this case, no representative 00006 of the sink need be chosen (they are all losing). 00007 00008 @note The set of dominated cells must be recomputed each time the 00009 domination graph or the vulnerable or reversible info is changed. 00010 Dominated() does this computation lazily when required. 00011 */ 00012 //---------------------------------------------------------------------------- 00013 00014 #include "BitsetIterator.hpp" 00015 #include "InferiorCells.hpp" 00016 00017 using namespace benzene; 00018 00019 //---------------------------------------------------------------------------- 00020 00021 InferiorCells::InferiorCells() 00022 : m_dominated_computed(false) 00023 { 00024 } 00025 00026 //---------------------------------------------------------------------------- 00027 00028 bitset_t InferiorCells::Dominated() const 00029 { 00030 if (!m_dominated_computed) { 00031 00032 // remove vulnerable and reversible cells from graph 00033 Digraph<HexPoint> g(m_dom_graph); 00034 for (BitsetIterator p(Vulnerable()); p; ++p) { 00035 g.RemoveVertex(*p); 00036 } 00037 for (BitsetIterator p(Reversible()); p; ++p) { 00038 g.RemoveVertex(*p); 00039 } 00040 00041 bitset_t captains = InferiorCellsUtil::FindDominationCaptains(g); 00042 bitset_t vertices = BitsetUtil::SetToBitset(g.Vertices()); 00043 m_dominated = vertices - captains; 00044 m_dominated_computed = true; 00045 00046 /// @todo ensure m_dominated is disjoint from all others. 00047 HexAssert((m_dominated & Vulnerable()).none()); 00048 HexAssert((m_dominated & Reversible()).none()); 00049 } 00050 return m_dominated; 00051 } 00052 00053 00054 bitset_t InferiorCells::All() const 00055 { 00056 return Dead() 00057 | Vulnerable() | Reversible() | Dominated() 00058 | Captured(BLACK) | Captured(WHITE) 00059 | PermInf(BLACK) | PermInf(WHITE) 00060 | MutualFillin(BLACK) | MutualFillin(WHITE); 00061 } 00062 00063 bitset_t InferiorCells::Fillin(HexColor color) const 00064 { 00065 bitset_t ret = Captured(color) | PermInf(color) | MutualFillin(color); 00066 if (color == DEAD_COLOR) ret |= Dead(); 00067 return ret; 00068 } 00069 00070 //---------------------------------------------------------------------------- 00071 00072 void InferiorCells::AddDead(HexPoint dead) 00073 { 00074 bitset_t b; 00075 b.set(dead); 00076 AddDead(b); 00077 } 00078 00079 void InferiorCells::AddDead(const bitset_t& dead) 00080 { 00081 m_dead |= dead; 00082 00083 RemoveVulnerable(dead); 00084 RemoveReversible(dead); 00085 RemoveDominated(dead); 00086 00087 AssertPairwiseDisjoint(); 00088 } 00089 00090 void InferiorCells::AddCaptured(HexColor color, HexPoint captured) 00091 { 00092 bitset_t b; 00093 b.set(captured); 00094 AddCaptured(color, b); 00095 } 00096 00097 void InferiorCells::AddCaptured(HexColor color, const bitset_t& captured) 00098 { 00099 m_captured[color] |= captured; 00100 00101 RemoveVulnerable(captured); 00102 RemoveReversible(captured); 00103 RemoveDominated(captured); 00104 00105 AssertPairwiseDisjoint(); 00106 } 00107 00108 void InferiorCells::AddPermInf(HexColor color, 00109 const bitset_t& cells, 00110 const bitset_t& carrier) 00111 { 00112 m_perm_inf[color] |= cells; 00113 m_perm_inf_carrier[color] |= carrier; 00114 00115 RemoveVulnerable(cells); 00116 RemoveReversible(cells); 00117 RemoveDominated(cells); 00118 00119 AssertPairwiseDisjoint(); 00120 } 00121 00122 void InferiorCells::AddPermInf(HexColor color, HexPoint cell, 00123 const bitset_t& carrier) 00124 { 00125 bitset_t b; 00126 b.set(cell); 00127 AddPermInf(color, b, carrier); 00128 } 00129 00130 void InferiorCells::AddMutualFillin(HexColor color, 00131 const bitset_t& cells, 00132 const bitset_t& carrier) 00133 { 00134 m_mutual_fillin[color] |= cells; 00135 m_mutual_fillin_carrier[color] |= carrier; 00136 00137 RemoveVulnerable(cells); 00138 RemoveReversible(cells); 00139 RemoveDominated(cells); 00140 00141 AssertPairwiseDisjoint(); 00142 } 00143 00144 void InferiorCells::AddMutualFillin(HexColor color, HexPoint cell, 00145 const bitset_t& carrier) 00146 { 00147 bitset_t b; 00148 b.set(cell); 00149 AddMutualFillin(color, b, carrier); 00150 } 00151 00152 void InferiorCells::AddDominated(HexPoint cell, const std::set<HexPoint>& dom) 00153 { 00154 m_dom_graph.AddEdges(cell, dom); 00155 m_dominated_computed = false; 00156 00157 //AssertPairwiseDisjoint(); 00158 } 00159 00160 void InferiorCells::AddDominated(HexPoint cell, HexPoint dominator) 00161 { 00162 m_dom_graph.AddEdge(cell, dominator); 00163 m_dominated_computed = false; 00164 00165 //AssertPairwiseDisjoint(); 00166 } 00167 00168 void InferiorCells::AddVulnerable(HexPoint cell, 00169 const std::set<HexPoint>& killers) 00170 { 00171 m_vulnerable.set(cell); 00172 00173 // add each killer with an empty carrier 00174 std::set<HexPoint>::iterator it = killers.begin(); 00175 for (; it != killers.end(); ++it) { 00176 m_killers[cell].insert(VulnerableKiller(*it)); 00177 } 00178 00179 // update reversible and dominated 00180 RemoveReversible(cell); 00181 m_dominated_computed = false; 00182 00183 AssertPairwiseDisjoint(); 00184 } 00185 00186 void InferiorCells::AddVulnerable(HexPoint cell, 00187 const std::set<VulnerableKiller>& killers) 00188 { 00189 m_vulnerable.set(cell); 00190 m_killers[cell].insert(killers.begin(), killers.end()); 00191 RemoveReversible(cell); 00192 m_dominated_computed = false; 00193 00194 AssertPairwiseDisjoint(); 00195 } 00196 00197 void InferiorCells::AddVulnerable(HexPoint cell, HexPoint killer) 00198 { 00199 m_vulnerable.set(cell); 00200 m_killers[cell].insert(VulnerableKiller(killer)); 00201 RemoveReversible(cell); 00202 m_dominated_computed = false; 00203 00204 AssertPairwiseDisjoint(); 00205 } 00206 00207 void InferiorCells::AddVulnerable(HexPoint cell, const VulnerableKiller& killer) 00208 { 00209 m_vulnerable.set(cell); 00210 m_killers[cell].insert(killer); 00211 RemoveReversible(cell); 00212 m_dominated_computed = false; 00213 00214 AssertPairwiseDisjoint(); 00215 } 00216 00217 void InferiorCells::AddReversible(HexPoint cell, bitset_t carrier, 00218 HexPoint reverser) 00219 { 00220 // Cell and carrier have equivalent roles, so just merge 00221 bitset_t reversibleCandidates = carrier; 00222 reversibleCandidates.set(cell); 00223 00224 // Cannot add any if not independent of previous reversible cells 00225 if (m_allReversibleCarriers.test(reverser)) return; 00226 if ((m_allReversers & reversibleCandidates).any()) return; 00227 if (reversibleCandidates.test(reverser)) return; 00228 00229 // Independent, so mark all (non-vulnerable) candidates as reversible 00230 bool noAdditions = true; 00231 for (BitsetIterator it(reversibleCandidates); it; ++it) 00232 { 00233 if (m_vulnerable.test(*it)) continue; 00234 noAdditions = false; 00235 m_reversible.set(*it); 00236 m_reversers[*it].insert(reverser); 00237 } 00238 if (noAdditions) return; 00239 m_allReversibleCarriers |= reversibleCandidates; 00240 m_allReversers.set(reverser); 00241 00242 m_dominated_computed = false; 00243 AssertPairwiseDisjoint(); 00244 } 00245 00246 void InferiorCells::AddReversible(HexPoint cell, bitset_t carrier, 00247 const std::set<HexPoint>& reversers) 00248 { 00249 // Cell and carrier have equivalent roles, so just merge 00250 bitset_t reversibleCandidates = carrier; 00251 reversibleCandidates.set(cell); 00252 // Merge all reversers into one big pot (all or nothing :) 00253 bitset_t reverserCandidates; 00254 for (std::set<HexPoint>::iterator it = reversers.begin(); 00255 it != reversers.end(); ++it) 00256 { 00257 reverserCandidates.set(*it); 00258 } 00259 00260 // Cannot add any if not independent of previous reversible cells 00261 if ((m_allReversibleCarriers & reverserCandidates).any()) return; 00262 if ((m_allReversers & reversibleCandidates).any()) return; 00263 if ((reverserCandidates & reversibleCandidates).any()) return; 00264 00265 // Independent, so mark all (non-vulnerable) candidates as reversible 00266 bool noAdditions = true; 00267 for (BitsetIterator it(reversibleCandidates); it; ++it) 00268 { 00269 if (m_vulnerable.test(*it)) continue; 00270 noAdditions = false; 00271 m_reversible.set(*it); 00272 m_reversers[*it].insert(reversers.begin(), reversers.end()); 00273 } 00274 if (noAdditions) return; 00275 m_allReversibleCarriers |= reversibleCandidates; 00276 m_allReversers |= reverserCandidates; 00277 00278 m_dominated_computed = false; 00279 AssertPairwiseDisjoint(); 00280 } 00281 00282 //---------------------------------------------------------------------------- 00283 00284 void InferiorCells::AddDominatedFrom(const InferiorCells& other) 00285 { 00286 bitset_t vertices=BitsetUtil::SetToBitset(other.m_dom_graph.Vertices()); 00287 for (BitsetIterator p(vertices); p; ++p) { 00288 AddDominated(*p, other.m_dom_graph.OutSet(*p)); 00289 } 00290 //AssertPairwiseDisjoint(); 00291 } 00292 00293 void InferiorCells::AddVulnerableFrom(const InferiorCells& other) 00294 { 00295 for (BitsetIterator p(other.Vulnerable()); p; ++p) { 00296 AddVulnerable(*p, other.m_killers[*p]); 00297 } 00298 AssertPairwiseDisjoint(); 00299 } 00300 00301 void InferiorCells::AddReversibleFrom(const InferiorCells& other) 00302 { 00303 for (BitsetIterator p(other.Reversible()); p; ++p) { 00304 AddReversible(*p, EMPTY_BITSET, other.m_reversers[*p]); 00305 } 00306 m_allReversibleCarriers |= other.AllReversibleCarriers(); 00307 m_allReversers |= other.AllReversers(); 00308 AssertPairwiseDisjoint(); 00309 } 00310 00311 void InferiorCells::AddPermInfFrom(HexColor color, const InferiorCells& other) 00312 { 00313 m_perm_inf[color] |= other.m_perm_inf[color]; 00314 m_perm_inf_carrier[color] |= other.m_perm_inf_carrier[color]; 00315 AssertPairwiseDisjoint(); 00316 } 00317 00318 void InferiorCells::AddMutualFillinFrom(HexColor color, 00319 const InferiorCells& other) 00320 { 00321 m_mutual_fillin[color] |= other.m_mutual_fillin[color]; 00322 m_mutual_fillin_carrier[color] |= other.m_mutual_fillin_carrier[color]; 00323 AssertPairwiseDisjoint(); 00324 } 00325 00326 //---------------------------------------------------------------------------- 00327 00328 void InferiorCells::Clear() 00329 { 00330 ClearDead(); 00331 ClearVulnerable(); 00332 ClearReversible(); 00333 for (BWIterator c; c; ++c) { 00334 ClearCaptured(*c); 00335 ClearPermInf(*c); 00336 ClearMutualFillin(*c); 00337 } 00338 ClearDominated(); 00339 } 00340 00341 void InferiorCells::ClearDead() 00342 { 00343 m_dead.reset(); 00344 } 00345 00346 void InferiorCells::ClearCaptured(HexColor color) 00347 { 00348 m_captured[color].reset(); 00349 } 00350 00351 void InferiorCells::ClearPermInf(HexColor color) 00352 { 00353 m_perm_inf[color].reset(); 00354 m_perm_inf_carrier[color].reset(); 00355 } 00356 00357 void InferiorCells::ClearMutualFillin(HexColor color) 00358 { 00359 m_mutual_fillin[color].reset(); 00360 m_mutual_fillin_carrier[color].reset(); 00361 } 00362 00363 void InferiorCells::ClearVulnerable() 00364 { 00365 RemoveVulnerable(m_vulnerable); 00366 m_dominated_computed = false; 00367 } 00368 00369 void InferiorCells::ClearReversible() 00370 { 00371 RemoveReversible(m_reversible); 00372 m_allReversibleCarriers.reset(); 00373 m_allReversers.reset(); 00374 m_dominated_computed = false; 00375 } 00376 00377 void InferiorCells::ClearDominated() 00378 { 00379 m_dom_graph.Clear(); 00380 m_dominated_computed = false; 00381 } 00382 00383 //---------------------------------------------------------------------------- 00384 00385 void InferiorCells::RemoveDominated(const bitset_t& dominated) 00386 { 00387 bitset_t vertices = BitsetUtil::SetToBitset(m_dom_graph.Vertices()); 00388 for (BitsetIterator p(vertices & dominated); p; ++p) { 00389 m_dom_graph.RemoveVertex(*p); 00390 } 00391 m_dominated_computed = false; 00392 } 00393 00394 void InferiorCells::RemoveVulnerable(const bitset_t& vulnerable) 00395 { 00396 for (BitsetIterator p(vulnerable & m_vulnerable); p; ++p) { 00397 m_killers[*p].clear(); 00398 } 00399 m_vulnerable = m_vulnerable - vulnerable; 00400 m_dominated_computed = false; 00401 } 00402 00403 void InferiorCells::RemoveReversible(const bitset_t& reversible) 00404 { 00405 for (BitsetIterator p(reversible & m_reversible); p; ++p) { 00406 m_reversers[*p].clear(); 00407 } 00408 m_reversible = m_reversible - reversible; 00409 m_dominated_computed = false; 00410 } 00411 00412 void InferiorCells::RemoveReversible(HexPoint reversible) 00413 { 00414 if (m_reversible.test(reversible)) { 00415 m_reversers[reversible].clear(); 00416 m_reversible.reset(reversible); 00417 m_dominated_computed = false; 00418 } 00419 } 00420 00421 //---------------------------------------------------------------------------- 00422 00423 void InferiorCells::AssertPairwiseDisjoint() const 00424 { 00425 HexAssert((m_dead & m_vulnerable).none()); 00426 HexAssert((m_dead & m_reversible).none()); 00427 HexAssert((m_reversible & m_vulnerable).none()); 00428 HexAssert((m_allReversibleCarriers & m_allReversers).none()); 00429 HexAssert((m_reversible & m_allReversibleCarriers) == m_reversible); 00430 HexAssert(!m_dominated_computed || (m_dead & m_dominated).none()); 00431 HexAssert(!m_dominated_computed || (m_vulnerable & m_dominated).none()); 00432 HexAssert(!m_dominated_computed || (m_reversible & m_dominated).none()); 00433 00434 for (BWIterator c; c; ++c) { 00435 HexAssert((m_captured[*c] & m_dead).none()); 00436 HexAssert(!m_dominated_computed 00437 || (m_captured[*c] & m_dominated).none()); 00438 HexAssert((m_captured[*c] & m_vulnerable).none()); 00439 HexAssert((m_captured[*c] & m_reversible).none()); 00440 HexAssert((m_captured[*c] & m_captured[!*c]).none()); 00441 00442 HexAssert((m_perm_inf[*c] & m_dead).none()); 00443 HexAssert(!m_dominated_computed 00444 || (m_perm_inf[*c] & m_dominated).none()); 00445 HexAssert((m_perm_inf[*c] & m_vulnerable).none()); 00446 HexAssert((m_perm_inf[*c] & m_reversible).none()); 00447 00448 HexAssert((m_captured[*c] & m_perm_inf[*c]).none()); 00449 HexAssert((m_captured[*c] & m_perm_inf[!*c]).none()); 00450 00451 HexAssert((m_mutual_fillin[*c] & m_dead).none()); 00452 HexAssert(!m_dominated_computed 00453 || (m_mutual_fillin[*c] & m_dominated).none()); 00454 HexAssert((m_mutual_fillin[*c] & m_vulnerable).none()); 00455 HexAssert((m_mutual_fillin[*c] & m_reversible).none()); 00456 00457 HexAssert((m_mutual_fillin[*c] & m_captured[*c]).none()); 00458 HexAssert((m_mutual_fillin[*c] & m_captured[!*c]).none()); 00459 HexAssert((m_mutual_fillin[*c] & m_perm_inf[*c]).none()); 00460 HexAssert((m_mutual_fillin[*c] & m_perm_inf[!*c]).none()); 00461 } 00462 } 00463 00464 //---------------------------------------------------------------------------- 00465 00466 bitset_t InferiorCells::FindPresimplicialPairs() const 00467 { 00468 bitset_t fillin; 00469 std::set<VulnerableKiller>::iterator k1, k2; 00470 00471 /** @todo Handle vulnerable cycles larger than length 2? If they 00472 occur, they are extrememly rare, so it is probably not worth 00473 it. */ 00474 00475 for (BitsetIterator x(m_vulnerable); x; ++x) { 00476 if (fillin.test(*x)) continue; 00477 00478 for (k1 = m_killers[*x].begin(); k1 != m_killers[*x].end(); ++k1) { 00479 HexPoint y = k1->killer(); 00480 if (fillin.test(y)) continue; 00481 if ((k1->carrier() & fillin).any()) continue; 00482 00483 bool success = false; 00484 for (k2 = m_killers[y].begin(); k2 != m_killers[y].end(); ++k2) { 00485 HexPoint z = k2->killer(); 00486 if (z != *x) continue; 00487 if (fillin.test(z)) continue; 00488 if ((k2->carrier() & fillin).any()) continue; 00489 00490 // if x kills y and y kills x and the carriers do not 00491 // intersect, fill them in along with their carriers. 00492 if ((k1->carrier() & k2->carrier()).none()) { 00493 bitset_t both = k1->carrier() | k2->carrier(); 00494 if ((both & fillin).none()) { 00495 fillin |= both; 00496 fillin.set(y); 00497 fillin.set(*x); 00498 success = true; 00499 break; 00500 } 00501 } 00502 } 00503 00504 // if x and a killer of x have been filled in, there is no 00505 // point checking the remaining killers of x. 00506 if (success) break; 00507 } 00508 } 00509 00510 return fillin; 00511 } 00512 00513 bitset_t InferiorCells::DeductionSet(HexColor color) const 00514 { 00515 bitset_t deductionSet; 00516 deductionSet = Captured(color); 00517 deductionSet |= PermInf(color); 00518 deductionSet |= PermInfCarrier(color); 00519 deductionSet |= MutualFillin(color); 00520 deductionSet |= MutualFillinCarrier(color); 00521 return deductionSet; 00522 } 00523 00524 //---------------------------------------------------------------------------- 00525 00526 std::string InferiorCells::GuiOutput() const 00527 { 00528 std::size_t c = 0; 00529 std::ostringstream out; 00530 for (int i = 0; i < FIRST_INVALID; ++i) 00531 { 00532 HexPoint p = static_cast<HexPoint>(i); 00533 std::ostringstream os; 00534 00535 os << " " << p << " "; 00536 if (Dead().test(i)) 00537 { 00538 os << "fd"; 00539 os << ((DEAD_COLOR == BLACK) ? "b" : "w"); 00540 } 00541 else if (Captured(BLACK).test(i)) 00542 os << "fcb"; 00543 else if (Captured(WHITE).test(i)) 00544 os << "fcw"; 00545 else if (PermInf(BLACK).test(i)) 00546 os << "fpb"; 00547 else if (PermInf(WHITE).test(i)) 00548 os << "fpw"; 00549 else if (MutualFillin(BLACK).test(i)) 00550 os << "fub"; 00551 else if (MutualFillin(WHITE).test(i)) 00552 os << "fuw"; 00553 else if (Vulnerable().test(i)) 00554 { 00555 os << "iv["; 00556 bool first=true; 00557 std::set<VulnerableKiller>::const_iterator i; 00558 for (i = m_killers[p].begin(); i != m_killers[p].end(); ++i) 00559 { 00560 if (!first) os << "-"; 00561 os << i->killer(); 00562 first = false; 00563 } 00564 os << "]"; 00565 } 00566 else if (Reversible().test(i)) 00567 { 00568 os << "ir["; 00569 bool first=true; 00570 std::set<HexPoint>::const_iterator i; 00571 for (i = m_reversers[p].begin(); i != m_reversers[p].end(); ++i) 00572 { 00573 if (!first) os << "-"; 00574 os << *i; 00575 first = false; 00576 } 00577 os << "]"; 00578 } 00579 else if (Dominated().test(i)) 00580 { 00581 os << "id["; 00582 bool first=true; 00583 std::set<HexPoint>::iterator i; 00584 for (i=m_dom_graph.out_begin(p); i!=m_dom_graph.out_end(p); ++i) 00585 { 00586 // PHIL IS CONFUSED: CAN THIS HAPPEN?? 00587 if (Vulnerable().test(*i)) 00588 continue; 00589 if (!first) os << "-"; 00590 os << *i; 00591 first = false; 00592 } 00593 os << "]"; 00594 } 00595 else 00596 continue; 00597 00598 std::string str = os.str(); 00599 std::size_t t = str.size(); 00600 if (c + t > 40) 00601 { 00602 out << '\n'; 00603 c = t; 00604 } 00605 else 00606 c += t; 00607 00608 out << str; 00609 } 00610 return out.str(); 00611 } 00612 00613 //---------------------------------------------------------------------------- 00614 00615 bitset_t 00616 InferiorCellsUtil::FindDominationCaptains(const Digraph<HexPoint>& graph) 00617 { 00618 bitset_t captains; 00619 00620 // Find the strongly connected components of the domination graph. 00621 std::vector<HexPointSet> comp; 00622 graph.FindStronglyConnectedComponents(comp); 00623 00624 // Find the sinks in the component graph 00625 for (std::size_t i=0; i < comp.size(); ++i) { 00626 00627 std::set<HexPoint> out; 00628 graph.OutSet(comp[i], out); 00629 00630 // remove members of the component from the outset since 00631 // we are only concerned with edges leaving the component 00632 std::set<HexPoint>::iterator it; 00633 for (it = comp[i].begin(); it != comp[i].end(); ++it) 00634 out.erase(*it); 00635 00636 // if a sink, pick a representative for the component 00637 if (out.empty()) { 00638 captains.set(*comp[i].begin()); 00639 } 00640 } 00641 00642 return captains; 00643 } 00644 00645 //----------------------------------------------------------------------------