All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
kanjiMove.cc
Go to the documentation of this file.
1 #include "osl/record/kanjiMove.h"
2 #include "osl/record/kanjiCode.h"
6 #include "osl/stl/copy_if.h"
7 #include "osl/misc/eucToLang.h"
8 #include <boost/foreach.hpp>
9 #include <boost/mem_fn.hpp>
10 #include <boost/lambda/lambda.hpp>
11 #include <boost/lambda/bind.hpp>
12 #include <algorithm>
13 #include <iterator>
14 #include <iostream>
15 using namespace boost::lambda;
16 
17 namespace
18 {
19 int moveFromX(const osl::Move& move)
20 {
21  const osl::Square& p = move.from();
22  return p.x();
23 }
24 
25 int moveFromY(const osl::Move& move)
26 {
27  const osl::Square& p = move.from();
28  return p.y();
29 }
30 
31 struct SortMoveFromX :
32  public std::binary_function<osl::Move, osl::Move, bool>
33 {
34  bool operator()(const osl::Move& a, const osl::Move& b) const
35  {
36  const osl::Square& a_p = a.from();
37  const osl::Square& b_p = b.from();
38  return a_p.x() < b_p.x();
39  }
40 };
41 
42 struct SortMoveFromXDesc :
43  public std::binary_function<osl::Move, osl::Move, bool>
44 {
45  bool operator()(const osl::Move& a, const osl::Move& b) const
46  {
47  const osl::Square& a_p = a.from();
48  const osl::Square& b_p = b.from();
49  return a_p.x() > b_p.x();
50  }
51 };
52 
53 struct SortMoveFromY :
54  public std::binary_function<osl::Move, osl::Move, bool>
55 {
56  bool operator()(const osl::Move& a, const osl::Move& b) const
57  {
58  const osl::Square& a_p = a.from();
59  const osl::Square& b_p = b.from();
60  return a_p.y() < b_p.y();
61  }
62 };
63 
64 struct SortMoveFromYDesc :
65  public std::binary_function<osl::Move, osl::Move, bool>
66 {
67  bool operator()(const osl::Move& a, const osl::Move& b) const
68  {
69  const osl::Square& a_p = a.from();
70  const osl::Square& b_p = b.from();
71  return a_p.y() > b_p.y();
72  }
73 };
74 
75 struct RemoveMoveFromXOver :
76  public std::unary_function<osl::Move, bool>
77 {
78  const int min_x;
79  RemoveMoveFromXOver(const int min_x)
80  : min_x(min_x)
81  {}
82 
83  bool operator()(const osl::Move& m) const
84  {
85  const osl::Square& p = m.from();
86  return p.x() > min_x;
87  }
88 };
89 
90 struct RemoveMoveFromXGTE :
91  public std::unary_function<osl::Move, bool>
92 {
93  const int min_x;
94  RemoveMoveFromXGTE(const int min_x)
95  : min_x(min_x)
96  {}
97 
98  bool operator()(const osl::Move& m) const
99  {
100  const osl::Square& p = m.from();
101  return p.x() >= min_x;
102  }
103 };
104 
105 struct RemoveMoveFromYOver :
106  public std::unary_function<osl::Move, bool>
107 {
108  const int min_y;
109  RemoveMoveFromYOver(const int min_y)
110  : min_y(min_y)
111  {}
112 
113  bool operator()(const osl::Move& m) const
114  {
115  const osl::Square& p = m.from();
116  return p.y() > min_y;
117  }
118 };
119 
120 struct RemoveMoveFromYGTE :
121  public std::unary_function<osl::Move, bool>
122 {
123  const int min_y;
124  RemoveMoveFromYGTE(const int min_y)
125  : min_y(min_y)
126  {}
127 
128  bool operator()(const osl::Move& m) const
129  {
130  const osl::Square& p = m.from();
131  return p.y() >= min_y;
132  }
133 };
134 
135 struct RemoveMoveFromXUnder :
136  public std::unary_function<osl::Move, bool>
137 {
138  const int max_x;
139  RemoveMoveFromXUnder(const int max_x)
140  : max_x(max_x)
141  {}
142 
143  bool operator()(const osl::Move& m) const
144  {
145  const osl::Square& p = m.from();
146  return p.x() < max_x;
147  }
148 };
149 
150 struct RemoveMoveFromXLTE :
151  public std::unary_function<osl::Move, bool>
152 {
153  const int max_x;
154  RemoveMoveFromXLTE(const int max_x)
155  : max_x(max_x)
156  {}
157 
158  bool operator()(const osl::Move& m) const
159  {
160  const osl::Square& p = m.from();
161  return p.x() <= max_x;
162  }
163 };
164 
165 struct RemoveMoveFromYUnder :
166  public std::unary_function<osl::Move, bool>
167 {
168  const int max_y;
169  RemoveMoveFromYUnder(const int max_y)
170  : max_y(max_y)
171  {}
172 
173  bool operator()(const osl::Move& m) const
174  {
175  const osl::Square& p = m.from();
176  return p.y() < max_y;
177  }
178 };
179 
180 struct RemoveMoveFromYLTE :
181  public std::unary_function<osl::Move, bool>
182 {
183  const int max_y;
184  RemoveMoveFromYLTE(const int max_y)
185  : max_y(max_y)
186  {}
187 
188  bool operator()(const osl::Move& m) const
189  {
190  const osl::Square& p = m.from();
191  return p.y() <= max_y;
192  }
193 };
194 
195 struct RemoveMoveFromXEqual :
196  public std::unary_function<osl::Move, bool>
197 {
198  const int x;
199  RemoveMoveFromXEqual(const int x)
200  : x(x)
201  {}
202 
203  bool operator()(const osl::Move& m) const
204  {
205  const osl::Square& p = m.from();
206  return p.x() == x;
207  }
208 };
209 
210 struct RemoveMoveFromYEqual :
211  public std::unary_function<osl::Move, bool>
212 {
213  const int y;
214  RemoveMoveFromYEqual(const int y)
215  : y(y)
216  {}
217 
218  bool operator()(const osl::Move& m) const
219  {
220  const osl::Square& p = m.from();
221  return p.y() == y;
222  }
223 };
224 } // anonymous namespace
225 
228  : verbose(false)
229 {
230  for (size_t x=1; x<=9; ++x)
231  {
232  for (size_t y=1; y<=9; ++y)
233  {
234  const std::string str = StandardCharacters::suji[x] +
236  str2position[str] = Square(x,y);
237  }
238  }
239  str2piece[K_PAWN] = PAWN;
247  str2piece[K_GOLD] = GOLD;
250  str2piece[K_ROOK] = ROOK;
253  str2piece[K_KING] = KING;
255 
256  // pieces in kakinoki-style board specification
260 }
261 
264 {
265 }
266 
268 KanjiMove::toSquare(const std::string& s) const
269 {
270  str2position_t::const_iterator p=str2position.find(s);
271  if (p == str2position.end())
272  return Square();
273  return p->second;
274 }
275 
277 KanjiMove::toPtype(const std::string& s) const
278 {
279  str2piece_t::const_iterator p=str2piece.find(s);
280  if (p == str2piece.end())
281  return Ptype();
282  return p->second;
283 }
284 
285 void osl::record::
287  std::string& str,
288  const osl::Square& to_pos,
289  const osl::Player& player) const
290 {
291  assert(!str.empty());
292  assert(found.size() >= 2);
293 
294  if ( (str.substr(0,2) == K_MIGI && player == BLACK) ||
295  (str.substr(0,2) == K_HIDARI && player == WHITE) )
296  {
297  found.sort( bind(moveFromX, boost::lambda::_1) < bind(moveFromX, boost::lambda::_2) );
298  const osl::Move min = found.front();
299  found.remove_if( RemoveMoveFromXOver(min.from().x()) ); // list really removes
300  }
301  else if ( (str.substr(0,2) == K_HIDARI && player == BLACK) ||
302  (str.substr(0,2) == K_MIGI && player == WHITE) )
303  {
304  found.sort( bind(moveFromX, boost::lambda::_1) < bind(moveFromX, boost::lambda::_2) );
305  const Move max = found.back();
306  found.remove_if( RemoveMoveFromXUnder(max.from().x()) ); // list really removes
307  }
308  else if ( (str.substr(0,2) == K_SHITA && player == BLACK) ||
309  (str.substr(0,2) == K_UE && player == WHITE) )
310  {
311  found.sort( bind(moveFromY, boost::lambda::_1) < bind(moveFromY, boost::lambda::_2) );
312  const Move min = found.front();
313  found.remove_if( RemoveMoveFromYOver(min.from().y()) ); // list really removes
314  }
315  else if ( (str.substr(0,2) == K_UE && player == BLACK) ||
316  (str.substr(0,2) == K_SHITA && player == WHITE) )
317  {
318  found.sort( bind(moveFromY, boost::lambda::_1) > bind(moveFromY, boost::lambda::_2) );
319  const Move max = found.front();
320  found.remove_if( RemoveMoveFromYUnder(max.from().y()) ); // list really removes
321  }
322  else if (str.substr(0,2) == K_YORU)
323  {
324  found.remove_if( std::not1(RemoveMoveFromYEqual(to_pos.y())) ); // list really removes
325  }
326  else if (str.substr(0,2) == K_SUGU && player == WHITE)
327  {
328  found.remove_if( std::not1(RemoveMoveFromXEqual(to_pos.x())) ); // or
329  found.remove_if( std::not1(RemoveMoveFromYEqual(to_pos.y()-1)) ); // list really removes
330  }
331  else if (str.substr(0,2) == K_SUGU && player == BLACK)
332 
333  {
334  found.remove_if( std::not1(RemoveMoveFromXEqual(to_pos.x())) ); // or
335  found.remove_if( std::not1(RemoveMoveFromYEqual(to_pos.y()+1)) ); // list really removes
336  }
337  else if (str.substr(0,2) == K_HIKU && player == BLACK)
338  {
339  found.remove_if( RemoveMoveFromYGTE(to_pos.y()) ); // list really removes
340  }
341  else if (str.substr(0,2) == K_HIKU && player == WHITE)
342  {
343  found.remove_if( RemoveMoveFromYLTE(to_pos.y()) ); // list really removes
344  }
345  else if (str.substr(0,2) == K_YUKU && player == BLACK)
346  {
347  found.remove_if( RemoveMoveFromYLTE(to_pos.y()) ); // list really removes
348  }
349  else if (str.substr(0,2) == K_YUKU && player == WHITE)
350  {
351  found.remove_if( RemoveMoveFromYGTE(to_pos.y()) ); // list really removes
352  }
353 
354  str.erase(0,2);
355  assert(!found.empty());
356 
357  if (found.size() > 1)
358  {
359  assert(!str.empty());
360  selectCandidates(found, str, to_pos, player);
361  }
362 
363  assert(found.size() == 1);
364  if (!str.empty())
365  std::cerr << "WARNING: A single candidate is selected, but the input string still has some characters: " << misc::eucToLang(str) << std::endl;
366 }
367 
369 KanjiMove::strToMove(const std::string& orig,
370  const osl::NumEffectState& state,
371  const osl::Move& last_move) const
372 {
373  std::string str(orig);
374  if (str.find(K_RESIGN) != str.npos)
375  return Move();
376  assert(str.size() >= 4*2
377  || (str.size() >= 3*2
378  && (str.substr(2,2) == K_ONAZI
379  || (isdigit(str[2]) && isdigit(str[3])))));
380  const Player player = str.substr(0,2) == K_BLACK_SIGN ? BLACK : WHITE;
381  assert(player == state.turn());
382  str.erase(0,2);
383 
384  Square to_pos;
385  if (str.substr(0,2) == K_ONAZI)
386  {
387  to_pos = last_move.to();
388  str.erase(0,2);
389  if (str.substr(0,2) == K_SPACE)
390  str.erase(0,2);
391  }
392  else if (isdigit(str[0]) && isdigit(str[1]))
393  {
394  to_pos = Square(str[0]-'0', str[1]-'0');
395  str.erase(0,2);
396  }
397  else
398  {
399  to_pos = toSquare(str.substr(0,4));
400  str.erase(0,4);
401  }
402 
403  Ptype ptype;
404  if (str.substr(0,2) == K_NARU) // PLANCE, PKIGHT, PSILVER
405  {
406  ptype = toPtype(str.substr(0,4));
407  str.erase(0,4);
408  }
409  else
410  {
411  ptype = toPtype(str.substr(0,2));
412  str.erase(0,2);
413  }
414 
415  // promote or not
416  bool is_promote = false;
417  if (str.size() >= 4 && str.substr(0,4) == K_FUNARI)
418  str.erase(0,4);
419  else if (str.size() >= 4 && str.substr(str.size()-4,4) == K_FUNARI)
420  str.erase(str.size()-4,4);
421  else if (str.size() >= 2 && str.substr(0,2) == K_NARU)
422  {
423  is_promote = true;
424  str.erase(0,2);
425  }
426  else if (str.size() >= 2 && str.substr(str.size()-2,2) == K_NARU)
427  {
428  is_promote = true;
429  str.erase(str.size()-2,2);
430  }
431 
432  MoveVector moves;
433  LegalMoves::generateWithFullUnpromotions(state, moves);
434  found_moves_t found;
435  BOOST_FOREACH(Move move, moves)
436  {
437  if (move.oldPtype() == ptype &&
438  move.to() == to_pos &&
439  move.isPromotion() == is_promote)
440  {
442  if (std::find(found.begin(), found.end(), move) == found.end())
443  found.push_back(move);
444  }
445  }
446  if (verbose)
447  {
448  std::cerr << "\n" << orig << "\n" << state;
449  std::cerr << "remain: " << str << " (" << str.size() << " bytes)\n";
450  std::cerr << "promote: " << is_promote << "\n";
451  std::cerr << "ptype: " << ptype << "\n";
452  std::cerr << "to_position: " << to_pos << "\n";
453  std::cerr << "candidates: " << found.size() << std::endl;
454  if (found.size() >=2) {
455  BOOST_FOREACH(const Move move, found) {
456  std::cerr << " " << move << std::endl;
457  }
458  }
459  }
460  if (found.empty()) {
461  // there is no leagal move
462  return Move::INVALID();
463  }
464  assert(!found.empty());
465 
466  // Single candidate
467  if (found.size() == 1)
468  return found.front();
469 
470  // Multiple candidates
471  assert(found.size() >= 2);
472 
473  // drop
474  if (str.substr(0,2) == K_UTSU)
475  {
476  found_moves_t::iterator it =
477  std::find_if(found.begin(), found.end(),
478  bind(boost::mem_fn(&Move::isDrop), boost::lambda::_1)
479  );
480  str.erase(0,2);
481  assert(str.empty());
482  assert(it != found.end());
483  return *it;
484  }
485  else
486  {
487  found.remove_if(
488  bind(boost::mem_fn(&Move::isDrop), boost::lambda::_1)
489  ); // list really removes
490  if (found.size() == 1)
491  return found.front();
492  }
493 
494  // Multiple candidates
495  assert(found.size() >= 2);
496  if (str.empty())
497  return Move();
498  assert(!str.empty());
499  selectCandidates(found, str, to_pos, player);
500  assert(found.size() == 1);
501  return found.front();
502 }
503 
506 {
507  static const KanjiMove Kanji_Move;
508  return Kanji_Move;
509 }
510 
511 // ;;; Local Variables:
512 // ;;; mode:c++
513 // ;;; c-basic-offset:2
514 // ;;; End: