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