analyzer.cc Source File

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
analyzer.cc
Go to the documentation of this file.
1 /* analyzer.cc
2 */
3 #include "osl/annotate/analyzer.h"
4 #include "osl/checkmate/dualDfpn.h"
5 #include "osl/checkmate/dfpn.h"
6 #ifdef OSL_DFPN_SMP
7 # include "osl/checkmate/dfpnParallel.h"
8 #endif
9 #include "osl/move_generator/legalMoves.h"
10 #include "osl/threatmate/mlPredictor.h"
11 #include "osl/effect_util/neighboring8Direct.h"
12 #include "osl/eval/see.h"
13 #include "osl/eval/ml/openMidEndingEval.h"
14 #include "osl/game_playing/alphaBetaPlayer.h"
15 #include "osl/game_playing/gameState.h"
16 #include <boost/foreach.hpp>
17
18 const int checkmate_limit = 1000000/2;
19
20 osl::annotate::
21 Analyzer::~Analyzer()
22 {
23 }
24
25 osl::annotate::Trivalent osl::annotate::
26 Analyzer::isCheckmate(NumEffectState& state, Move& best_move, bool attack, size_t *node_count)
27 {
28 #ifdef OSL_DFPN_SMP
29 checkmate::DfpnParallel dfpn;
30 #else
31 checkmate::Dfpn dfpn;
32 #endif
33 checkmate::DfpnTable table(attack ? state.turn() : alt(state.turn()));
34 dfpn.setTable(&table);
35 const PathEncoding path(state.turn());
36 Move test;
37 const ProofDisproof pdp
38 = attack
39 ? dfpn.hasCheckmateMove(state, HashKey(state), path, checkmate_limit, test)
40 : dfpn.hasEscapeMove(state, HashKey(state), path, checkmate_limit*2, Move::PASS(alt(state.turn())));
41 if (node_count)
42 *node_count = dfpn.nodeCount();
43 if (pdp.isCheckmateSuccess())
44 {
45 best_move = test;
46 return True;
47 }
48 return pdp.isFinal() ? False : Unknown;
49 }
50
51
52
53 void osl::annotate::
54 RepetitionAnalyzer::match(AnalysesResult& shared,
55 const NumEffectState& src, const vector<Move>& moves,
56 int last_move)
57 {
58 shared.repetition.clear();
59 NumEffectState state; // assume initial position
60 HashKey key(state);
61 vector<HashKey> keys;
62 for (int i=0; i<=last_move; ++i) {
63 Move move = moves[i];
64 keys.push_back(key);
65 if (! state.isValidMove(move))
66 return;
67 key = key.newMakeMove(move);
68 state.makeMove(move);
69 }
70 if (HashKey(src) != key)
71 return;
72 for (size_t i=0; i<keys.size(); ++i)
73 if (keys[i] == key)
74 shared.repetition.push_back(i);
75 }
76
77 void osl::annotate::
78 CheckmateAnalyzer::match(AnalysesResult& shared,
79 const NumEffectState& src, const vector<Move>& /*moves*/,
80 int /*last_move*/)
81 {
82 if (! src.inCheck())
83 {
84 shared.checkmate = False;
85 return;
86 }
87 NumEffectState s(src);
88 Move dummy;
89 shared.checkmate = isCheckmate(s, dummy, false);
90 }
91
92 void osl::annotate::
93 CheckmateWin::match(AnalysesResult& shared,
94 const NumEffectState& src, const vector<Move>& /*moves*/,
95 int /*last_move*/)
96 {
97 if (src.inCheck())
98 {
99 shared.checkmate_win = False;
100 return;
101 }
102 NumEffectState s(src);
103 shared.checkmate_win = isCheckmate(s, shared.checkmate_move, true);
104 }
105
106 void osl::annotate::
107 EscapeFromCheck::match(AnalysesResult& shared,
108 const NumEffectState& src, const vector<Move>& moves,
109 int last_move)
110 {
111 shared.escape_from_check = matchMain(src, moves, last_move) ? True : False;
112 }
113
114 bool osl::annotate::
115 EscapeFromCheck::matchMain(const NumEffectState& src, const vector<Move>& moves,
116 int last_move)
117 {
118 if (last_move < 0)
119 return false;
120 if (moves[last_move].ptype() == KING)
121 {
122 if (src.hasEffectAt(src.turn(), moves[last_move].from()))
123 return true;
124 if (moves[last_move].capturePtype() != PTYPE_EMPTY)
125 {
126 const PtypeO captured = moves[last_move].capturePtypeO();
127 if (src.hasEffectIf(captured, moves[last_move].to(),
128 moves[last_move].from()))
129 return true;
130 }
131 return false;
132 }
133 const PieceMask pin = src.pin(alt(src.turn()));
134 if (pin.test(src.pieceAt(moves[last_move].to()).number()))
135 return true;
136 if (moves[last_move].capturePtype() != PTYPE_EMPTY)
137 {
138 const PtypeO captured = moves[last_move].capturePtypeO();
139 if (src.hasEffectIf(captured, moves[last_move].to(),
140 src.kingSquare(alt(src.turn()))))
141 return true;
142 }
143 return false;
144 }
145
146 void osl::annotate::
147 ThreatmateAnalyzer::match(AnalysesResult& shared,
148 const NumEffectState& src, const vector<Move>& moves,
149 int last_move)
150 {
151 if (src.inCheck())
152 {
153 shared.threatmate = False;
154 return;
155 }
156 NumEffectState s(src);
157 s.changeTurn();
158 shared.threatmate = isCheckmate(s, shared.threatmate_move, true, &shared.threatmate_node_count);
159 threatmate::MlPredictor predictor;
160 shared.threatmate_probability = (last_move >= 0) ? predictor.probability(src, moves[last_move]) : 0.0;
161 }
162
163
164 void osl::annotate::
165 CheckmateForCapture::match(AnalysesResult& shared,
166 const NumEffectState& src, const vector<Move>& history,
167 int last_move)
168 {
169 if (last_move < 0 || shared.escape_from_check == True)
170 return;
171 const Square last_to = history[last_move].to();
172 if (! src.hasEffectAt(src.turn(), last_to))
173 return;
174 MoveVector all, moves;
175 LegalMoves::generate(src, all);
176 BOOST_FOREACH(Move m, all)
177 if (m.to() == last_to)
178 moves.push_back(m);
179 if (moves.empty())
180 return;
181 BOOST_FOREACH(Move move, moves)
182 {
183 DualDfpn dfpn;
184 NumEffectState s(src);
185 s.makeMove(move);
186 Move checkmate_move;
187 const bool checkmate
188 #ifdef OSL_DFPN_SMP
189 = dfpn.isWinningStateParallel(checkmate_limit, s, HashKey(s), PathEncoding(s.turn()),
190 checkmate_move, move);
191 #else
192 = dfpn.isWinningState(checkmate_limit, s, HashKey(s), PathEncoding(s.turn()),
193 checkmate_move, move);
194 #endif
195 if (checkmate)
196 {
197 ++shared.checkmate_for_capture.checkmate_count;
198 if (See::see(src, move) > 0)
199 ++shared.checkmate_for_capture.see_plus_checkmate_count;
200 }
201 else
202 ++shared.checkmate_for_capture.safe_count;
203 }
204 }
205
206 void osl::annotate::
207 CheckmateForEscape::match(AnalysesResult& shared,
208 const NumEffectState& src, const vector<Move>& history,
209 int last_move)
210 {
211 if (last_move < 0)
212 return;
213 const Square last_to = history[last_move].to();
214 if (! src.inCheck() || src.hasEffectAt(src.turn(), last_to))
215 return;
216 // 取れない王手
217 MoveVector moves;
218 LegalMoves::generate(src, moves);
219 if (moves.empty())
220 return;
221 BOOST_FOREACH (Move move, moves)
222 {
223 // treat chuai as safe
224 const Square to = move.to();
225 if (src.hasEffectAt(alt(src.turn()), to)
226 && (src.countEffect(src.turn(), to)
227 - (move.isDrop() ? 0 : 1) == 0))
228 {
229 ++shared.checkmate_for_escape.safe_count;
230 continue;
231 }
232
233 DualDfpn dfpn;
234 NumEffectState s(src);
235 s.makeMove(move);
236 Move checkmate_move;
237 const bool checkmate
238 #ifdef OSL_DFPN_SMP
239 = dfpn.isWinningStateParallel(checkmate_limit, s, HashKey(s), PathEncoding(s.turn()),
240 checkmate_move, move);
241 #else
242 = dfpn.isWinningState(checkmate_limit, s, HashKey(s), PathEncoding(s.turn()),
243 checkmate_move, move);
244 #endif
245 if (checkmate)
246 ++shared.checkmate_for_escape.checkmate_count;
247 else
248 ++shared.checkmate_for_escape.safe_count;
249 }
250 }
251
252 bool osl::annotate::
253 ThreatmateIfMorePieces::suitable(const NumEffectState& state, Piece p)
254 {
255 // 外す対象
256 // - 取る側が長い利きで、守備側から利きあり ... 利きが外れると色々おこりやすい
257 // - 取られる駒が玉の周囲に利いていて、守備側から利きあり .. 取り返しの影響が大きい
258 if (state.hasEffectAt(p.owner(), p.square()))
259 {
260 if (state.longEffectAt(p.square(), alt(p.owner())).any())
261 return false;
262 if (Neighboring8Direct::hasEffect
263 (state, p.ptypeO(), p.square(), state.kingSquare(p.owner())))
264 return false;
265 }
266 return true;
267 }
268
269 void osl::annotate::
270 ThreatmateIfMorePieces::match(AnalysesResult& shared,
271 const NumEffectState& src, const vector<Move>& /*history*/,
272 int last_move)
273 {
274 if (last_move < 0)
275 return;
276 if (src.inCheck() || shared.threatmate == True)
277 return;
278
279 const PieceMask effected_pieces = src.effectedMask(alt(src.turn())) & src.piecesOnBoard(src.turn());
280 BOOST_FOREACH(Ptype ptype, PieceStand::order)
281 {
282 DualDfpn dfpn;
283 if (src.hasPieceOnStand(src.turn(), ptype))
284 {
285 NumEffectState s(src.emulateHandPiece(src.turn(), alt(src.turn()), ptype));
286 s.setTurn(alt(src.turn()));
287
288 Move hand_move;
289 const bool threatmate
290 #ifdef OSL_DFPN_SMP
291 = dfpn.isWinningStateParallel(checkmate_limit, s, HashKey(s), PathEncoding(s.turn()),
292 hand_move, Move::PASS(alt(s.turn())));
293 #else
294 = dfpn.isWinningState(checkmate_limit, s, HashKey(s), PathEncoding(s.turn()),
295 hand_move, Move::PASS(alt(s.turn())));
296 #endif
297 if (threatmate)
298 shared.threatmate_if_more_pieces.hand_ptype.push_back(ptype);
299 continue;
300 }
301 mask_t m = effected_pieces.getMask(Ptype_Table.getIndex(ptype))
302 & Ptype_Table.getMaskLow(ptype);
303 if (! m.any())
304 continue;
305
306 Piece p = src.pieceOf(m.takeOneBit());
307 while (m.any() && !suitable(src, p))
308 p = src.pieceOf(m.takeOneBit());
309 if (! suitable(src, p))
310 continue;
311 assert(p.isOnBoard());
312 assert(unpromote(p.ptype()) == ptype);
313 NumEffectState s(src.emulateCapture(p, alt(src.turn())));
314 s.setTurn(alt(src.turn()));
315 if (s.inCheck() || s.inCheck(alt(s.turn())))
316 continue;
317
318 Move board_move;
319 const bool threatmate
320 #ifdef OSL_DFPN_SMP
321 = dfpn.isWinningStateParallel(checkmate_limit, s, HashKey(s), PathEncoding(s.turn()),
322 board_move, Move::PASS(alt(s.turn())));
323 #else
324 = dfpn.isWinningState(checkmate_limit, s, HashKey(s), PathEncoding(s.turn()),
325 board_move, Move::PASS(alt(s.turn())));
326 #endif
327 if (threatmate)
328 shared.threatmate_if_more_pieces.board_ptype.push_back(p);
329 }
330 }
331
332 namespace osl
333 {
334 namespace
335 {
336 MoveWithComment do_search(const NumEffectState& src, int seconds)
337 {
338 game_playing::AlphaBeta2OpenMidEndingEvalPlayer player;
339 player.setNextIterationCoefficient(1.0);
340 player.setVerbose(0);
341 player.setTableLimit(100000, 200);
342
343 game_playing::GameState state(src);
344 search::TimeAssigned time(MilliSeconds::Interval(seconds*1000));
345 return player.searchWithSecondsForThisMove(state, time);
346 }
347 }
348 }
349
350
351 void osl::annotate::
352 Vision3::match(AnalysesResult& shared,
353 const NumEffectState& src, const vector<Move>& history,
354 int last_move)
355 {
356 if (last_move < 0)
357 return;
358 if (src.inCheck() || shared.threatmate == True
359 || shared.checkmate == True || shared.checkmate_win == True
360 || shared.escape_from_check == True)
361 return;
362
363 // better to takeback?
364 search::MoveWithComment response = do_search(src, 1);
365 if (! response.move.isNormal()
366 || response.move.to() == history[last_move].to())
367 return;
368
369 NumEffectState s = src;
370 s.changeTurn();
371
372 // get pv after pass
373 MoveWithComment pv = do_search(s, 2);
374 if (! pv.move.isNormal())
375 return;
376 if (See::see(s, pv.move) > 0) {
377 if (pv.move.from() == history[last_move].to())
378 return;
379 const Piece p = s.pieceAt(pv.move.to());
380 if (p.isPiece()
381 && ! s.hasEffectAt(alt(s.turn()), pv.move.to())
382 && src.effectedChanged(alt(s.turn())).test(p.number()))
383 return;
384 }
385 typedef eval::ml::OpenMidEndingEval eval_t;
386 shared.vision.cur_eval
387 = eval_t(s).value() * 200.0/eval_t::captureValue(newPtypeO(WHITE,PAWN));
388 if (pv.value*eval::delta(s.turn())
389 < shared.vision.cur_eval*eval::delta(s.turn())+200
390 || abs(shared.vision.cur_eval) >= 1000)
391 return;
392 shared.vision.eval = pv.value;
393 shared.vision.pv.push_back(pv.move);
394 BOOST_FOREACH(Move m, pv.moves)
395 shared.vision.pv.push_back(m);
396 }
397
398 // ;;; Local Variables:
399 // ;;; mode:c++
400 // ;;; c-basic-offset:2
401 // ;;; End: