00001
00002
00003 #include "osl/checkmate/dualDfpn.h"
00004 #include "osl/checkmate/dfpn.h"
00005 #include "osl/checkmate/dfpnRecord.h"
00006 #ifdef OSL_DFPN_SMP
00007 # include "osl/checkmate/dfpnParallel.h"
00008 #endif
00009 #include "osl/repetitionCounter.h"
00010 #include "osl/stl/hash_map.h"
00011 #include "osl/stl/slist.h"
00012 #include "osl/stat/average.h"
00013 #include "osl/centering3x3.h"
00014 #include "osl/centering5x3.h"
00015 #ifdef OSL_SMP
00016 # include "osl/misc/lightMutex.h"
00017 # include <boost/thread/condition.hpp>
00018 #endif
00019 #ifdef OSL_SHOW_PROOF_TREE_MIGRATION_STAT
00020 # include "osl/stat/ratio.h"
00021 #endif
00022 #include "osl/misc/milliSeconds.h"
00023 #include "osl/oslConfig.h"
00024 #include <boost/foreach.hpp>
00025 #include <iostream>
00026 #include <iomanip>
00027
00028 #define DFPN_SHARE_TABLE
00029
00030 static const int max_oracle_list_size = 2;
00031 static const size_t local_table_growth_limit = 40000;
00032 struct osl::checkmate::DualDfpn::OraclePool
00033 {
00034 struct Element
00035 {
00036 Dfpn::ProofOracle oracle;
00037 PieceStand proof_pieces;
00038 unsigned int id;
00039 bool in_check;
00040 Element() : oracle(HashKey(), PieceStand()), id((unsigned int)-1), in_check(false)
00041 {
00042 }
00043 Element(const Dfpn::ProofOracle& o, PieceStand p, size_t i, bool c) : oracle(o), proof_pieces(p), id(i), in_check(c)
00044 {
00045 }
00046 };
00047 struct List : FixedCapacityVector<Element, max_oracle_list_size>
00048 {
00049 void add(const Element& e)
00050 {
00051 if (size() == capacity())
00052 back() = e;
00053 else
00054 push_back(e);
00055 }
00056 };
00057 #ifdef OSL_SMP
00058 mutable boost::mutex mutex;
00059 #endif
00060 typedef hash_map<HashKey, List> table_t;
00061 table_t table;
00062 Player defender;
00063 void setAttack(Player attack)
00064 {
00065 defender = alt(attack);
00066 }
00067 void addProof(const NumEffectState& state, const HashKey& key, PieceStand proof_pieces)
00068 {
00069 const Dfpn::ProofOracle oracle(key, PieceStand(WHITE, state));
00070 const std::pair<HashKey,HashKey> king = makeLargeKey(state);
00071 #ifdef OSL_SMP
00072 boost::mutex::scoped_lock lk(mutex);;
00073 #endif
00074 const Element e(oracle, proof_pieces, table.size(), state.inCheck());
00075 table[king.first].add(e);
00076 table[king.second].add(e);
00077 }
00078 const List probe(const NumEffectState& state) const
00079 {
00080 const std::pair<HashKey,HashKey> key = makeLargeKey(state);
00081 #ifdef OSL_SMP
00082 boost::mutex::scoped_lock lk(mutex);;
00083 #endif
00084 table_t::const_iterator p = table.find(key.first);
00085 if (p != table.end())
00086 return p->second;
00087 p = table.find(key.second);
00088 if (p != table.end())
00089 return p->second;
00090 return List();
00091 }
00092
00093 template <Direction DIR>
00094 static void addKey(HashKey& key, const SimpleState& state, Square target)
00095 {
00096 const Offset offset = DirectionTraits<DIR>::blackOffset();
00097 target += offset;
00098 const Piece piece = state.pieceOnBoard(target);
00099 hash::Hash_Gen_Table.addHashKey(key, target, piece.ptypeO());
00100 }
00101 template <Direction DIR, Direction DIR2>
00102 static void addKey(HashKey& key, const SimpleState& state, Square target)
00103 {
00104 const Offset offset = DirectionTraits<DIR>::blackOffset()
00105 + DirectionTraits<DIR2>::blackOffset();
00106 target += offset;
00107 const Piece piece = state.pieceOnBoard(target);
00108 hash::Hash_Gen_Table.addHashKey(key, target, piece.ptypeO());
00109 }
00110 const HashKey makeKey(const SimpleState& state) const
00111 {
00112 const Square target_king=state.kingSquare(defender);
00113 const Square center = Centering3x3::adjustCenter(target_king);
00114 HashKey key;
00115 hash::Hash_Gen_Table.addHashKey(key, center,
00116 state.pieceOnBoard(center).ptypeO());
00117 addKey<UL>(key, state, center); addKey<U> (key, state, center);
00118 addKey<UR>(key, state, center);
00119 addKey<L> (key, state, center); addKey<R> (key, state, center);
00120 addKey<DL>(key, state, center); addKey<D> (key, state, center);
00121 addKey<DR>(key, state, center);
00122 return key;
00123 }
00124 const std::pair<HashKey,HashKey> makeLargeKey(const SimpleState& state) const
00125 {
00126 HashKey key_small = makeKey(state), key_large;
00127 const Square target_king=state.kingSquare(defender);
00128 const Square center = Centering5x3::adjustCenter(target_king);
00129 hash::Hash_Gen_Table.addHashKey(key_large, center,
00130 state.pieceOnBoard(center).ptypeO());
00131 addKey<UL>(key_large, state, center); addKey<U> (key_large, state, center);
00132 addKey<UR>(key_large, state, center);
00133 addKey<L> (key_large, state, center); addKey<R> (key_large, state, center);
00134 addKey<DL>(key_large, state, center); addKey<D> (key_large, state, center);
00135 addKey<DR>(key_large, state, center);
00136 addKey<L,UL>(key_large, state, center); addKey<L,L> (key_large, state, center);
00137 addKey<L,DL>(key_large, state, center);
00138 addKey<R,UR>(key_large, state, center); addKey<R,R> (key_large, state, center);
00139 addKey<R,DR>(key_large, state, center);
00140 return std::make_pair(key_large, key_small);
00141 }
00142 };
00143
00144 struct osl::checkmate::DualDfpn::Shared
00145 {
00146 CArray<DfpnTable,2> table;
00147 CArray<OraclePool,2> pool;
00148 size_t main_node_count;
00149 size_t simulation_count;
00150 volatile size_t last_gc, gc_threshold;
00151 CArray<stat::Average,max_oracle_list_size> proof_by_oracle;
00152 CArray<bool,2> blocking_verify;
00153 #ifdef OSL_SMP
00154 boost::mutex mutex;
00155 boost::condition condition;
00156 CArray<LightMutex,max_oracle_list_size> proof_by_oracle_mutex;
00157 #endif
00158 volatile int shared_table_user, shared_table_gc_wait;
00159 #ifdef OSL_DFPN_SMP
00160 boost::scoped_ptr<DfpnParallel> parallel_search;
00161 #endif
00162 typedef slist<PathEncoding> disproof_list_t;
00163 typedef hash_map<HashKey, disproof_list_t> disproof_table_t;
00164 disproof_table_t disproof_table;
00165
00166 Shared() : main_node_count(0), simulation_count(0), last_gc(0), gc_threshold(10),
00167 shared_table_user(0), shared_table_gc_wait(0)
00168 {
00169 table[BLACK].setAttack(BLACK);
00170 table[WHITE].setAttack(WHITE);
00171 pool[BLACK].setAttack(BLACK);
00172 pool[WHITE].setAttack(WHITE);
00173 blocking_verify.fill(true);
00174 }
00175 ~Shared()
00176 {
00177 showStats();
00178 }
00179 void showStats()
00180 {
00181 if (main_node_count || simulation_count) {
00182 #ifdef DFPN_DEBUG
00183 std::cerr << "shared " << main_node_count << " " << simulation_count << "\n";
00184 BOOST_FOREACH(stat::Average& a, proof_by_oracle)
00185 std::cerr << a.getAverage()
00186 << " " << (int)(a.getAverage()*a.numElements()) << "\n";
00187 std::cerr << "oracles " << pool[BLACK].table.size() << " " << pool[WHITE].table.size() << "\n";
00188 std::cerr << "table " << table[0].totalSize() << " " << table[1].totalSize() << "\n";
00189 table[0].showStats();
00190 table[1].showStats();
00191 #endif
00192 }
00193 }
00194 void addMainNodeCount(int add)
00195 {
00196 #ifdef OSL_SMP
00197 boost::mutex::scoped_lock lk(mutex);;
00198 #endif
00199 main_node_count += add;
00200 }
00201 void addSimulationNodeCount(int add)
00202 {
00203 #ifdef OSL_SMP
00204 boost::mutex::scoped_lock lk(mutex);;
00205 #endif
00206 simulation_count += add;
00207 }
00208 struct TableUseLock : boost::noncopyable
00209 {
00210 Shared *shared;
00211 explicit TableUseLock(Shared *s) : shared(s)
00212 {
00213 # ifdef OSL_SMP
00214 boost::mutex::scoped_lock lk(shared->mutex);
00215 while (shared->shared_table_user < 0)
00216 shared->condition.wait(lk);
00217 shared->shared_table_user++;
00218 # endif
00219 }
00220 ~TableUseLock()
00221 {
00222 # ifdef OSL_SMP
00223 boost::mutex::scoped_lock lk(shared->mutex);
00224 assert(shared->shared_table_user > 0);
00225 shared->shared_table_user--;
00226 if (shared->shared_table_user == 0 && shared->shared_table_gc_wait)
00227 shared->condition.notify_all();
00228 # endif
00229 }
00230 };
00231 };
00232
00233 struct osl::checkmate::DualDfpn::Local
00234 {
00235 Dfpn dfpn;
00236 #ifndef DFPN_SHARE_TABLE
00237 CArray<DfpnTable,2> table;
00238 #endif
00239 CArray<DfpnTable,2> table_small;
00240 size_t local_node_count;
00241 Local() : local_node_count(0)
00242 {
00243 #ifndef DFPN_SHARE_TABLE
00244 table[BLACK].setAttack(BLACK);
00245 table[WHITE].setAttack(WHITE);
00246 #endif
00247 table_small[BLACK].setAttack(BLACK);
00248 table_small[WHITE].setAttack(WHITE);
00249 }
00250 ~Local()
00251 {
00252 #ifdef DFPN_DEBUG
00253 std::cerr << "local " << table_small[0].totalSize()
00254 << " " << table_small[1].totalSize() << "\n";
00255 #endif
00256 }
00257 };
00258
00259
00260
00261 osl::checkmate::
00262 DualDfpn::DualDfpn(uint64_t )
00263 : shared(new Shared), local(new Local)
00264 {
00265 }
00266
00267 osl::checkmate::
00268 DualDfpn::DualDfpn(const DualDfpn& src)
00269 : shared(src.shared), local(new Local)
00270 {
00271 }
00272
00273 osl::checkmate::
00274 DualDfpn::~DualDfpn()
00275 {
00276 }
00277
00278 osl::checkmate::Dfpn& osl::checkmate::
00279 DualDfpn::prepareDfpn(Player attack)
00280 {
00281 #ifdef DFPN_SHARE_TABLE
00282 local->dfpn.setTable(&(shared->table[attack]));
00283 #else
00284 local->dfpn.setTable(&(local->table[attack]));
00285 #endif
00286 local->dfpn.setBlockingVerify(shared->blocking_verify[attack]);
00287 return local->dfpn;
00288 }
00289
00290 osl::checkmate::Dfpn& osl::checkmate::
00291 DualDfpn::prepareDfpnSmall(Player attack)
00292 {
00293 local->dfpn.setTable(&(local->table_small[attack]));
00294 local->dfpn.setBlockingVerify(shared->blocking_verify[attack]);
00295 return local->dfpn;
00296 }
00297
00298 void osl::checkmate::
00299 DualDfpn::runGC(bool verbose, size_t memory_use_ratio_1000)
00300 {
00301 #ifdef DFPN_SHARE_TABLE
00302 const size_t unit_size = (sizeof(HashKey)+sizeof(DfpnRecord)+sizeof(char*)*2);
00303 size_t removed = 0;
00304 size_t total = shared->table[BLACK].size() + shared->table[WHITE].size();
00305 size_t current_use = memory_use_ratio_1000*(OslConfig::memoryUseLimit()/1000);
00306 if (total < local_table_growth_limit*8
00307 || total*unit_size*64 < OslConfig::memoryUseLimit()
00308 || (total*unit_size*3 < current_use
00309 && total*unit_size*8 < OslConfig::memoryUseLimit()))
00310 return;
00311 MilliSeconds start = MilliSeconds::now();
00312 {
00313 {
00314 # ifdef OSL_SMP
00315 boost::mutex::scoped_lock lk(shared->mutex);
00316 # endif
00317 total = shared->table[BLACK].size() + shared->table[WHITE].size();
00318 if (total < local_table_growth_limit*8
00319 || (total*unit_size*3 < current_use
00320 && total*unit_size*6 < OslConfig::memoryUseLimit()))
00321 return;
00322 if (total < shared->last_gc + local_table_growth_limit*2)
00323 return;
00324 if (shared->shared_table_user > 0
00325 && memory_use_ratio_1000 < 650
00326 && total < shared->last_gc*2)
00327 return;
00328 if (shared->shared_table_user < 0 || shared->shared_table_gc_wait > 0)
00329 return;
00330 # ifdef OSL_SMP
00331 while (shared->shared_table_user > 0) {
00332 ++shared->shared_table_gc_wait;
00333 shared->condition.wait(lk);
00334 --shared->shared_table_gc_wait;
00335 }
00336 if (shared->shared_table_user < 0)
00337 return;
00338 # endif
00339 shared->shared_table_user--;
00340 }
00341 removed += shared->table[BLACK].smallTreeGC(shared->gc_threshold);
00342 removed += shared->table[WHITE].smallTreeGC(shared->gc_threshold);
00343 {
00344 # ifdef OSL_SMP
00345 boost::mutex::scoped_lock lk(shared->mutex);
00346 # endif
00347 if (total > shared->last_gc*2) {
00348 if (100.0*removed/total < 70)
00349 shared->gc_threshold += 15;
00350 else if (100.0*removed/total < 90)
00351 shared->gc_threshold += 5;
00352 }
00353 shared->last_gc = total - removed;
00354 shared->shared_table_user++;
00355 assert(shared->shared_table_user == 0);
00356 # ifdef OSL_SMP
00357 shared->condition.notify_all();
00358 # endif
00359 }
00360 }
00361 if (! verbose)
00362 return;
00363 const double elapsed = start.elapsedSeconds();
00364 if (removed > 10000 || elapsed > 0.1)
00365 std::cerr << " GC " << removed
00366 << " entries " << std::setprecision(3)
00367 << (unit_size * removed / (1<<20)) << "MB "
00368 << 100.0*removed/total << "%"
00369 << " (" << elapsed << " s)\n";
00370 #endif
00371 }
00372
00373
00374 template <osl::Player P>
00375 osl::ProofDisproof osl::checkmate::
00376 DualDfpn::findProof(int node_limit, const NumEffectState& state,
00377 const HashKey& key, const PathEncoding& path,
00378 Move& best_move, Move last_move)
00379 {
00380 assert(state.turn() == P);
00381
00382 Dfpn& dfpn = prepareDfpn(P);
00383 const OraclePool::List l = shared->pool[P].probe(state);
00384 const PieceStand attack_stand = (P==BLACK) ? key.blackStand() : PieceStand(WHITE, state);
00385 int num_tried = 0;
00386 for (size_t i=0; i<l.size(); ++i)
00387 {
00388 if (! attack_stand.isSuperiorOrEqualTo(l[i].proof_pieces)
00389 || l[i].in_check != state.inCheck())
00390 continue;
00391 ++num_tried;
00392 const ProofDisproof pdp = (node_limit > 20)
00393 ? dfpn.tryProof(state, key, path, l[i].oracle, l[i].id, best_move, last_move)
00394 : dfpn.tryProofLight(state, key, path, l[i].oracle, l[i].id, best_move, last_move);
00395 const size_t count = dfpn.nodeCount();
00396 local->local_node_count += count;
00397 shared->addSimulationNodeCount(count);
00398 if (count) {
00399 #ifdef OSL_SMP
00400 SCOPED_LOCK(lk,shared->proof_by_oracle_mutex[i]);
00401 #endif
00402 shared->proof_by_oracle[i].add(pdp.isCheckmateSuccess());
00403 }
00404 if (pdp.isCheckmateSuccess())
00405 assert(best_move.isNormal());
00406 if (pdp.isFinal())
00407 return pdp;
00408 }
00409 if (node_limit == 0 && num_tried)
00410 return ProofDisproof(1,1);
00411 const ProofDisproof table_pdp = dfpn.hasCheckmateMove(state, key, path, 0, best_move, last_move);
00412 if (table_pdp.isCheckmateSuccess())
00413 return table_pdp;
00414 {
00415 #ifdef OSL_SMP
00416 boost::mutex::scoped_lock lk(shared->mutex);
00417 #endif
00418 Shared::disproof_table_t::const_iterator p = shared->disproof_table.find(key);
00419 if (p != shared->disproof_table.end()) {
00420 BOOST_FOREACH(const PathEncoding& ppath, p->second)
00421 if (ppath == path)
00422 return ProofDisproof::LoopDetection();
00423 }
00424 }
00425 #ifdef OSL_SHOW_PROOF_TREE_MIGRATION_STAT
00426 static stat::Ratio migration_success("migration_success", true);
00427 bool need_migration = false;
00428 #endif
00429
00430 if (node_limit < 80) {
00431 if (local->table_small[P].totalSize() >= local_table_growth_limit) {
00432 local->table_small[P].clear();
00433 }
00434 Dfpn& dfpn_small = prepareDfpnSmall(P);
00435 const ProofDisproof pdp = dfpn_small.hasCheckmateMove(state, key, path, node_limit, best_move, last_move);
00436 const size_t count = dfpn_small.nodeCount();
00437 local->local_node_count += count;
00438 shared->addMainNodeCount(count);
00439 if (pdp.isLoopDetection()) {
00440 #ifdef OSL_SMP
00441 boost::mutex::scoped_lock lk(shared->mutex);
00442 #endif
00443 shared->disproof_table[key].push_front(path);
00444 }
00445 if (! pdp.isCheckmateSuccess())
00446 return pdp;
00447 assert(best_move.isNormal());
00448
00449 #ifdef OSL_SHOW_PROOF_TREE_MIGRATION_STAT
00450 need_migration = true;
00451 #endif
00452 }
00453
00454 Shared::TableUseLock lk(&*shared);
00455 PieceStand proof_pieces;
00456 const ProofDisproof pdp = dfpn.hasCheckmateMove(state, key, path, node_limit, best_move, proof_pieces, last_move);
00457 const size_t count = dfpn.nodeCount();
00458 local->local_node_count += count;
00459 shared->addMainNodeCount(count);
00460 if (pdp.isCheckmateSuccess())
00461 shared->pool[P].addProof(state, key, proof_pieces);
00462 #ifdef OSL_SHOW_PROOF_TREE_MIGRATION_STAT
00463 if (need_migration)
00464 migration_success.add(pdp.isCheckmateSuccess());
00465 #endif
00466 if (pdp.isLoopDetection()) {
00467 #ifdef OSL_SMP
00468 boost::mutex::scoped_lock lk(shared->mutex);
00469 #endif
00470 shared->disproof_table[key].push_front(path);
00471 }
00472 if (pdp.isCheckmateSuccess())
00473 assert(best_move.isNormal());
00474 return pdp;
00475 }
00476
00477 osl::checkmate::ProofDisproof osl::checkmate::
00478 DualDfpn::findProof(int node_limit, const NumEffectState& state,
00479 const HashKey& key, const PathEncoding& path,
00480 Move& best_move, Move last_move)
00481 {
00482 if (state.turn() == BLACK)
00483 return findProof<BLACK>(node_limit, state, key, path, best_move, last_move);
00484 else
00485 return findProof<WHITE>(node_limit, state, key, path, best_move, last_move);
00486 }
00487
00488 bool osl::checkmate::
00489 DualDfpn::isWinningState(int node_limit, const NumEffectState& state,
00490 const HashKey& key, const PathEncoding& path,
00491 Move& best_move, Move last_move)
00492 {
00493 return findProof(node_limit, state, key, path, best_move, last_move)
00494 .isCheckmateSuccess();
00495 }
00496
00497 #ifdef OSL_DFPN_SMP
00498 template <osl::Player P>
00499 bool osl::checkmate::
00500 DualDfpn::isWinningStateParallel(int node_limit, const NumEffectState& state,
00501 const HashKey& key, const PathEncoding& path,
00502 Move& best_move, Move last_move)
00503 {
00504 PieceStand proof_pieces;
00505 size_t count;
00506 ProofDisproof pdp;
00507 {
00508 #ifdef OSL_SMP
00509 boost::mutex::scoped_lock lk(shared->mutex);
00510 #endif
00511 if (! shared->parallel_search)
00512 shared->parallel_search.reset(new DfpnParallel(std::min(OslConfig::numCPUs(), 8)));
00513 #ifdef DFPN_SHARE_TABLE
00514 shared->parallel_search->setTable(&(shared->table[P]));
00515 #else
00516 shared->parallel_search->setTable(&(local->table[P]));
00517 #endif
00518
00519 pdp = shared->parallel_search->hasCheckmateMove
00520 (state, key, path, node_limit, best_move, proof_pieces, last_move);
00521 count = shared->parallel_search->nodeCount();
00522 }
00523 shared->addMainNodeCount(count);
00524 if (pdp.isCheckmateSuccess())
00525 shared->pool[P].addProof(state, key, proof_pieces);
00526 if (pdp.isLoopDetection()) {
00527 shared->disproof_table[key].push_front(path);
00528 }
00529 if (pdp.isCheckmateSuccess())
00530 assert(best_move.isNormal());
00531 return pdp.isCheckmateSuccess();
00532 }
00533
00534 bool osl::checkmate::
00535 DualDfpn::isWinningStateParallel(int node_limit, const NumEffectState& state,
00536 const HashKey& key, const PathEncoding& path,
00537 Move& best_move, Move last_move)
00538 {
00539 if (state.turn() == BLACK)
00540 return isWinningStateParallel<BLACK>(node_limit, state, key, path, best_move, last_move);
00541 else
00542 return isWinningStateParallel<WHITE>(node_limit, state, key, path, best_move, last_move);
00543 }
00544 #endif
00545
00546 template <osl::Player P>
00547 bool
00548 osl::checkmate::
00549 DualDfpn::isLosingState(int node_limit, const NumEffectState& state,
00550 const HashKey& key, const PathEncoding& path,
00551 Move last_move)
00552 {
00553 Shared::TableUseLock lk(&*shared);
00554 assert(state.turn() == P);
00555 Dfpn& dfpn = prepareDfpn(alt(P));
00556 const ProofDisproof pdp = dfpn.hasEscapeMove(state, key, path, node_limit, last_move);
00557 const size_t count = dfpn.nodeCount();
00558 local->local_node_count += count;
00559 shared->addMainNodeCount(count);
00560 return pdp.isCheckmateSuccess();
00561 }
00562
00563 bool osl::checkmate::
00564 DualDfpn::isLosingState(int node_limit, const NumEffectState& state,
00565 const HashKey& key, const PathEncoding& path,
00566 Move last_move)
00567 {
00568 if (state.turn() == BLACK)
00569 return isLosingState<BLACK>(node_limit, state, key, path, last_move);
00570 else
00571 return isLosingState<WHITE>(node_limit, state, key, path, last_move);
00572 }
00573
00574 void osl::checkmate::
00575 DualDfpn::writeRootHistory(const RepetitionCounter& counter,
00576 const MoveStack& moves,
00577 const SimpleState& state, Player attack)
00578 {
00579
00580 Shared::TableUseLock lk(&*shared);
00581 Dfpn& dfpn = prepareDfpn(attack);
00582 PieceStand white_stand(WHITE, state);
00583 for (int i=0; i<counter.checkCount(attack); ++i)
00584 {
00585 const HashKey& key = counter.history().top(i);
00586 if (key != counter.history().top(0))
00587 {
00588 dfpn.setIllegal(key, white_stand);
00589 }
00590 assert(moves.hasLastMove(i+1));
00591 if (! moves.hasLastMove(i+1))
00592 break;
00593 const Move last_move = moves.lastMove(i+1);
00594 if (last_move.isNormal())
00595 white_stand = white_stand.previousStand(WHITE, last_move);
00596 }
00597 }
00598
00599 void osl::checkmate::
00600 DualDfpn::setRootPlayer(Player root)
00601 {
00602 shared->blocking_verify[root] = true;
00603 shared->blocking_verify[alt(root)] = true;
00604 }
00605
00606 void osl::checkmate::
00607 DualDfpn::setVerbose(int )
00608 {
00609 }
00610
00611 int osl::checkmate::
00612 DualDfpn::distance(Player attack, const HashKey& key)
00613 {
00614 Shared::TableUseLock lk(&*shared);
00615 return prepareDfpn(attack).distance(key);
00616 }
00617
00618 size_t osl::checkmate::
00619 DualDfpn::mainNodeCount() const
00620 {
00621 #ifdef OSL_USE_RACE_DETECTOR
00622 boost::mutex::scoped_lock lk(shared->mutex);
00623 #endif
00624 return shared->main_node_count;
00625
00626 }
00627
00628 size_t osl::checkmate::
00629 DualDfpn::totalNodeCount() const
00630 {
00631 #ifdef OSL_USE_RACE_DETECTOR
00632 boost::mutex::scoped_lock lk(shared->mutex);
00633 #endif
00634 return shared->main_node_count + shared->simulation_count;
00635 }
00636
00637 const osl::checkmate::DfpnTable& osl::checkmate::
00638 DualDfpn::table(Player attack) const
00639 {
00640 return shared->table[attack];
00641 }
00642
00643 namespace osl
00644 {
00645 template ProofDisproof checkmate::DualDfpn::findProof<BLACK>
00646 (int, const NumEffectState&, const HashKey&, const PathEncoding&,
00647 Move&, Move);
00648 template ProofDisproof checkmate::DualDfpn::findProof<WHITE>
00649 (int, const NumEffectState&, const HashKey&, const PathEncoding&,
00650 Move&, Move);
00651
00652
00653 template bool checkmate::DualDfpn::isLosingState<BLACK>
00654 (int, const NumEffectState&, const HashKey&, const PathEncoding&, Move);
00655 template bool checkmate::DualDfpn::isLosingState<WHITE>
00656 (int, const NumEffectState&, const HashKey&, const PathEncoding&, Move);
00657
00658 #ifdef OSL_DFPN_SMP
00659 template bool checkmate::DualDfpn::isWinningStateParallel<BLACK>
00660 (int, const NumEffectState&, const HashKey&, const PathEncoding&, Move&, Move);
00661 template bool checkmate::DualDfpn::isWinningStateParallel<WHITE>
00662 (int, const NumEffectState&, const HashKey&, const PathEncoding&, Move&, Move);
00663 #endif
00664 }
00665
00666
00667
00668
00669
00670