00001
00002
00003 #include "osl/annotate/analyzer.h"
00004 #include "osl/checkmate/dualDfpn.h"
00005 #include "osl/checkmate/dfpn.h"
00006 #ifdef OSL_DFPN_SMP
00007 # include "osl/checkmate/dfpnParallel.h"
00008 #endif
00009 #include "osl/move_generator/legalMoves.h"
00010 #include "osl/apply_move/applyMove.h"
00011 #include "osl/threatmate/mlPredictor.h"
00012 #include "osl/effect_util/neighboring8Direct.h"
00013 #include "osl/eval/see.h"
00014 #include "osl/eval/ml/openMidEndingEval.h"
00015 #include "osl/game_playing/alphaBetaPlayer.h"
00016 #include "osl/game_playing/gameState.h"
00017 #include <boost/foreach.hpp>
00018
00019 const int checkmate_limit = 1000000/2;
00020
00021 osl::annotate::
00022 Analyzer::~Analyzer()
00023 {
00024 }
00025
00026 osl::annotate::Trivalent osl::annotate::
00027 Analyzer::isCheckmate(NumEffectState& state, Move& best_move, bool attack, size_t *node_count)
00028 {
00029 #ifdef OSL_DFPN_SMP
00030 checkmate::DfpnParallel dfpn;
00031 #else
00032 checkmate::Dfpn dfpn;
00033 #endif
00034 checkmate::DfpnTable table(attack ? state.getTurn() : alt(state.getTurn()));
00035 dfpn.setTable(&table);
00036 const PathEncoding path(state.getTurn());
00037 Move test;
00038 const ProofDisproof pdp
00039 = attack
00040 ? dfpn.hasCheckmateMove(state, HashKey(state), path, checkmate_limit, test)
00041 : dfpn.hasEscapeMove(state, HashKey(state), path, checkmate_limit*2, Move::PASS(alt(state.getTurn())));
00042 if (node_count)
00043 *node_count = dfpn.nodeCount();
00044 if (pdp.isCheckmateSuccess())
00045 {
00046 best_move = test;
00047 return True;
00048 }
00049 return pdp.isFinal() ? False : Unknown;
00050 }
00051
00052
00053
00054 void osl::annotate::
00055 CheckmateAnalyzer::match(AnalysesResult& shared,
00056 const NumEffectState& src, const vector<Move>& ,
00057 int )
00058 {
00059 if (! src.inCheck())
00060 {
00061 shared.checkmate = False;
00062 return;
00063 }
00064 NumEffectState s(src);
00065 Move dummy;
00066 shared.checkmate = isCheckmate(s, dummy, false);
00067 }
00068
00069 void osl::annotate::
00070 CheckmateWin::match(AnalysesResult& shared,
00071 const NumEffectState& src, const vector<Move>& ,
00072 int )
00073 {
00074 if (src.inCheck())
00075 {
00076 shared.checkmate_win = False;
00077 return;
00078 }
00079 NumEffectState s(src);
00080 shared.checkmate_win = isCheckmate(s, shared.checkmate_move, true);
00081 }
00082
00083 void osl::annotate::
00084 EscapeFromCheck::match(AnalysesResult& shared,
00085 const NumEffectState& src, const vector<Move>& moves,
00086 int last_move)
00087 {
00088 shared.escape_from_check = matchMain(src, moves, last_move) ? True : False;
00089 }
00090
00091 bool osl::annotate::
00092 EscapeFromCheck::matchMain(const NumEffectState& src, const vector<Move>& moves,
00093 int last_move)
00094 {
00095 if (last_move < 0)
00096 return false;
00097 if (moves[last_move].ptype() == KING)
00098 {
00099 if (src.hasEffectBy(src.getTurn(), moves[last_move].from()))
00100 return true;
00101 if (moves[last_move].capturePtype() != PTYPE_EMPTY)
00102 {
00103 const PtypeO captured = moves[last_move].capturePtypeO();
00104 if (src.hasEffectFromTo(captured, moves[last_move].to(),
00105 moves[last_move].from()))
00106 return true;
00107 }
00108 return false;
00109 }
00110 const PieceMask pin = src.pin(alt(src.getTurn()));
00111 if (pin.test(src.getPieceAt(moves[last_move].to()).number()))
00112 return true;
00113 if (moves[last_move].capturePtype() != PTYPE_EMPTY)
00114 {
00115 const PtypeO captured = moves[last_move].capturePtypeO();
00116 if (src.hasEffectFromTo(captured, moves[last_move].to(),
00117 src.getKingPosition(alt(src.getTurn()))))
00118 return true;
00119 }
00120 return false;
00121 }
00122
00123 void osl::annotate::
00124 ThreatmateAnalyzer::match(AnalysesResult& shared,
00125 const NumEffectState& src, const vector<Move>& moves,
00126 int last_move)
00127 {
00128 if (src.inCheck())
00129 {
00130 shared.threatmate = False;
00131 return;
00132 }
00133 NumEffectState s(src);
00134 s.changeTurn();
00135 shared.threatmate = isCheckmate(s, shared.threatmate_move, true, &shared.threatmate_node_count);
00136 threatmate::MlPredictor predictor;
00137 shared.threatmate_probability = (last_move >= 0) ? predictor.probability(src, moves[last_move]) : 0.0;
00138 }
00139
00140
00141 void osl::annotate::
00142 CheckmateForCapture::match(AnalysesResult& shared,
00143 const NumEffectState& src, const vector<Move>& history,
00144 int last_move)
00145 {
00146 if (last_move < 0 || shared.escape_from_check == True)
00147 return;
00148 const Position last_to = history[last_move].to();
00149 if (! src.hasEffectBy(src.getTurn(), last_to))
00150 return;
00151 MoveVector all, moves;
00152 LegalMoves::generate(src, all);
00153 BOOST_FOREACH(Move m, all)
00154 if (m.to() == last_to)
00155 moves.push_back(m);
00156 if (moves.empty())
00157 return;
00158 BOOST_FOREACH(Move move, moves)
00159 {
00160 DualDfpn dfpn;
00161 NumEffectState s(src);
00162 ApplyMoveOfTurn::doMove(s, move);
00163 Move checkmate_move;
00164 const bool checkmate
00165 #ifdef OSL_DFPN_SMP
00166 = dfpn.isWinningStateParallel(checkmate_limit, s, HashKey(s), PathEncoding(s.getTurn()),
00167 checkmate_move, move);
00168 #else
00169 = dfpn.isWinningState(checkmate_limit, s, HashKey(s), PathEncoding(s.getTurn()),
00170 checkmate_move, move);
00171 #endif
00172 if (checkmate)
00173 {
00174 ++shared.checkmate_for_capture.checkmate_count;
00175 if (See::see(src, move) > 0)
00176 ++shared.checkmate_for_capture.see_plus_checkmate_count;
00177 }
00178 else
00179 ++shared.checkmate_for_capture.safe_count;
00180 }
00181 }
00182
00183 void osl::annotate::
00184 CheckmateForEscape::match(AnalysesResult& shared,
00185 const NumEffectState& src, const vector<Move>& history,
00186 int last_move)
00187 {
00188 if (last_move < 0)
00189 return;
00190 const Position last_to = history[last_move].to();
00191 if (! src.inCheck() || src.hasEffectBy(src.getTurn(), last_to))
00192 return;
00193
00194 MoveVector moves;
00195 LegalMoves::generate(src, moves);
00196 if (moves.empty())
00197 return;
00198 BOOST_FOREACH (Move move, moves)
00199 {
00200
00201 const Position to = move.to();
00202 if (src.hasEffectBy(alt(src.getTurn()), to)
00203 && (src.countEffect(src.getTurn(), to)
00204 - (move.isDrop() ? 0 : 1) == 0))
00205 {
00206 ++shared.checkmate_for_escape.safe_count;
00207 continue;
00208 }
00209
00210 DualDfpn dfpn;
00211 NumEffectState s(src);
00212 ApplyMoveOfTurn::doMove(s, move);
00213 Move checkmate_move;
00214 const bool checkmate
00215 #ifdef OSL_DFPN_SMP
00216 = dfpn.isWinningStateParallel(checkmate_limit, s, HashKey(s), PathEncoding(s.getTurn()),
00217 checkmate_move, move);
00218 #else
00219 = dfpn.isWinningState(checkmate_limit, s, HashKey(s), PathEncoding(s.getTurn()),
00220 checkmate_move, move);
00221 #endif
00222 if (checkmate)
00223 ++shared.checkmate_for_escape.checkmate_count;
00224 else
00225 ++shared.checkmate_for_escape.safe_count;
00226 }
00227 }
00228
00229 bool osl::annotate::
00230 ThreatmateIfMorePieces::suitable(const NumEffectState& state, Piece p)
00231 {
00232
00233
00234
00235 if (state.hasEffectBy(p.owner(), p.position()))
00236 {
00237 if (state.selectLong(p.position(), alt(p.owner())).any())
00238 return false;
00239 if (Neighboring8Direct::hasEffect
00240 (state, p.ptypeO(), p.position(), state.getKingPosition(p.owner())))
00241 return false;
00242 }
00243 return true;
00244 }
00245
00246 void osl::annotate::
00247 ThreatmateIfMorePieces::match(AnalysesResult& shared,
00248 const NumEffectState& src, const vector<Move>& ,
00249 int last_move)
00250 {
00251 if (last_move < 0)
00252 return;
00253 if (src.inCheck() || shared.threatmate == True)
00254 return;
00255
00256 const PieceMask effected_pieces = src.effectedMask(alt(src.getTurn())) & src.getOnBoardMask(src.getTurn());
00257 BOOST_FOREACH(Ptype ptype, PieceStand::order)
00258 {
00259 DualDfpn dfpn;
00260 if (src.hasPieceOnStand(src.getTurn(), ptype))
00261 {
00262 NumEffectState s(src.emulateHandPiece(src.getTurn(), alt(src.getTurn()), ptype));
00263 s.setTurn(alt(src.getTurn()));
00264
00265 Move hand_move;
00266 const bool threatmate
00267 #ifdef OSL_DFPN_SMP
00268 = dfpn.isWinningStateParallel(checkmate_limit, s, HashKey(s), PathEncoding(s.getTurn()),
00269 hand_move, Move::PASS(alt(s.getTurn())));
00270 #else
00271 = dfpn.isWinningState(checkmate_limit, s, HashKey(s), PathEncoding(s.getTurn()),
00272 hand_move, Move::PASS(alt(s.getTurn())));
00273 #endif
00274 if (threatmate)
00275 shared.threatmate_if_more_pieces.hand_ptype.push_back(ptype);
00276 continue;
00277 }
00278 mask_t m = effected_pieces.getMask(Ptype_Table.getIndex(ptype))
00279 & Ptype_Table.getMaskLow(ptype);
00280 if (! m.any())
00281 continue;
00282
00283 Piece p = src.getPieceOf(m.takeOneBit());
00284 while (m.any() && !suitable(src, p))
00285 p = src.getPieceOf(m.takeOneBit());
00286 if (! suitable(src, p))
00287 continue;
00288 assert(p.isOnBoard());
00289 assert(unpromote(p.ptype()) == ptype);
00290 NumEffectState s(src.emulateCapture(p, alt(src.getTurn())));
00291 s.setTurn(alt(src.getTurn()));
00292 if (s.inCheck() || s.inCheck(alt(s.getTurn())))
00293 continue;
00294
00295 Move board_move;
00296 const bool threatmate
00297 #ifdef OSL_DFPN_SMP
00298 = dfpn.isWinningStateParallel(checkmate_limit, s, HashKey(s), PathEncoding(s.getTurn()),
00299 board_move, Move::PASS(alt(s.getTurn())));
00300 #else
00301 = dfpn.isWinningState(checkmate_limit, s, HashKey(s), PathEncoding(s.getTurn()),
00302 board_move, Move::PASS(alt(s.getTurn())));
00303 #endif
00304 if (threatmate)
00305 shared.threatmate_if_more_pieces.board_ptype.push_back(p);
00306 }
00307 }
00308
00309 namespace osl
00310 {
00311 namespace
00312 {
00313 MoveWithComment do_search(const NumEffectState& src, int seconds)
00314 {
00315 game_playing::AlphaBeta2OpenMidEndingEvalPlayer player;
00316 player.setNextIterationCoefficient(1.0);
00317 player.setVerbose(0);
00318 player.setTableLimit(100000, 200);
00319
00320 game_playing::GameState state(src);
00321 search::TimeAssigned time(MilliSeconds::Interval(seconds*1000));
00322 return player.searchWithSecondsForThisMove(state, time);
00323 }
00324 }
00325 }
00326
00327
00328 void osl::annotate::
00329 Vision3::match(AnalysesResult& shared,
00330 const NumEffectState& src, const vector<Move>& history,
00331 int last_move)
00332 {
00333 if (last_move < 0)
00334 return;
00335 if (src.inCheck() || shared.threatmate == True
00336 || shared.checkmate == True || shared.checkmate_win == True
00337 || shared.escape_from_check == True)
00338 return;
00339
00340
00341 search::MoveWithComment response = do_search(src, 1);
00342 if (! response.move.isNormal()
00343 || response.move.to() == history[last_move].to())
00344 return;
00345
00346 NumEffectState s = src;
00347 s.changeTurn();
00348
00349
00350 MoveWithComment pv = do_search(s, 2);
00351 if (! pv.move.isNormal())
00352 return;
00353 if (See::see(s, pv.move) > 0) {
00354 if (pv.move.from() == history[last_move].to())
00355 return;
00356 const Piece p = s.getPieceAt(pv.move.to());
00357 if (p.isPiece()
00358 && ! s.hasEffectBy(alt(s.getTurn()), pv.move.to())
00359 && src.effectedChanged(alt(s.getTurn())).test(p.number()))
00360 return;
00361 }
00362 typedef eval::ml::OpenMidEndingEval eval_t;
00363 shared.vision.cur_eval
00364 = eval_t(s).value() * 200.0/eval_t::captureValue(newPtypeO(WHITE,PAWN));
00365 if (pv.value*eval::delta(s.getTurn())
00366 < shared.vision.cur_eval*eval::delta(s.getTurn())+200)
00367 return;
00368 shared.vision.eval = pv.value;
00369 shared.vision.pv.push_back(pv.move);
00370 BOOST_FOREACH(Move m, pv.moves)
00371 shared.vision.pv.push_back(m);
00372 }
00373
00374
00375
00376
00377