ntesukiSearcher.tcc
Go to the documentation of this file.
00001 /* ntesukiSearcher.tcc
00002  */
00003 #include "osl/ntesuki/ntesukiSearcher.h"
00004 #include "osl/ntesuki/ntesukiMove.h"
00005 #include "osl/ntesuki/ntesukiMoveList.h"
00006 #include "osl/ntesuki/ntesukiSimulationSearcher.h"
00007 #include "osl/apply_move/applyMoveWithPath.h"
00008 #include "osl/effect_util/effectUtil.h"
00009 // for release, inline the following templates as well
00010 #ifdef NDEBUG
00011 # include "osl/ntesuki/ntesukiMove.tcc"
00012 # include "osl/ntesuki/ntesukiRecord.tcc"
00013 #endif
00014 
00015 #include "osl/record/csaRecord.h"
00016 #include <climits>
00017 #include <list>
00018 #include <algorithm>
00019 
00020 using namespace osl;
00021 using namespace osl::ntesuki;
00022 
00023 /* 409600 nodes at root node for MTDF
00024  * (/ 40960 8) => 5120
00025  *  cf. 1600 for brinkmate searcher
00026  */
00027 const int READ_ATTACK_BACK_LIMIT = 5120;
00028 
00029 #ifndef NDEBUG
00030 #define RETURN(val)                                                     \
00031   if (record->getValueWithPath<A>(pass_left, path).proof() == 0)\
00032     ntesuki_assert(record->getValueWithPath<A>(pass_left, path).disproof() > ProofDisproof::DISPROOF_LIMIT);\
00033   if (record->getValueWithPath<A>(pass_left, path).disproof() == 0)\
00034     ntesuki_assert(record->getValueWithPath<A>(pass_left, path).proof() > ProofDisproof::PROOF_LIMIT);\
00035   ntesuki_assert(val.isFinal() == record->getValueWithPath<A>(pass_left, path).isFinal());\
00036   return val
00037 #else
00038 #define RETURN(val) return val
00039 #endif
00040 
00041 #define RETURN_ON_STOP \
00042   if (node_count > read_node_limit || *stop_flag)\
00043     return
00044 
00045 /* ===================
00046  * misc
00047  */
00048 static
00049 unsigned int addWithSaturation(unsigned int limit, 
00050                                unsigned int l, unsigned int r)
00051 {
00052   if (limit < l)
00053     return limit;
00054   const unsigned int sum = l+r;
00055   if (limit < sum)
00056     return limit;
00057   // guard against overflow
00058   if (sum < l)
00059     return limit;
00060   ntesuki_assert(r <= sum);
00061   return sum;
00062 }
00063 
00064 struct PlayMoveLock
00065 {
00066   std::vector<Move>& mlist;
00067 
00068   PlayMoveLock(std::vector<Move>& l,
00069                const osl::Move& m)
00070     : mlist(l)
00071   {
00072     mlist.push_back(m);
00073   }
00074 
00075   ~PlayMoveLock()
00076   {
00077     mlist.pop_back();
00078   }
00079 };
00080 
00081 struct LockGC
00082 {
00083   osl::ntesuki::NtesukiTable& table;
00084   LockGC(osl::ntesuki::NtesukiTable& t)
00085     : table(t)
00086   {
00087     table.lockGC();
00088   }
00089 
00090   ~LockGC()
00091   {
00092     table.unlockGC();
00093   }
00094 };
00095 
00096 /* ===================
00097  *  Attack helper
00098  */
00099 template <class Search,Player T>
00100 class 
00101 osl::ntesuki::NtesukiSearcher::
00102 AttackHelper
00103 {
00104   unsigned int proof_limit, disproof_limit, pass_left;
00105   Search* searcher;
00106   NtesukiResult& result;
00107   NtesukiRecord* record;
00108   const NtesukiRecord* oracle_attack;
00109   const NtesukiRecord* oracle_defense;
00110   const Move last_move;
00111 public:
00112   AttackHelper(Search* searcher,
00113                NtesukiResult& result,
00114                NtesukiRecord* record,
00115                const NtesukiRecord* oracle_attack,
00116                const NtesukiRecord* oracle_defense,
00117                unsigned int proof_limit,
00118                unsigned int disproof_limit,
00119                unsigned int pass_left,
00120                const Move last_move)
00121     : proof_limit(proof_limit), disproof_limit(disproof_limit),
00122       pass_left(pass_left),
00123       searcher(searcher),  result(result), record(record),
00124       oracle_attack(oracle_attack), oracle_defense(oracle_defense),
00125       last_move(last_move)
00126   {
00127   }
00128         
00129   void operator()(Square last_to)
00130   {
00131     result = (*searcher).template defense<PlayerTraits<T>::opponent>
00132       (record, oracle_attack, oracle_defense,
00133        proof_limit, disproof_limit, pass_left, last_move);
00134   }
00135 }; // AttackHelper
00136 
00137 /* ===================
00138  *  Call Simulation Attack
00139  */
00140 template <class Search,Player T>
00141 class 
00142 osl::ntesuki::NtesukiSearcher::
00143 CallSimulationAttack
00144 {
00145   Search &simulator;
00146   NtesukiTable& table;
00147   NtesukiRecord *record;
00148   const NtesukiRecord *record_orig;
00149   unsigned int pass_left;
00150   bool& simulation_result;
00151   const Move last_move;
00152 
00153 public:
00154   CallSimulationAttack(Search& simulator,
00155                        NtesukiTable& table,
00156                        NtesukiRecord *record,
00157                        const NtesukiRecord *record_orig,
00158                        unsigned int pass_left,
00159                        bool& simulation_result,
00160                        const Move last_move)
00161     : simulator(simulator), table(table),
00162       record(record), record_orig(record_orig),
00163       pass_left(pass_left),
00164       simulation_result(simulation_result),
00165       last_move(last_move)
00166   {
00167   }
00168         
00169   void operator()(Square last_to)
00170   {
00171     LockGC glock(table);
00172     simulation_result = simulator.template
00173       startFromDefenseDisproof<PlayerTraits<T>::opponent>
00174       (record, record_orig, pass_left, last_move);
00175   }
00176 }; // Call Simulation Attack
00177 
00178 /* ===================
00179   *  Defense helper
00180   */
00181 template <class Search,Player T>
00182 class
00183 osl::ntesuki::NtesukiSearcher::
00184 DefenseHelper
00185 {
00186   unsigned int proof_limit, disproof_limit, pass_left;
00187   Search* searcher;
00188   NtesukiResult& result;
00189   NtesukiRecord* record;
00190   const NtesukiRecord* oracle_attack;
00191   const NtesukiRecord* oracle_defense;
00192   const Move last_move;
00193 
00194 public:
00195   DefenseHelper(Search* searcher,
00196                 NtesukiResult& result,
00197                 NtesukiRecord* record,
00198                 const NtesukiRecord* oracle_attack,
00199                 const NtesukiRecord* oracle_defense,
00200                 unsigned int proof_limit,
00201                 unsigned int disproof_limit,
00202                 unsigned int pass_left,
00203                 const Move last_move)
00204     : proof_limit(proof_limit), disproof_limit(disproof_limit),
00205       pass_left(pass_left), searcher(searcher), result(result), record(record),
00206       oracle_attack(oracle_attack), oracle_defense(oracle_defense),
00207       last_move(last_move)
00208   {
00209   }
00210 
00211   void operator()(Square p)
00212   {
00213     (*searcher).template attack<PlayerTraits<T>::opponent>
00214       (record,  oracle_attack, oracle_defense,
00215        proof_limit, disproof_limit,
00216        pass_left, last_move);
00217   }
00218 };// DefenseHelper
00219 
00220 /* ===================
00221  *  Call Simulation Defense
00222  */
00223 template <class Search,Player T>
00224 class 
00225 osl::ntesuki::NtesukiSearcher::
00226 CallSimulationDefense
00227 {
00228   Search &simulator;
00229   NtesukiTable &table;
00230   NtesukiRecord *record;
00231   const NtesukiRecord *record_orig;
00232   unsigned int pass_left;
00233   bool& simulation_result;
00234   const Move last_move;
00235 public:
00236   CallSimulationDefense(Search& simulator,
00237                         NtesukiTable& table,
00238                         NtesukiRecord *record,
00239                         const NtesukiRecord *record_orig,
00240                         unsigned int pass_left,
00241                         bool& simulation_result,
00242                         const Move last_move)
00243     : simulator(simulator), table(table),
00244       record(record), record_orig(record_orig),
00245       pass_left(pass_left),
00246       simulation_result(simulation_result),
00247       last_move(last_move)
00248   {
00249   }
00250         
00251   void operator()(Square last_to)
00252   {
00253     LockGC glock(table);
00254     simulation_result = simulator.template
00255       startFromAttackProof<PlayerTraits<T>::opponent>
00256       (record, record_orig, pass_left, last_move);
00257   }
00258 }; // Call Simulation Defense
00259 
00260 /* ===================
00261  *  Call Simulation Defense Disproof
00262  */
00263 template <class Search,Player T>
00264 class 
00265 osl::ntesuki::NtesukiSearcher::
00266 CallSimulationDefenseDisproof
00267 {
00268   Search &simulator;
00269   NtesukiTable &table;
00270   NtesukiRecord *record;
00271   const NtesukiRecord *record_orig;
00272   unsigned int pass_left;
00273   bool& simulation_result;
00274   const Move last_move;
00275 public:
00276   CallSimulationDefenseDisproof(Search& simulator,
00277                                 NtesukiTable& table,
00278                                 NtesukiRecord *record,
00279                                 const NtesukiRecord *record_orig,
00280                                 unsigned int pass_left,
00281                                 bool& simulation_result,
00282                                 const Move last_move)
00283     : simulator(simulator), table(table),
00284       record(record), record_orig(record_orig),
00285       pass_left(pass_left),
00286       simulation_result(simulation_result),
00287       last_move(last_move)
00288   {
00289   }
00290         
00291   void operator()(Square last_to)
00292   {
00293     LockGC glock(table);
00294     simulation_result = simulator.template
00295       startFromAttackDisproof<PlayerTraits<T>::opponent>
00296       (record, record_orig, pass_left, last_move);
00297   }
00298 }; // Call Simulation Defense Disproof
00299 
00300 template <Player T>
00301 void osl::ntesuki::NtesukiSearcher::
00302 simulateSiblingsFail(NtesukiRecord *record,
00303                      NtesukiRecord *record_best,
00304                      int pass_left,
00305                      unsigned int& success_count,
00306                      unsigned int& total_count)
00307 {
00308   LockGC glock(table);
00309 
00310   const Player A = T;
00311   if (!record_best) return;
00312   ntesuki_assert(record_best);
00313 
00314   NtesukiMoveList moves;
00315   mg->generate<T>(state, moves);
00316 
00317   for (NtesukiMoveList::iterator move_it = moves.begin();
00318        move_it != moves.end(); move_it++)
00319   {
00320     NtesukiMove& move = *move_it;
00321     NtesukiRecord *record_child = table.allocateWithMove(record,
00322                                                          move);
00323     if (record_child == 0)
00324     {
00325       *stop_flag = TableLimitReached;
00326       return;
00327     }
00328     ntesuki_assert(record_child);
00329     if (record_child == record_best) continue;
00330     if (record_child->isVisited()) continue;
00331     if (move.isCheckmateFail<A>(pass_left)) continue;
00332     const PathEncoding path_child(path, move.getMove());
00333     const NtesukiResult result_child = record_child->getValueWithPath<A>(pass_left,
00334                                                                          path_child);
00335     if (result_child.isFinal())
00336     {
00337       continue;
00338     }
00339 
00340     bool simulation_result;
00341     total_count++;
00342     CallSimulationAttack<NtesukiSimulationSearcher, T>
00343       helper(simulator, table, record_child, record_best,
00344              pass_left, simulation_result, move.getMove());
00345     TRY_DFPN;
00346     ApplyMoveWithPath<T>::doUndoMoveOrPass(state, path, move.getMove(), helper);
00347     CATCH_DFPN;
00348     RETURN_ON_STOP;
00349 
00350     if (simulation_result)
00351     {
00352       success_count++;
00353       ntesuki_assert(record_child->getValueWithPath<A>(pass_left,
00354                                                        path_child).isCheckmateFail());
00355       TRY_DFPN;
00356       move.setBySimulation();
00357       move.setCheckmateFail<A>(pass_left);
00358       CATCH_DFPN;
00359     }
00360   }
00361 }
00362 
00363 /* ===================
00364  * Count the increase of child nodes
00365  */
00366 class CountChildLock
00367 {
00368 public:
00369   CountChildLock(NtesukiRecord* r,
00370                  const NtesukiTable& t)
00371     : record(r), table(t)
00372   {
00373     size_start = table.size();
00374   }
00375 
00376   ~CountChildLock()
00377   {
00378     record->addChildCount(table.size() - size_start);
00379   }
00380 private:
00381   osl::ntesuki::NtesukiRecord* record;
00382   const osl::ntesuki::NtesukiTable& table;
00383   unsigned int size_start;
00384 };
00385 
00386 
00387 /* ===================
00388  * Attack
00389  */
00390 template <Player T>
00391 NtesukiResult osl::ntesuki::NtesukiSearcher::
00392 attack(NtesukiRecord* record,
00393        const NtesukiRecord* oracle_attack,
00394        const NtesukiRecord* oracle_defense,
00395        unsigned int proof_limit, unsigned int disproof_limit,
00396        const int pass_left, const Move last_move)
00397 {
00398   CountChildLock cclock(record, table);
00399   const Player A = T;
00400 #ifndef NDEBUG
00401   const Player D = PlayerTraits<T>::opponent;
00402 #endif
00403 
00404   ntesuki_assert(T == state.turn());
00405   ntesuki_assert(!state.inCheck(D));
00406   ntesuki_assert(proof_limit < ProofDisproof::PROOF_LIMIT);
00407   ntesuki_assert(disproof_limit < ProofDisproof::DISPROOF_LIMIT);
00408   ntesuki_assert(record->getValueOr<A>(pass_left, path, iwscheme).proof()
00409                  < proof_limit);
00410   ntesuki_assert(record->getValueOr<A>(pass_left, path, iwscheme).disproof()
00411                  < disproof_limit);
00412 
00413   RETURN_ON_STOP (record->getValueOr<A>(pass_left, path, iwscheme));
00414 
00415   ntesuki_assert(record->getValueOr<A>(pass_left, path, iwscheme).proof()
00416                  < proof_limit);
00417   ntesuki_assert(record->getValueOr<A>(pass_left, path, iwscheme).disproof()
00418                  < disproof_limit);
00419   ntesuki_assert(record->getBestMove<A>(pass_left).isInvalid());
00420   
00421   ntesuki_assert(proof_limit > 0);
00422   ntesuki_assert(disproof_limit > 0);
00423   
00424   /* ノードの初期化. 必要なら FixedDepthSearcher も呼ばれる.
00425    */
00426   TRY_DFPN;
00427   if (record->setUpNode<T>())
00428   {
00429     const NtesukiResult result_cur =
00430       record->getValueWithPath<A>(pass_left, path);
00431     if (result_cur.isCheckmateSuccess())
00432     {
00433       /* By fixed searcher */
00434       ++immediate_win;
00435       RETURN (result_cur);
00436     }
00437     else if (result_cur.isCheckmateFail() && pass_left == 0)
00438     {
00439       RETURN (result_cur);
00440     }
00441   }
00442   CATCH_DFPN;
00443 
00444   /* Iterative Wideningc Scheme に応じて探索
00445    */
00446   NtesukiResult result_cur = record->getValueOr<A>(pass_left, path, iwscheme);
00447   while ((result_cur.proof() < proof_limit) &&
00448          (result_cur.disproof() < disproof_limit))
00449   {
00450     if (iwscheme == NtesukiRecord::no_iw)
00451     {
00452       /* Order は変えない
00453        */
00454       TRY_DFPN;
00455       attackWithOrder<T>(record, NULL, NULL,
00456                          proof_limit, disproof_limit,
00457                          pass_left, last_move);
00458       
00459       CATCH_DFPN;
00460       RETURN_ON_STOP (result_cur);
00461     }// no_iw
00462     else if (iwscheme == NtesukiRecord::strict_iw)
00463     {
00464       /* 必ず小さい方から探索
00465        */
00466       for (int pass_left_child = 0; pass_left_child <= pass_left; pass_left_child++)
00467       {
00468         NtesukiResult result_st = record->getValueWithPath<A>(pass_left_child, path);
00469         if (!result_st.isCheckmateFail())
00470         {
00471           ntesuki_assert(result_st.proof() < proof_limit);
00472           ntesuki_assert(result_st.disproof() < disproof_limit);
00473           TRY_DFPN;      
00474           attackWithOrder<T>(record, NULL, NULL,
00475                              proof_limit, disproof_limit,
00476                              pass_left_child, last_move);
00477           
00478           CATCH_DFPN;
00479           RETURN_ON_STOP (result_cur);
00480           break;
00481         }
00482       }
00483     }// strict_iw
00484     else if (iwscheme == NtesukiRecord::pn_iw)
00485     {
00486       /* proof number の小さい方から探索
00487        */
00488       unsigned int p_min = ProofDisproof::BigProofNumber,
00489         p_2nd = ProofDisproof::BigProofNumber;
00490       int pass_left_best = -1;
00491       for (int pass_left_child = 0; pass_left_child <= pass_left; pass_left_child++)
00492       {
00493         NtesukiResult result_st = record->getValueWithPath<A>(pass_left_child, path);
00494         if (result_st.isCheckmateFail()) continue;
00495         
00496         const unsigned int proof = result_st.proof();
00497         if (proof < p_min)
00498         {
00499           pass_left_best = pass_left_child;
00500           p_2nd = p_min;
00501           p_min = proof;
00502         }
00503         else if (proof < p_2nd)
00504         {
00505           p_2nd = proof;
00506         }
00507       }
00508 
00509       unsigned int proof_limit_child = std::min(proof_limit, p_2nd + 1);
00510       unsigned int disproof_limit_child = disproof_limit;
00511       TRY_DFPN;      
00512       attackWithOrder<T>(record, NULL, NULL,
00513                          proof_limit_child, disproof_limit_child,
00514                          pass_left_best, last_move);
00515       
00516       CATCH_DFPN;
00517       RETURN_ON_STOP (result_cur);
00518     }// pn_iw
00519     result_cur = record->getValueOr<A>(pass_left, path, iwscheme);
00520   }
00521   return result_cur;
00522 }
00523 
00524 template <Player T>
00525 void osl::ntesuki::NtesukiSearcher::
00526 attackWithOrder(NtesukiRecord* record,
00527                 const NtesukiRecord* oracle_attack,
00528                 const NtesukiRecord* oracle_defense,
00529                 unsigned int proof_limit, unsigned int disproof_limit,
00530                 const int pass_left, const Move last_move)
00531 {
00532   ++node_count;
00533 
00534   const Player A = T;
00535 #ifndef NDEBUG
00536   const Player D = PlayerTraits<T>::opponent;
00537 #endif
00538   ntesuki_assert(T == state.turn());
00539   ntesuki_assert(!state.inCheck(D));
00540   ntesuki_assert(proof_limit < ProofDisproof::PROOF_LIMIT);
00541   ntesuki_assert(disproof_limit < ProofDisproof::DISPROOF_LIMIT);
00542 
00543   RETURN_ON_STOP;
00544   const bool under_attack = state.inCheck(T);
00545 
00546   ntesuki_assert (record->getValueWithPath<A>(pass_left, path).proof()
00547                   < proof_limit);
00548   ntesuki_assert (record->getValueWithPath<A>(pass_left, path).disproof()
00549                   < disproof_limit);
00550   ntesuki_assert(record->getBestMove<A>(pass_left).isInvalid());
00551   
00552   NtesukiRecord::VisitLock visitLock(record);
00553 
00554   ntesuki_assert(proof_limit > 0);
00555   ntesuki_assert(disproof_limit > 0);
00556   
00557   NtesukiMoveList moves;
00558   /* 手の生成
00559    */
00560   TRY_DFPN;
00561   record->generateMoves<T>(moves, pass_left, false);
00562   CATCH_DFPN;
00563 
00564   /* collect statistic information */
00565   ++attack_node_count;
00566   if (under_attack)
00567   {
00568     ++attack_node_under_attack_count;
00569   }
00570   attack_node_moves_count += moves.size();
00571 
00572   /* 攻め手がなくなる→失敗 */
00573   if (moves.empty())
00574   {
00575     if (pass_left != 0 &&
00576         record->rzone_move_generation)
00577     {   
00578       /* まだ未生成の手がある */
00579       NtesukiResult r = record->getValueWithPath<A>(pass_left - 1, path);
00580       
00581       if (r.isCheckmateFail())
00582       {
00583         /* rzone はこれ以上は拡大しない */
00584         record->rzone_move_generation = false;
00585         TRY_DFPN;
00586         record->setResult<A>(pass_left, ProofDisproof(1,1),
00587                              NtesukiMove::INVALID(), false);
00588         CATCH_DFPN;
00589       }
00590       else
00591       {
00592         /* rzone が増えるまで,より低い order での探索を優先させる */
00593         TRY_DFPN;
00594         record->setResult<A>(pass_left, ProofDisproof(r.proof() + 2,
00595                                                       r.disproof() + 2),
00596                              NtesukiMove::INVALID(), false);
00597         CATCH_DFPN;
00598       }
00599       return;
00600     }
00601     TRY_DFPN;
00602     /* 双玉問題なら D の NoEscape だが,
00603      * 片玉問題で,全合法手を生成しない場合(pass_left==0 の場合など)では
00604      * ただの NoCheckmate */
00605     record->setResult<A>(pass_left, ProofDisproof::NoCheckmate(),
00606                          NtesukiMove::INVALID(), false);
00607     CATCH_DFPN;
00608     return;
00609   }
00610 
00611   ntesuki_assert(!moves.empty());
00612   ntesuki_assert(record->getValueWithPath<A>(pass_left, path).proof() != 0);
00613   ntesuki_assert(record->getValueWithPath<A>(pass_left, path).disproof() != 0);
00614 
00615   /* 攻める手の実行
00616    */
00617   for (;;)
00618   {
00619     ntesuki_assert(record->getValueWithPath<A>(pass_left, path).proof() != 0);
00620     ntesuki_assert(record->getValueWithPath<A>(pass_left, path).disproof() != 0);
00621 
00622     unsigned int best_proof = ProofDisproof::BigProofNumber,
00623       best_disproof = 0,
00624       second_proof = ProofDisproof::BigProofNumber,
00625       sum_disproof = 0;
00626     unsigned int step_cost = 1;
00627 
00628     NtesukiMove* best_move =
00629       selectMoveAttack<T>(record,
00630                           best_proof, sum_disproof,
00631                           second_proof, best_disproof,
00632                           step_cost,
00633                           moves,
00634                           pass_left);
00635     if (best_move == NULL)
00636     {
00637       if (pass_left != 0 &&
00638           record->rzone_move_generation)
00639       { 
00640         /* まだ未生成の手がある */
00641         NtesukiResult r = record->getValueWithPath<A>(pass_left - 1, path);
00642         
00643         if (r.isCheckmateFail())
00644         {
00645           /* rzone はこれ以上は拡大しない */
00646           record->rzone_move_generation = false;
00647           TRY_DFPN;
00648           record->setResult<A>(pass_left, ProofDisproof(1,1),
00649                                NtesukiMove::INVALID(), false);
00650           CATCH_DFPN;
00651         }
00652         else
00653         {
00654           /* rzone が増えるまで,より低い order での探索を優先させる */
00655           TRY_DFPN;
00656           record->setResult<A>(pass_left, ProofDisproof(r.proof() + 2,
00657                                                         r.disproof() + 2),
00658                                NtesukiMove::INVALID(), false);
00659           CATCH_DFPN;
00660         }
00661       }
00662       else
00663       {
00664         ntesuki_assert(record->getValueWithPath<A>(pass_left, path).disproof() == 0);
00665       }
00666       return;
00667     }
00668     else if (best_move->isCheckmateSuccess<A>(pass_left))
00669     {
00670       return;
00671     }
00672 
00673     /* このノードの証明数・反証数を設定する
00674      */
00675     const NtesukiResult result_cur(best_proof, sum_disproof);
00676     record->setResult<A>(pass_left, result_cur,
00677                          NtesukiMove::INVALID(), false);
00678 
00679     /* 他を読む
00680      */
00681     if ((proof_limit <= best_proof) ||
00682         (disproof_limit <= sum_disproof))
00683     {
00684       ntesuki_assert(!result_cur.isFinal());
00685       return;
00686     }
00687 
00688     /* 手を試す
00689      */
00690     unsigned int proof_child = std::min(proof_limit, second_proof + step_cost);
00691     ntesuki_assert(disproof_limit > sum_disproof);// disproof_child
00692     unsigned int disproof_child =
00693       addWithSaturation(ProofDisproof::DISPROOF_LIMIT,
00694                         disproof_limit, best_disproof)
00695       - sum_disproof;
00696 
00697     NtesukiRecord *record_child = table.allocateWithMove(record, *best_move);
00698     if (record_child == 0)
00699     {
00700       *stop_flag = TableLimitReached;
00701       return;
00702     }
00703     ntesuki_assert(record_child);
00704     const PathEncoding path_child(path, best_move->getMove());
00705     NtesukiResult result_child = record_child->getValueWithPath<A>(pass_left,
00706                                                                    path_child);
00707     if (!result_child.isFinal())
00708     {
00709       if (best_move->isCheck())
00710       {
00711         oracle_attack = NULL;
00712       }
00713       if (ptt_aunt &&
00714           pass_left != 0 &&
00715           record->getValueWithPath<A>(pass_left - 1, path).isCheckmateFail())
00716       {
00717         oracle_defense = record;
00718       }
00719 
00720       AttackHelper<NtesukiSearcher, T> helper(this,
00721                                               result_child,
00722                                               record_child,
00723                                               oracle_attack,
00724                                               oracle_defense,
00725                                               proof_child,
00726                                               disproof_child,
00727                                               pass_left,
00728                                               best_move->getMove());
00729       PlayMoveLock pml(moves_played, best_move->getMove());
00730       TRY_DFPN;
00731       ApplyMoveWithPath<T>::doUndoMoveOrPass(state, path, best_move->getMove(), helper);
00732       CATCH_DFPN;
00733       record->updateWithChild(record_child, pass_left);
00734       RETURN_ON_STOP;
00735 
00736       const NtesukiResult result_cur = record->getValueWithPath<A>(pass_left, path_child);
00737       if (result_cur.isFinal())
00738       {
00739         return;
00740       }
00741     }
00742 
00743     if (result_child.isPawnDropFoul(best_move->getMove()))
00744     {
00745       best_move->setPawnDropCheckmate();
00746       best_move->setCheckmateFail<A>(pass_left);
00747     }
00748     else if (result_child.isCheckmateSuccess())
00749     {
00750       best_move->setCheckmateSuccess<A>(pass_left);
00751       TRY_DFPN;
00752       record->setResult<A>(pass_left, ProofDisproof::Checkmate(),
00753                            *best_move, false);
00754       CATCH_DFPN;
00755       return;
00756     }
00757     else if (result_child.isCheckmateFail())
00758     {
00759       if (result_child != ProofDisproof::LoopDetection())
00760       {
00761         best_move->setCheckmateFail<A>(pass_left);
00762       }
00763 
00764       if (result_child == ProofDisproof::PawnCheckmate())
00765       {
00766         best_move->setPawnDropCheckmate();
00767       }
00768 
00769       if (ptt_siblings_fail &&
00770           !best_move->isCheck() &&
00771           result_child != ProofDisproof::LoopDetection())
00772       {
00773         TRY_DFPN;
00774         simulateSiblingsFail<T>(record, record_child, pass_left,
00775                                 sibling_attack_success_count,
00776                                 sibling_attack_count);
00777         CATCH_DFPN;
00778       }
00779     }
00780   }//for(;;)
00781 }
00782 
00783 /* dynamic widening */
00784 typedef std::pair<unsigned int, unsigned int> top_pdp_t;
00785 static bool sorter(const top_pdp_t& lhs,
00786                    const top_pdp_t& rhs)
00787 {
00788   if (lhs.first == rhs.first)
00789   {
00790     //return rhs.second > rhs.second;
00791     return rhs.second < rhs.second;
00792   }
00793   else
00794   {
00795     return lhs.first > rhs.first;
00796   }
00797 }
00798 
00799 template <Player T>
00800 osl::ntesuki::NtesukiMove * osl::ntesuki::NtesukiSearcher::
00801 selectMoveAttack(NtesukiRecord* record,
00802                  unsigned int& best_proof,
00803                  unsigned int& sum_disproof,
00804                  unsigned int& second_proof,
00805                  unsigned int& best_disproof,
00806                  unsigned int& step_cost,
00807                  NtesukiMoveList& moves,
00808                  const int pass_left)
00809 {
00810   const Player A = T;
00811 
00812   bool read_nopromote = false;
00813 
00814  re_select_move_attack:
00815   NtesukiMove *best_move = NULL;
00816   
00817   bool loop = false;
00818   bool pawn_checkmate = false;
00819   unsigned short min_child_age = SHRT_MAX;
00820 
00821   int average_cost = 0;
00822   int average_cost_count = 0;
00823 
00824   /* reset values */
00825   best_proof = ProofDisproof::BigProofNumber;
00826   best_disproof = 0;
00827   second_proof = ProofDisproof::BigProofNumber;
00828   sum_disproof = 0;
00829 
00830   /* dynamic Widening */
00831   std::list<top_pdp_t> pdps;
00832 
00833   /* 手を選ぶ
00834    */
00835   for (NtesukiMoveList::iterator move_it = moves.begin();
00836        move_it != moves.end(); ++move_it)
00837   {
00838     NtesukiMove& move = *move_it;
00839     pawn_checkmate |= move.isPawnDropCheckmate();
00840 
00841     if (move.isPass())
00842     {
00843       continue;
00844     }
00845     
00846     if (!move.isCheck() && 0 == pass_left)
00847     {
00848       continue;
00849     }
00850 
00851     if (move.isCheckmateFail<A>(pass_left))
00852     {
00853       continue;
00854     }
00855 
00856     if (delay_nopromote &&
00857         !read_nopromote &&
00858         move.isNoPromote())
00859     {
00860       continue;
00861     }
00862 
00863     if (delay_non_attack &&
00864         !record->readNonAttack(pass_left) &&
00865         ((move.getOrder() > pass_left) ||
00866          move.isLameLong())
00867         )
00868     {
00869       continue;
00870     }
00871     
00872     unsigned int proof = move.h_a_proof;
00873     unsigned int disproof = move.h_a_disproof;
00874 
00875     if (tsumero_estimate && !move.isCheck())
00876     {
00877       proof = tsumero_estimate;
00878       disproof = 1;
00879     }
00880     
00881     average_cost += proof;
00882     average_cost_count++;
00883 
00884     NtesukiRecord *record_child = table.findWithMove(record, move);
00885     if (record_child)
00886     {
00887       if (record_child->isVisited())
00888       {
00889         /* ループ発見 */
00890         /* defender の方からの王手千日手の可能性アリ
00891          */
00892         loop = true;
00893         continue;
00894       }
00895       
00896       const PathEncoding path_child(path, move.getMove());
00897       NtesukiResult result_child;
00898       TRY_DFPN;
00899       result_child =
00900         record_child->getValueAnd<A>(pass_left, path_child,
00901                                      iwscheme, psscheme);
00902       CATCH_DFPN;
00903       proof = result_child.proof();
00904       disproof = result_child.disproof();
00905       
00906       if (0 == disproof)/* 不詰み */
00907       {
00908         if (result_child == ProofDisproof::LoopDetection())
00909         {
00910           loop = true;
00911           continue;
00912         }
00913         if (record_child->getValueWithPath<A>(pass_left, path_child) ==
00914             ProofDisproof::PawnCheckmate())
00915         {
00916           move.setPawnDropCheckmate();
00917           pawn_checkmate = true;
00918         }
00919         
00920         ntesuki_assert(proof >= ProofDisproof::PROOF_LIMIT);
00921         move.setCheckmateFail<A>(pass_left);
00922 
00923         /* should do ptt_siblings_fail */
00924         continue;
00925       }
00926       else if (0 == proof)/* 詰み */
00927       {
00928         /* 打歩詰めだけチェック */
00929         if (record_child->getValueWithPath<A>(pass_left, path_child).
00930             isPawnDropFoul(move.getMove()))
00931         {
00932           move.setPawnDropCheckmate();
00933           move.setCheckmateFail<A>(pass_left);
00934           pawn_checkmate = true;
00935           continue;
00936         }
00937 
00938         /* 間違いなく勝ち手 */
00939         ntesuki_assert(disproof >= ProofDisproof::DISPROOF_LIMIT);
00940         move.setCheckmateSuccess<A>(pass_left);
00941         TRY_DFPN;
00942         record->setResult<A>(pass_left, ProofDisproof::Checkmate(),
00943                              move, false);
00944         CATCH_DFPN;
00945         
00946         return &move;
00947       }
00948 
00949       min_child_age = std::min(record_child->distance,
00950                                min_child_age);
00951       if (record_child->distance <= record->distance)
00952       {
00953         if (!record->useOld<A>(pass_left))
00954         {
00955           continue;
00956         }
00957       }
00958 
00959       /* the assertion:
00960        * use_old == (record_child->distance <= record->distance)
00961        * does not hold, as the distance gets updated to youngest.
00962        */
00963     }
00964     
00965     /* Proof Disproof の調整はここで */
00966     if (!move.isCheck())
00967     {
00968       ntesuki_assert(pass_left > 0);
00969       proof += tsumero_cost;
00970       disproof += tsumero_cost;
00971     }
00972 
00973     if (!record->useOld<A>(pass_left)
00974         && !(NtesukiRecord::max_for_split && record->is_split))
00975     {
00976       sum_disproof = addWithSaturation(ProofDisproof::DISPROOF_LIMIT,
00977                                        disproof, sum_disproof);
00978     }
00979     else
00980     {
00981       sum_disproof = std::max(disproof, sum_disproof);
00982     }
00983 
00984     /* best move の設定 */
00985     if (proof < best_proof)
00986     {
00987       best_move = &move;
00988       second_proof = best_proof;
00989       best_proof = proof;
00990       best_disproof = disproof;
00991     }
00992     else if (proof < second_proof)
00993     {
00994       second_proof = proof;
00995     }
00996 
00997     /* dynamic widening: 良い手の選定 */
00998     if (dynamic_widening_width > 0)
00999     {
01000       if (pdps.size() < dynamic_widening_width)
01001       {
01002         pdps.push_back(top_pdp_t(proof, disproof));
01003         //Sorter sorter;
01004         pdps.sort(sorter);
01005       }
01006       else
01007       {
01008         if (pdps.back().first > proof)
01009         {
01010           pdps.pop_back();
01011           pdps.push_back(top_pdp_t(proof, disproof));
01012         }// back().proof == proof だった場合は?
01013         pdps.sort(sorter);
01014       }
01015     }
01016   }
01017 
01018   /* dynamic widening: 良い手の集計 */
01019   if ((dynamic_widening_width > 0 &&
01020        dynamic_widening_width < moves.size())
01021       &&
01022       (!record->useOld<A>(pass_left)
01023        && !(NtesukiRecord::max_for_split && record->is_split)))
01024   {
01025     sum_disproof = 0;
01026     for (std::list<top_pdp_t>::const_iterator it = pdps.begin();
01027          it != pdps.end(); ++it)
01028     {
01029       sum_disproof += it->second;
01030     }
01031   }
01032 
01033   /* 選んだ手を吟味する
01034    */
01035   if (best_move == NULL)
01036   {
01037     if (false == record->useOld<A>(pass_left))
01038     {
01039       if (SHRT_MAX != min_child_age)
01040       {
01041         record->setUseOld<A>(pass_left, true);
01042 
01043         ntesuki_assert(min_child_age <= record->distance);
01044         record->distance = min_child_age;
01045 
01046         goto re_select_move_attack;
01047       }
01048     }
01049 
01050     if (!record->readNonAttack(pass_left))
01051     {
01052       if (!read_attack_only)
01053       {
01054         record->setReadNonAttack(pass_left);
01055         if (ptt_non_attack &&
01056             pass_left != 0)
01057         {
01058           TRY_DFPN;
01059           handleNonAttack<T>(record, pass_left);
01060           CATCH_DFPN;
01061           RETURN_ON_STOP NULL;
01062         }
01063         record->setUseOld<A>(pass_left, false);
01064         goto re_select_move_attack;
01065       }
01066     }
01067 
01068     if (delay_nopromote &&
01069         !read_nopromote &&
01070         (pass_left > 0 || pawn_checkmate))
01071     {
01072       read_nopromote = true;
01073       record->setUseOld<A>(pass_left, false);
01074       goto re_select_move_attack;
01075     }
01076 
01077     ntesuki_assert(best_proof == ProofDisproof::BigProofNumber);
01078 
01079     if (pass_left != 0 &&
01080         record->rzone_move_generation)
01081     {
01082       /* まだ未生成の手がある */
01083       return NULL;
01084     }
01085     /* 本当に disproof されてしまった */
01086     if (pawn_checkmate)/* 打歩詰めがあった */
01087     {
01088       if (delay_nopromote) assert(read_nopromote);
01089 
01090       TRY_DFPN;
01091       record->setResult<A>(pass_left, ProofDisproof::PawnCheckmate(),
01092                            NtesukiMove::INVALID(), false);
01093       CATCH_DFPN;
01094       return NULL;
01095     }
01096     // pawn checkmate and loop??
01097     else if (loop) /* ループがあった */
01098     {
01099       record->setLoopWithPath<A>(pass_left, path);
01100       TRY_DFPN;
01101       record->setResult<A>(pass_left, NtesukiResult(1, 1),
01102                            NtesukiMove::INVALID(), false);
01103       CATCH_DFPN;
01104       return NULL;
01105     }
01106     else /* 全ての手が普通に反証された */
01107     {
01108       TRY_DFPN;
01109       record->setResult<A>(pass_left, ProofDisproof::NoCheckmate(),
01110                            NtesukiMove::INVALID(), false);
01111       CATCH_DFPN;
01112       return NULL;
01113     }
01114   }
01115 
01116   ntesuki_assert(best_proof != 0);
01117   ntesuki_assert(sum_disproof != 0);
01118   ntesuki_assert(best_proof < ProofDisproof::PROOF_LIMIT);
01119   ntesuki_assert(sum_disproof < ProofDisproof::DISPROOF_LIMIT);
01120 
01121   if (record->useOld<A>(pass_left))
01122   {
01123     ntesuki_assert(min_child_age != SHRT_MAX);
01124     record->distance = min_child_age;
01125   }
01126   average_cost /= average_cost_count;
01127   step_cost = std::max(average_cost, 1);
01128   return best_move;
01129 }
01130 
01131 template <Player T>
01132 void osl::ntesuki::NtesukiSearcher::
01133 handleNonAttack(NtesukiRecord* record,
01134                 int pass_left)
01135 {
01136   const Player A = T;
01137   ntesuki_assert(T == state.turn());
01138 
01139   NtesukiMoveList moves;
01140   mg->generate<T>(state, moves);
01141 
01142   for (NtesukiMoveList::iterator move_it = moves.begin();
01143        move_it != moves.end(); ++move_it)
01144   {
01145     NtesukiRecord *record_best = table.findWithMove(record,
01146                                                      *move_it);
01147     const PathEncoding path_best(path, move_it->getMove());
01148     if (!record_best ||
01149         !record_best->getValueWithPath<A>(pass_left,
01150                                           path_best).isCheckmateFail()) continue;
01151 
01152     /* record_best is checkmate fail */
01153     for (NtesukiMoveList::iterator move_it2 = moves.begin();
01154          move_it2 != moves.end(); ++move_it2)
01155     {
01156       if (move_it2->isPass())
01157       {
01158         continue;
01159       }
01160       if (*move_it2 == *move_it)
01161       {
01162         continue;
01163       }
01164       if (move_it2->isCheckmateFail<A>(pass_left))
01165       {
01166         continue;
01167       }
01168       NtesukiRecord *record_child = table.allocateWithMove(record,
01169                                                            *move_it2);
01170       if (record_child == 0)
01171       {
01172         *stop_flag = TableLimitReached;
01173         return;
01174       }
01175       ntesuki_assert(record_child);
01176       const PathEncoding path_child(path, move_it->getMove());
01177       if(record_child->getValueWithPath<A>(pass_left,
01178                                            path_child).isFinal())
01179       {
01180         continue;
01181       }
01182 
01183       if (record_child->isVisited())
01184       {
01185         TRY_DFPN;
01186         move_it2->setCheckmateFail<A>(pass_left);
01187         record->setLoopWithPath<A>(pass_left, path_child);
01188         CATCH_DFPN;
01189         continue;
01190       }
01191 
01192       bool simulation_result;
01193       CallSimulationAttack<NtesukiSimulationSearcher, T>
01194         helper(simulator, table, record_child, record_best,
01195                pass_left, simulation_result, move_it2->getMove());
01196       TRY_DFPN;
01197       ApplyMoveWithPath<T>::doUndoMoveOrPass(state, path, move_it2->getMove(), helper);
01198       CATCH_DFPN;
01199       RETURN_ON_STOP;
01200 
01201       if (simulation_result)
01202       {
01203         move_it2->setBySimulation();
01204         move_it2->setCheckmateFail<A>(pass_left);
01205       }
01206     }
01207   }
01208 }
01209 
01210 /* ===================
01211  * defense
01212  */
01213 template <Player T>
01214 NtesukiResult osl::ntesuki::NtesukiSearcher::
01215 defense(NtesukiRecord* record,
01216         const NtesukiRecord* oracle_attack,
01217         const NtesukiRecord* oracle_defense,
01218         unsigned int proof_limit, unsigned int disproof_limit,
01219         int pass_left,
01220         const Move last_move)
01221 {
01222   const Player A = PlayerTraits<T>::opponent;
01223   const Player D = T;
01224   CountChildLock cclock(record, table);
01225 
01226   ntesuki_assert(T == state.turn());
01227   ntesuki_assert(proof_limit    < ProofDisproof::PROOF_LIMIT);
01228   ntesuki_assert(disproof_limit < ProofDisproof::DISPROOF_LIMIT);
01229   ntesuki_assert (record->getValueAnd<A>(pass_left, path,
01230                                          iwscheme, psscheme).proof()
01231                   < proof_limit);
01232   ntesuki_assert (record->getValueAnd<A>(pass_left, path,
01233                                          iwscheme, psscheme).disproof()
01234                   < disproof_limit);
01235   
01236   ntesuki_assert(state.inCheck(T) || (pass_left > 0));
01237   ntesuki_assert(!state.inCheck(A));
01238 
01239   ++node_count;
01240   RETURN_ON_STOP (record->getValueAnd<A>(pass_left, path,
01241                                          iwscheme, psscheme));
01242 
01243   ntesuki_assert(record);
01244   ntesuki_assert(!record->getValueWithPath<A>(pass_left, path).isFinal());
01245   ntesuki_assert(record->getBestMove<A>(pass_left).isInvalid());
01246 
01247   NtesukiRecord::VisitLock visitLock(record);
01248 
01249   /* ノードの初期化. 必要なら FixedDepthSearcher も呼ばれる.
01250    */
01251   TRY_DFPN;
01252   if (record->setUpNode<T>())
01253   {
01254     const NtesukiResult r = record->getValueWithPath<A>(pass_left, path);
01255     if (r.isCheckmateFail())
01256     {
01257       /* By fixed searcher */
01258       ++immediate_lose;
01259       RETURN (r);
01260     }
01261     else if (r.isFinal())
01262     {
01263       RETURN (r);
01264     }
01265   }
01266   CATCH_DFPN;
01267 
01268   /* Player Selection Scheme に応じて探索
01269    */
01270   NtesukiResult result_cur = record->getValueAnd<A>(pass_left, path, iwscheme, psscheme);
01271   while ((result_cur.proof() < proof_limit) &&
01272          (result_cur.disproof() < disproof_limit))
01273   {
01274     bool read_attack_first = false;
01275     if (psscheme)
01276     {
01277       /* Dual Lambda 探索を行う:
01278        *  pn_D(n-1) < dn_A(n) なら order を下げて,攻守を入れ換える. ただし,
01279        *   pn_D(n-1) : 受け方の order n-1 における証明数
01280        *   dn_A(n)   : 攻め方の order n における反証数
01281        */
01282       if (pass_left > 0)
01283       {
01284         const NtesukiResult result_attacker =
01285           record->getValueWithPath<A>(pass_left, path);
01286         const NtesukiResult result_defender =
01287           record->getValueOr<D>(pass_left - 1, path, iwscheme);
01288         if (result_defender.proof() < result_attacker.disproof())
01289         {
01290           read_attack_first = true;
01291         }
01292       }
01293     }
01294 
01295     if (read_attack_first)
01296     {
01297       NtesukiRecord::UnVisitLock unVisitLock(record);
01298 
01299       TRY_DFPN;
01300       attack<T>(record, NULL, NULL,
01301                 disproof_limit, proof_limit,
01302                 pass_left - 1, last_move);
01303       CATCH_DFPN;
01304       RETURN_ON_STOP (result_cur);
01305     }
01306     else
01307     {
01308       TRY_DFPN;
01309       defenseWithPlayer<T>(record, oracle_attack, oracle_defense,
01310                            proof_limit, disproof_limit,
01311                            pass_left, last_move);
01312       CATCH_DFPN;
01313       RETURN_ON_STOP (result_cur);
01314     }
01315     result_cur = record->getValueAnd<A>(pass_left, path, iwscheme, psscheme);
01316   }
01317   return result_cur;
01318 }
01319 
01320 template <Player T>
01321 void osl::ntesuki::NtesukiSearcher::
01322 defenseWithPlayer(NtesukiRecord* record,
01323                   const NtesukiRecord* oracle_attack,
01324                   const NtesukiRecord* oracle_defense,
01325                   unsigned int proof_limit, unsigned int disproof_limit,
01326                   int pass_left,
01327                   const Move last_move)
01328 {
01329   const Player A = PlayerTraits<T>::opponent;
01330   const bool under_attack = state.inCheck(T);
01331 
01332   /* 受け手の生成
01333    */
01334   NtesukiMoveList moves;
01335 
01336   TRY_DFPN;
01337   record->generateMoves<T>(moves, pass_left, true);
01338   CATCH_DFPN;
01339 
01340   if (moves.empty())
01341   {
01342     TRY_DFPN;
01343     record->setResult<A>(0, ProofDisproof::NoEscape(),
01344                          NtesukiMove::INVALID(), false);
01345     CATCH_DFPN;
01346     return;
01347   }
01348   
01349   /* collect statistic information */
01350   ++defense_node_count;
01351   if (under_attack)
01352   {
01353     ++defense_node_under_attack_count;
01354   }
01355   defense_node_moves_count += moves.size();
01356 
01357   ntesuki_assert(!moves.empty());
01358   ntesuki_assert(record->getValueWithPath<A>(pass_left, path).isUnknown());
01359 
01360   /* Pass の disproof simulation. */
01361   if (!under_attack &&
01362       record->do_oracle_aunt &&
01363       oracle_defense)
01364   {
01365     record->do_oracle_aunt = false;
01366     
01367     NtesukiMove pass(Move::PASS(T));
01368     NtesukiRecord *record_pass = table.allocateWithMove(record,
01369                                                         pass);
01370     if (record_pass == 0)
01371     {
01372       *stop_flag = TableLimitReached;
01373       return;
01374     }
01375     ntesuki_assert(record_pass);
01376 
01377     if (record_pass->isVisited())
01378     {
01379       /* ループ発見 */
01380       record->setLoopWithPath<A>(pass_left, path);
01381       assert(record->isLoopWithPath<A>(pass_left, path));
01382       TRY_DFPN;
01383       record->setResult<A>(pass_left, NtesukiResult(1, 1),
01384                            NtesukiMove::INVALID(), false);
01385       CATCH_DFPN;
01386       return;
01387     }
01388     
01389     ntesuki_assert(record_pass);
01390     const PathEncoding path_pass(path, pass.getMove());
01391     const NtesukiResult result_pass = record_pass->getValueWithPath<A>(pass_left - 1,
01392                                                                        path_pass);
01393     if (!result_pass.isFinal())
01394     {
01395       bool simulation_result;
01396       CallSimulationDefenseDisproof<NtesukiSimulationSearcher, T>
01397         helper(simulator, table, record_pass, oracle_defense,
01398                pass_left - 1, simulation_result, pass.getMove());
01399       TRY_DFPN;
01400       ApplyMoveWithPath<T>::doUndoMoveOrPass(state, path, pass.getMove(), helper);
01401       CATCH_DFPN;
01402       return;
01403       
01404       if (simulation_result)
01405       {
01406         ntesuki_assert(record_pass->getValueWithPath<A>(pass_left - 1,
01407                                                         path_pass).isCheckmateFail());
01408         pass.setBySimulation();
01409         pass.setCheckmateFail<A>(pass_left);
01410       }
01411     }
01412   }
01413 
01414   /* IS 将棋の simulation */
01415   if (record->do_oracle_attack && oracle_attack)
01416   {
01417     record->do_oracle_attack = false;
01418     
01419     ntesuki_assert(ptt_uncle && !under_attack); // 本来は pass_left >= 1 か
01420     NtesukiMove pass(Move::PASS(T));
01421     
01422     NtesukiRecord *record_pass = table.allocateWithMove(record,
01423                                                         pass);
01424     if (record_pass == 0)
01425     {
01426       *stop_flag = TableLimitReached;
01427       return;
01428     }
01429     ntesuki_assert(record_pass);
01430 
01431     if (record_pass->isVisited())
01432     {
01433       /* ループ発見 */
01434       record->setLoopWithPath<A>(pass_left, path);
01435       assert(record->isLoopWithPath<A>(pass_left, path));
01436       TRY_DFPN;
01437       record->setResult<A>(pass_left, NtesukiResult(1, 1),
01438                            NtesukiMove::INVALID(), false);
01439       CATCH_DFPN;
01440       return;
01441     }
01442     
01443     ntesuki_assert(record_pass);
01444     const PathEncoding path_pass(path, pass.getMove());
01445     const NtesukiResult result_pass = record_pass->getValueWithPath<A>(pass_left - 1,
01446                                                                        path_pass);
01447     if (!result_pass.isFinal())
01448     {
01449       ++isshogi_attack_count;
01450       
01451       bool simulation_result;
01452       CallSimulationDefense<NtesukiSimulationSearcher, T>
01453         helper(simulator, table, record_pass, oracle_attack,
01454                pass_left - 1, simulation_result, pass.getMove());
01455       TRY_DFPN;
01456       ApplyMoveWithPath<T>::doUndoMoveOrPass(state, path, pass.getMove(), helper);
01457       CATCH_DFPN;
01458       return;
01459       
01460       if (simulation_result)
01461       {
01462         ++isshogi_attack_success_count;
01463         ntesuki_assert(record_pass->getValueWithPath<A>(pass_left - 1,
01464                                                         path_pass).isCheckmateSuccess());
01465         pass.setBySimulation();
01466         pass.setCheckmateSuccess<A>(pass_left);
01467         record->setNtesuki<A>(pass_left);
01468         
01469         if (ptt_invalid_defense)
01470         {
01471           TRY_DFPN;
01472           simulateSiblingsSuccess<T>(record, record_pass, pass_left,
01473                                      pass_success_count,
01474                                      pass_count);
01475           CATCH_DFPN;
01476           return;
01477         }
01478       }
01479     }
01480   }
01481 
01482   for (;;)
01483   {
01484     unsigned int best_disproof = ProofDisproof::BigProofNumber,
01485       sum_proof = 0,
01486       second_disproof = ProofDisproof::BigProofNumber,
01487       best_proof = 0;
01488 
01489     unsigned int step_cost = 1;
01490     NtesukiMove *best_move = NULL;
01491 
01492     best_move = selectMoveDefense<T>(record,
01493                                      best_disproof,
01494                                      sum_proof,
01495                                      second_disproof,
01496                                      best_proof,
01497                                      step_cost,
01498                                      moves,
01499                                      pass_left,
01500                                      last_move);
01501     RETURN_ON_STOP;
01502     if (NULL == best_move)
01503     {
01504       ntesuki_assert(record->getValueWithPath<A>(pass_left, path).
01505                      isCheckmateSuccess());
01506       return;
01507     }
01508     else if (best_disproof == 0)
01509     {
01510       ntesuki_assert(best_move->isCheckmateFail<A>(pass_left) ||
01511                      record->isLoopWithPath<A>(pass_left, path));
01512       return;
01513     }
01514 
01515 #ifndef NDEBUG
01516     {     //XXXXXXX
01517       NtesukiRecord* best_child = table.findWithMove(record, *best_move);
01518       if (best_child)
01519       {
01520         const PathEncoding path_child(path, best_move->getMove());
01521         int pass_left_child = pass_left;
01522         if (best_move->isPass()) --pass_left_child;
01523         const NtesukiResult r =
01524           best_child->getValueOr<A>(pass_left_child, path_child,iwscheme);
01525         ntesuki_assert(r.disproof() == best_disproof);
01526         ntesuki_assert(r.proof() <= sum_proof);
01527       }
01528     }     //XXXXXXX
01529 #endif
01530 
01531     /* このノードの証明数・反証数を設定する
01532      */
01533     const NtesukiResult result_cur = ProofDisproof(sum_proof, best_disproof);
01534     record->setResult<A>(pass_left, result_cur,
01535                          NtesukiMove::INVALID(), false);
01536    
01537     /* 他を読む
01538      */
01539     if ((disproof_limit <= best_disproof) ||
01540         (proof_limit <= sum_proof))
01541     {
01542       ntesuki_assert(!result_cur.isFinal());
01543       return;
01544     }
01545 
01546     unsigned int proof_child =
01547       addWithSaturation(ProofDisproof::DISPROOF_LIMIT, 
01548                         proof_limit, best_proof) - sum_proof;
01549     unsigned int disproof_child = std::min(disproof_limit,
01550                                            second_disproof + step_cost);
01551 
01552     /* 手を試す
01553      */
01554     int pass_left_child = pass_left;
01555     if (best_move->isPass())
01556     {
01557       --pass_left_child;
01558     }
01559     NtesukiRecord *record_child =
01560       table.allocateWithMove(record, *best_move);
01561     if (record_child == 0)
01562     {
01563       *stop_flag = TableLimitReached;
01564       return;
01565     }
01566     ntesuki_assert(record_child);
01567     const PathEncoding path_child(path, best_move->getMove());
01568     ntesuki_assert(pass_left_child >= 0);
01569     NtesukiResult result_child =
01570       record_child->getValueOr<A>(pass_left_child,
01571                                   path_child,
01572                                   iwscheme);
01573 
01574     if (!result_child.isFinal())
01575     {
01576       if (best_move->isCheck())
01577       {
01578         if (ptt_uncle &&
01579             !under_attack &&
01580             delay_non_pass)
01581         {
01582           NtesukiMove& pass = moves.front();
01583           ntesuki_assert(pass.isPass());
01584           
01585           oracle_attack = table.findWithMove(record, pass);
01586           ntesuki_assert(oracle_attack);
01587         }
01588       }
01589 
01590       if (result_child.proof() >= proof_child)
01591       {
01592         std::cerr << *record_child
01593                   << result_child << "<- result \n"
01594                   << proof_child << "/" << disproof_child << "<- limit\n"
01595                   << *best_move << "\n"
01596                   << sum_proof << "/" << best_disproof << " <- cur\n";
01597       }
01598       DefenseHelper<NtesukiSearcher, T> helper(this,
01599                                                result_child,
01600                                                record_child,
01601                                                oracle_attack,
01602                                                oracle_defense,
01603                                                proof_child,
01604                                                disproof_child,
01605                                                pass_left_child,
01606                                                best_move->getMove());
01607 
01608       PlayMoveLock pml(moves_played, best_move->getMove());
01609       if (best_move->isPass())
01610       {
01611         NtesukiRecord::pass_count++;
01612       }
01613       TRY_DFPN;
01614       ApplyMoveWithPath<T>::doUndoMoveOrPass(state, path, best_move->getMove(), helper);
01615       CATCH_DFPN;
01616 
01617       if (best_move->isPass())
01618       {
01619         NtesukiRecord::pass_count--;
01620       }
01621       record->updateWithChild(record_child, pass_left);
01622       RETURN_ON_STOP;
01623 
01624       if (record->getValueWithPath<A>(pass_left, path).isFinal())
01625       {
01626         return;
01627       }
01628     }
01629 
01630     /* 結果を吟味する
01631      */
01632     if (result_child.isCheckmateFail())
01633     {
01634       if (result_child == ProofDisproof::AttackBack())
01635       {
01636         ++disproof_by_inversion_count;
01637       }
01638       if (result_child == ProofDisproof::LoopDetection())
01639       {
01640         record->setLoopWithPath<A>(pass_left, path);
01641         TRY_DFPN;
01642         record->setResult<A>(pass_left, NtesukiResult(1, 1),
01643                              NtesukiMove::INVALID(), false);
01644         CATCH_DFPN;
01645         return;
01646       }
01647 
01648       best_move->setCheckmateFail<A>(pass_left);
01649       TRY_DFPN;
01650       record->setResult<A>(pass_left, result_child,
01651                            *best_move, false);
01652       CATCH_DFPN;
01653       return;
01654     }
01655     else if (result_child.isCheckmateSuccess())
01656     {
01657       best_move->setCheckmateSuccess<A>(pass_left);
01658       NtesukiRecord *best_record = table.findWithMove(record, *best_move);
01659       if ((ptt_invalid_defense && best_move->isPass()) ||
01660           (ptt_siblings_success && !best_move->isCheck())
01661           )
01662       {
01663         TRY_DFPN;
01664         simulateSiblingsSuccess<T>(record, best_record, pass_left,
01665                                    sibling_defense_success_count,
01666                                    sibling_defense_count);
01667         CATCH_DFPN;
01668         RETURN_ON_STOP;
01669       }
01670     }
01671   }//for(;;)
01672 }
01673 
01674 template <Player T>
01675 osl::ntesuki::NtesukiMove* osl::ntesuki::NtesukiSearcher::
01676 selectMoveDefense(NtesukiRecord* record,
01677                   unsigned int& best_disproof,
01678                   unsigned int& sum_proof,
01679                   unsigned int& second_disproof,
01680                   unsigned int& best_proof,
01681                   unsigned int& step_cost,
01682                   NtesukiMoveList& moves,
01683                   const int pass_left,
01684                   const Move last_move)
01685 {
01686   const Player A = PlayerTraits<T>::opponent;
01687   const bool under_attack = state.inCheck(T);
01688 
01689   bool read_interpose = record->readInterpose(pass_left);
01690   /* GCによって情報がかわっている可能性が
01691    * bool read_non_pass = record->isNtesuki<A>(pass_left);*/
01692 
01693   bool read_non_pass = under_attack;
01694   if (pass_left > 0 && !under_attack)
01695   {
01696     NtesukiMove pass(Move::PASS(T));
01697     NtesukiRecord *record_pass = table.findWithMove(record, pass);
01698     if (record_pass)
01699     {
01700       const PathEncoding path_child(path, pass.getMove());
01701       read_non_pass =
01702         record_pass->getValueWithPath<A>(pass_left - 1,
01703                                          path_child).isCheckmateSuccess();
01704     }
01705   }
01706   if (under_attack) ntesuki_assert(read_non_pass);
01707 
01708   bool read_check_defense = record->readCheckDefense(pass_left);
01709   if (isscheme == NtesukiRecord::normal_is)
01710   {
01711     read_check_defense = true;
01712   }
01713 
01714  re_select_move_defense:
01715   unsigned short min_child_age = SHRT_MAX;
01716   NtesukiMove *best_move = NULL;
01717 
01718   int average_cost = 0;
01719   int average_cost_count = 0;
01720 
01721   /* reset values */
01722   best_disproof = ProofDisproof::BigProofNumber;
01723   sum_proof = 0;
01724   second_disproof = ProofDisproof::BigProofNumber;
01725   best_proof = 0;
01726 
01727   /* dynamic Widening */
01728   std::list<top_pdp_t> pdps;
01729 
01730   /* 手を選ぶ
01731    */
01732   for (NtesukiMoveList::iterator move_it = moves.begin();
01733        move_it != moves.end(); ++move_it)
01734   {
01735     NtesukiMove& move = *move_it;
01736     if (move.isCheckmateSuccess<A>(pass_left))
01737     {
01738       continue;
01739     }
01740     ntesuki_assert(!move.isCheckmateFail<A>(pass_left));
01741     
01742     if (delay_non_pass &&
01743         !read_non_pass &&
01744         !move.isPass())
01745     {
01746       continue;
01747     }
01748 
01749     if (delay_interpose &&
01750         (move.isInterpose() ||
01751          move.isLameLong()) &&
01752         !read_interpose)
01753     {
01754       continue;
01755     }
01756 
01757     if (move.isCheck() &&
01758         !under_attack &&
01759         !read_check_defense)
01760     {
01761       continue;
01762     }
01763     
01764     unsigned int proof = move.h_d_proof;
01765     unsigned int disproof = move.h_d_disproof;
01766     
01767     average_cost += disproof;
01768     average_cost_count++;
01769 
01770     NtesukiRecord *record_child = table.findWithMove(record, move);
01771     if (record_child)
01772     {
01773       int pass_left_child = pass_left;
01774       if (move.isPass()) --pass_left_child;
01775       const PathEncoding path_child(path, move.getMove());
01776       NtesukiResult result_child;
01777       TRY_DFPN;
01778       result_child =
01779         record_child->getValueOr<A>(pass_left_child, path_child,
01780                                     iwscheme);
01781       CATCH_DFPN;
01782       
01783       if (record_child->isVisited())
01784       {
01785         /* ループ発見 */
01786         record->setLoopWithPath<A>(pass_left, path);
01787         ntesuki_assert(record->isLoopWithPath<A>(pass_left, path));
01788         TRY_DFPN;
01789         record->setResult<A>(pass_left, NtesukiResult(1, 1),
01790                              NtesukiMove::INVALID(), false);
01791         CATCH_DFPN;
01792         best_disproof = 0;
01793         return &move;
01794       }
01795 
01796       proof    = result_child.proof();
01797       disproof = result_child.disproof();
01798 
01799       if (result_child.isCheckmateSuccess())//証明
01800       {
01801         ntesuki_assert(disproof >= ProofDisproof::DISPROOF_LIMIT);
01802         move.setCheckmateSuccess<A>(pass_left);
01803         if  (move.isPass())
01804         {
01805           /* 既にパスの後が証明されていた */
01806           record->setNtesuki<A>(pass_left);
01807 
01808           if (ptt_invalid_defense)
01809           {
01810             TRY_DFPN;
01811             simulateSiblingsSuccess<T>(record, record_child, pass_left,
01812                                        pass_success_count,
01813                                        pass_count);
01814             CATCH_DFPN;
01815             RETURN_ON_STOP(NULL);
01816             goto re_select_move_defense;
01817           }
01818         }
01819         if (ptt_siblings_success && !move.isCheck())
01820         {
01821           TRY_DFPN;
01822           simulateSiblingsSuccess<T>(record, record_child, pass_left,
01823                                      sibling_defense_success_count,
01824                                      sibling_defense_count);
01825           CATCH_DFPN;
01826           RETURN_ON_STOP(NULL);
01827           //re search as simulation is done.
01828           goto re_select_move_defense;
01829         }
01830         continue;
01831       }
01832       else if (result_child.isCheckmateFail())//反証
01833       {
01834         if (move.isCheck() && read_check_defense)
01835         {
01836           ++disproof_by_inversion_count;
01837         }
01838         if (result_child == ProofDisproof::LoopDetection())
01839         {
01840           record->setLoopWithPath<A>(pass_left, path);
01841           TRY_DFPN;
01842           record->setResult<A>(pass_left, NtesukiResult(1, 1),
01843                                NtesukiMove::INVALID(), false);
01844           CATCH_DFPN;
01845           best_disproof = 0;
01846           return &move;
01847         }
01848 
01849         ntesuki_assert(proof >= ProofDisproof::PROOF_LIMIT);
01850         move.setCheckmateFail<A>(pass_left);
01851         TRY_DFPN;
01852         record->setResult<A>(pass_left, result_child,
01853                              move, false);
01854         CATCH_DFPN;
01855         best_disproof = 0;
01856         return &move;
01857       }
01858 
01859       min_child_age = std::min(min_child_age,
01860                                record_child->distance);
01861       if ((record_child->distance <= record->distance) &&
01862           !move.isPass())
01863       {
01864         if (!record->useOld<A>(pass_left))
01865         {
01866           continue;
01867         }
01868       }
01869     }/* has record */
01870 
01871     /* Proof Disproof の調整はここでする */
01872     if (record->useOld<A>(pass_left))
01873     {
01874       sum_proof = std::max(proof, sum_proof);
01875     }
01876     else if (NtesukiRecord::max_for_split && record->is_split)
01877     {
01878       sum_proof = std::max(proof, sum_proof);
01879     }
01880     else
01881     {
01882       sum_proof = addWithSaturation(ProofDisproof::PROOF_LIMIT, 
01883                                     proof, sum_proof);
01884     }
01885 
01886     if (disproof < best_disproof)
01887     {
01888       best_move = &move;
01889       second_disproof = best_disproof;
01890       best_disproof = disproof;
01891       best_proof = proof;
01892     }
01893     else if (disproof < second_disproof)
01894     {
01895       second_disproof = disproof;
01896     }
01897 
01898     /* dynamic widening: 良い手の選定 */
01899     if (dynamic_widening_width > 0)
01900     {
01901       if (pdps.size() < dynamic_widening_width)
01902       {
01903         pdps.push_back(top_pdp_t(disproof, proof));
01904         pdps.sort(sorter);
01905       }
01906       else
01907       {
01908         if (pdps.back().first > disproof)
01909         {
01910           pdps.pop_back();
01911           pdps.push_back(top_pdp_t(disproof, proof));
01912         }// back().disproof == disproof だった場合は?
01913         pdps.sort(sorter);
01914       }
01915     }
01916   }/* foreach move */
01917 
01918   /* dynamic widening: 良い手の集計 */
01919   if (dynamic_widening_width > 0 &&
01920        dynamic_widening_width < moves.size())
01921   {
01922     sum_proof = 0;
01923     for (std::list<top_pdp_t>::const_iterator it = pdps.begin();
01924          it != pdps.end(); ++it)
01925     {
01926       sum_proof += it->second;
01927     }
01928   }
01929 
01930   /* 選んだ手を吟味する
01931    */
01932   if (NULL == best_move)
01933   {
01934     ntesuki_assert(sum_proof == 0);
01935     /* パスだけ先に読む enhancement */
01936     if (delay_non_pass &&
01937         read_non_pass == false)
01938     {
01939       ntesuki_assert(!under_attack);
01940       
01941       read_non_pass = true;
01942       record->setUseOld<A>(pass_left, false);
01943       record->setNtesuki<A>(pass_left);
01944 
01945       if (ptt_invalid_defense)
01946       {
01947         NtesukiMove move_pass = moves.front();
01948         ntesuki_assert(move_pass.isPass());
01949         NtesukiRecord *record_pass = table.findWithMove(record, move_pass);
01950         const PathEncoding path_child(path, move_pass.getMove());
01951         
01952         ntesuki_assert(record_pass->getValueWithPath<A>(pass_left - 1,
01953                                                         path_child).isCheckmateSuccess());
01954         TRY_DFPN;
01955         simulateSiblingsSuccess<T>(record, record_pass, pass_left,
01956                                    pass_success_count,
01957                                    pass_count);
01958         CATCH_DFPN;
01959         RETURN_ON_STOP(NULL);
01960       }
01961       goto re_select_move_defense;
01962     } /* delay non pass */
01963 
01964     if (!record->useOld<A>(pass_left))
01965     {
01966       if (SHRT_MAX != min_child_age)
01967       {
01968         record->setUseOld<A>(pass_left, true);
01969 
01970         ntesuki_assert(min_child_age <= record->distance);
01971         record->distance = min_child_age;
01972 
01973         goto re_select_move_defense;
01974       }
01975     }
01976 
01977     if (delay_interpose &&
01978         read_interpose == false)
01979     {
01980       read_interpose = true;
01981       record->setUseOld<A>(pass_left, false);
01982       record->setReadInterpose(pass_left);
01983       TRY_DFPN;
01984       handleInterpose<T>(record, pass_left);
01985       CATCH_DFPN;
01986       RETURN_ON_STOP NULL;
01987 
01988       goto re_select_move_defense;
01989     }
01990 
01991     /* 逆王手の扱い */
01992     switch(isscheme)
01993     {
01994     case NtesukiRecord::no_is:
01995       ntesuki_assert(read_check_defense == false);
01996       break;
01997     case NtesukiRecord::tonshi_is:
01998       handleTonshi<T>(record, pass_left, last_move);
01999       RETURN_ON_STOP NULL;
02000       break;
02001     case NtesukiRecord::delay_is:
02002       if (read_check_defense == false)
02003       {
02004         ++proof_without_inversion_count;
02005         read_check_defense = true;
02006         record->setReadCheckDefense(pass_left);
02007         goto re_select_move_defense;
02008       }
02009       break;
02010     case NtesukiRecord::normal_is:
02011       ntesuki_assert(read_check_defense == true);
02012       break;
02013     }
02014 
02015     /* 全ての手が普通に証明された */
02016     TRY_DFPN;
02017     record->setResult<A>(pass_left, ProofDisproof::Checkmate(),
02018                          NtesukiMove::INVALID(), false);
02019     CATCH_DFPN;
02020     return NULL;
02021   }
02022   ntesuki_assert(best_move);
02023   ntesuki_assert(sum_proof != 0);
02024   ntesuki_assert(best_disproof != 0);
02025 
02026   if (record->useOld<A>(pass_left))
02027   {
02028     ntesuki_assert(min_child_age != SHRT_MAX);
02029     record->distance = min_child_age;
02030   }
02031   average_cost /= average_cost_count;
02032   step_cost = std::max(average_cost, 1);
02033   return best_move;
02034 }
02035 
02036 template <Player T>
02037 void osl::ntesuki::NtesukiSearcher::
02038 handleTonshi(NtesukiRecord *record,
02039              int pass_left,
02040              const Move last_move)
02041 {
02042   const Player A = PlayerTraits<T>::opponent;
02043   const Player D = T;
02044 
02045   if (pass_left > 0)
02046   {
02047     NtesukiResult result_defender =
02048       record->getValueWithPath<D>(pass_left - 1, path);
02049     if (!result_defender.isFinal())
02050     {
02051       /* to make sure not to come back here
02052        */
02053       record->setResult<A>(pass_left, ProofDisproof::Bottom(),
02054                            NtesukiMove::INVALID(), false);
02055       const unsigned int read_node_limit_orig = read_node_limit;
02056       int ratio = 1;
02057       
02058       if ((record->distance / 2) == 0)
02059         ratio = 8;
02060       else if ((record->distance / 2) == 1)
02061         ratio = 2;
02062       
02063       read_node_limit = node_count + READ_ATTACK_BACK_LIMIT * ratio;
02064       
02065       NtesukiRecord::UnVisitLock unVisitLock(record);
02066       TRY_DFPN;
02067       result_defender = attack<T>(record, NULL, NULL,
02068                                   INITIAL_PROOF_LIMIT, INITIAL_PROOF_LIMIT,
02069                                   pass_left - 1, last_move);
02070       CATCH_DFPN;
02071       
02072       if (result_defender.isCheckmateSuccess())
02073       {
02074         ++attack_back_count;
02075       }
02076       
02077       read_node_limit = read_node_limit_orig;
02078       RETURN_ON_STOP;
02079     }
02080     
02081     if (result_defender.isFinal())
02082     {
02083       return;
02084     }
02085   }
02086 }
02087 
02088 template <Player T>
02089 void osl::ntesuki::NtesukiSearcher::
02090 simulateSiblingsSuccess(NtesukiRecord *record,
02091                         NtesukiRecord *record_best,
02092                         int pass_left,
02093                         unsigned int& success_count,
02094                         unsigned int& total_count)
02095 {
02096   LockGC glock(table);
02097 
02098   const Player A = PlayerTraits<T>::opponent;
02099   if (!record_best) return;
02100   ntesuki_assert(record_best);
02101   ntesuki_assert(record_best->getValue<A>(pass_left).isCheckmateSuccess());
02102 
02103   NtesukiMoveList moves;
02104   mg->generate<T>(state, moves);
02105 
02106   for (NtesukiMoveList::iterator move_it = moves.begin();
02107        move_it != moves.end(); ++move_it)
02108   {
02109     NtesukiMove& move = *move_it;
02110     NtesukiRecord *record_child = table.allocateWithMove(record,
02111                                                          move);
02112     if (record_child == 0)
02113     {
02114       *stop_flag = TableLimitReached;
02115       return;
02116     }
02117     ntesuki_assert(record_child);
02118     if (record_child == record_best) continue;
02119     if (record_child->isVisited()) continue;
02120     
02121     ntesuki_assert(record_child);
02122     const PathEncoding path_child(path, move.getMove());
02123     const NtesukiResult result_child = record_child->getValueWithPath<A>(pass_left,
02124                                                                          path_child);
02125     if (result_child.isFinal())
02126     {
02127       continue;
02128     }
02129 
02130     bool simulation_result;
02131     total_count++;
02132     CallSimulationDefense<NtesukiSimulationSearcher, T>
02133       helper(simulator, table, record_child, record_best,
02134              pass_left, simulation_result, move.getMove());
02135     TRY_DFPN;
02136     ApplyMoveWithPath<T>::doUndoMoveOrPass(state, path, move.getMove(), helper);
02137     CATCH_DFPN;
02138     RETURN_ON_STOP;
02139 
02140     if (simulation_result)
02141     {
02142       success_count++;
02143       ntesuki_assert(record_child->getValueWithPath<A>(pass_left,
02144                                                        path_child).isCheckmateSuccess());
02145       move.setBySimulation();
02146       move.setCheckmateSuccess<A>(pass_left);
02147     }
02148   }
02149 }
02150 
02151 template <Player T>
02152 void osl::ntesuki::NtesukiSearcher::
02153 handleInterpose(NtesukiRecord* record,
02154                 int pass_left)
02155 {
02156   const Player A = PlayerTraits<T>::opponent;
02157   ntesuki_assert(T == state.turn());
02158 
02159   NtesukiMoveList moves;
02160   mg->generate<T>(state, moves);
02161 
02162   for (NtesukiMoveList::iterator move_it = moves.begin();
02163        move_it != moves.end(); ++move_it)
02164   {
02165     if (move_it->isInterpose() &&
02166         !move_it->isCheckmateSuccess<A>(pass_left))
02167     {
02168       NtesukiRecord *record_child = table.allocateWithMove(record,
02169                                                            *move_it);
02170       if (record_child == 0)
02171       {
02172         *stop_flag = TableLimitReached;
02173         return;
02174       }
02175       ntesuki_assert(record_child);
02176 
02177       const PathEncoding path_child(path, move_it->getMove());
02178       if(record_child->getValueWithPath<A>(pass_left,
02179                                            path_child).isFinal())
02180       {
02181         continue;
02182       }
02183       ntesuki_assert(record_child->getBestMove<A>(pass_left).isInvalid());
02184       
02185       NtesukiMoveList::iterator best_it = moves.begin();
02186       for (; best_it != moves.end(); ++best_it)
02187       {
02188         if (best_it->to() == move_it->to() &&
02189             best_it->isCheckmateSuccess<A>(pass_left)) break;
02190       }
02191       if (best_it == moves.end())
02192       {
02193         continue;
02194       }
02195       const NtesukiRecord* record_best = table.findWithMove(record, *best_it);
02196       ntesuki_assert(record_best);
02197 
02198       bool simulation_result;
02199       CallSimulationDefense<NtesukiSimulationSearcher, T>
02200         helper(simulator, table, record_child, record_best,
02201                pass_left, simulation_result, move_it->getMove());
02202       TRY_DFPN;
02203       ApplyMoveWithPath<T>::doUndoMoveOrPass(state, path, move_it->getMove(), helper);
02204       CATCH_DFPN;
02205       RETURN_ON_STOP;
02206 
02207       if (simulation_result)
02208       {
02209         move_it->setBySimulation();
02210         move_it->setCheckmateSuccess<A>(pass_left);
02211       }
02212       else if (record_child->getValue<A>(pass_left).isCheckmateFail())
02213       {
02214         break;
02215       }
02216     }
02217   }
02218 }
02219 
02220 /* 外から呼ばれる関数.
02221  */
02222 template <Player A>
02223 int  osl::ntesuki::NtesukiSearcher::
02224 search()
02225 {
02226   NtesukiRecord::pass_count = 0;
02227   const Player D = PlayerTraits<A>::opponent;
02228   //const HashKey key = HashKey::calcHash(state);  
02229   const HashKey key(state);  
02230 
02231   NtesukiRecord *record = table.allocateRoot(key, PieceStand(WHITE, state),
02232                                              0, &state);
02233   ntesuki_assert(record);
02234 
02235   NtesukiResult result;
02236   if (A == state.turn())
02237   {
02238     const Player T = A;
02239     result = attack<T>(record, NULL, NULL,
02240                        INITIAL_PROOF_LIMIT,
02241                        INITIAL_DISPROOF_LIMIT,
02242                        max_pass - 1, Move::INVALID());
02243   }
02244   else//A != turn
02245   {
02246     const Player T = D;
02247     if (0 == (max_pass - 1) &&
02248         !state.inCheck(D))
02249     {
02250       if (verbose) std::cerr << "No Check" << std::endl;
02251       return NtesukiNotFound;
02252     }
02253     else
02254     {
02255       result = defense<T>(record, NULL, NULL,
02256                           INITIAL_PROOF_LIMIT,
02257                           INITIAL_DISPROOF_LIMIT,
02258                           max_pass - 1,
02259                           Move::INVALID());
02260     }
02261   }
02262 
02263   if (node_count > read_node_limit || *stop_flag)
02264   {
02265     if (verbose) std::cerr << "Limit Reached\t" << result << std::endl;
02266     return ReadLimitReached;
02267   }
02268   else
02269   {
02270     if (verbose) std::cerr << "result:\t" << result << std::endl;
02271     if (result.isCheckmateSuccess())
02272     {
02273       for (unsigned int i = 0; i < max_pass; ++i)
02274       {
02275         if (record->getValue<A>(i).isCheckmateSuccess())
02276         {
02277           return i;
02278         }
02279       }
02280     }
02281   }
02282   
02283   ntesuki_assert(result.isCheckmateFail());
02284   return NtesukiNotFound;
02285 }
02286 // ;;; Local Variables:
02287 // ;;; mode:c++
02288 // ;;; c-basic-offset:2
02289 // ;;; End:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines