All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
analyzer.cc
Go to the documentation of this file.
1 /* analyzer.cc
2  */
5 #include "osl/checkmate/dfpn.h"
6 #ifdef OSL_DFPN_SMP
8 #endif
12 #include "osl/eval/see.h"
16 #include <boost/foreach.hpp>
17 
18 const int checkmate_limit = 1000000/2;
19 
22 {
23 }
24 
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::
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::
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::
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::
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::
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::
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  {
198  if (See::see(src, move) > 0)
200  }
201  else
203  }
204 }
205 
206 void osl::annotate::
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  {
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)
247  else
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;
263  (state, p.ptypeO(), p.square(), state.kingSquare(p.owner())))
264  return false;
265  }
266  return true;
267 }
268 
269 void osl::annotate::
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  {
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::
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  }
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: