00001 #include "osl/record/kanjiMove.h"
00002 #include "osl/record/kanjiCode.h"
00003 #include "osl/record/kanjiPrint.h"
00004 #include "osl/container/moveVector.h"
00005 #include "osl/move_generator/legalMoves.h"
00006 #include "osl/stl/copy_if.h"
00007 #include <boost/foreach.hpp>
00008 #include <boost/mem_fn.hpp>
00009 #include <boost/lambda/lambda.hpp>
00010 #include <boost/lambda/bind.hpp>
00011 #include <algorithm>
00012 #include <iterator>
00013 #include <iostream>
00014 using namespace boost::lambda;
00015
00016 namespace
00017 {
00018 int moveFromX(const osl::Move& move)
00019 {
00020 const osl::Square& p = move.from();
00021 return p.x();
00022 }
00023
00024 int moveFromY(const osl::Move& move)
00025 {
00026 const osl::Square& p = move.from();
00027 return p.y();
00028 }
00029
00030 struct SortMoveFromX :
00031 public std::binary_function<osl::Move, osl::Move, bool>
00032 {
00033 bool operator()(const osl::Move& a, const osl::Move& b) const
00034 {
00035 const osl::Square& a_p = a.from();
00036 const osl::Square& b_p = b.from();
00037 return a_p.x() < b_p.x();
00038 }
00039 };
00040
00041 struct SortMoveFromXDesc :
00042 public std::binary_function<osl::Move, osl::Move, bool>
00043 {
00044 bool operator()(const osl::Move& a, const osl::Move& b) const
00045 {
00046 const osl::Square& a_p = a.from();
00047 const osl::Square& b_p = b.from();
00048 return a_p.x() > b_p.x();
00049 }
00050 };
00051
00052 struct SortMoveFromY :
00053 public std::binary_function<osl::Move, osl::Move, bool>
00054 {
00055 bool operator()(const osl::Move& a, const osl::Move& b) const
00056 {
00057 const osl::Square& a_p = a.from();
00058 const osl::Square& b_p = b.from();
00059 return a_p.y() < b_p.y();
00060 }
00061 };
00062
00063 struct SortMoveFromYDesc :
00064 public std::binary_function<osl::Move, osl::Move, bool>
00065 {
00066 bool operator()(const osl::Move& a, const osl::Move& b) const
00067 {
00068 const osl::Square& a_p = a.from();
00069 const osl::Square& b_p = b.from();
00070 return a_p.y() > b_p.y();
00071 }
00072 };
00073
00074 struct RemoveMoveFromXOver :
00075 public std::unary_function<osl::Move, bool>
00076 {
00077 const int min_x;
00078 RemoveMoveFromXOver(const int min_x)
00079 : min_x(min_x)
00080 {}
00081
00082 bool operator()(const osl::Move& m) const
00083 {
00084 const osl::Square& p = m.from();
00085 return p.x() > min_x;
00086 }
00087 };
00088
00089 struct RemoveMoveFromXGTE :
00090 public std::unary_function<osl::Move, bool>
00091 {
00092 const int min_x;
00093 RemoveMoveFromXGTE(const int min_x)
00094 : min_x(min_x)
00095 {}
00096
00097 bool operator()(const osl::Move& m) const
00098 {
00099 const osl::Square& p = m.from();
00100 return p.x() >= min_x;
00101 }
00102 };
00103
00104 struct RemoveMoveFromYOver :
00105 public std::unary_function<osl::Move, bool>
00106 {
00107 const int min_y;
00108 RemoveMoveFromYOver(const int min_y)
00109 : min_y(min_y)
00110 {}
00111
00112 bool operator()(const osl::Move& m) const
00113 {
00114 const osl::Square& p = m.from();
00115 return p.y() > min_y;
00116 }
00117 };
00118
00119 struct RemoveMoveFromYGTE :
00120 public std::unary_function<osl::Move, bool>
00121 {
00122 const int min_y;
00123 RemoveMoveFromYGTE(const int min_y)
00124 : min_y(min_y)
00125 {}
00126
00127 bool operator()(const osl::Move& m) const
00128 {
00129 const osl::Square& p = m.from();
00130 return p.y() >= min_y;
00131 }
00132 };
00133
00134 struct RemoveMoveFromXUnder :
00135 public std::unary_function<osl::Move, bool>
00136 {
00137 const int max_x;
00138 RemoveMoveFromXUnder(const int max_x)
00139 : max_x(max_x)
00140 {}
00141
00142 bool operator()(const osl::Move& m) const
00143 {
00144 const osl::Square& p = m.from();
00145 return p.x() < max_x;
00146 }
00147 };
00148
00149 struct RemoveMoveFromXLTE :
00150 public std::unary_function<osl::Move, bool>
00151 {
00152 const int max_x;
00153 RemoveMoveFromXLTE(const int max_x)
00154 : max_x(max_x)
00155 {}
00156
00157 bool operator()(const osl::Move& m) const
00158 {
00159 const osl::Square& p = m.from();
00160 return p.x() <= max_x;
00161 }
00162 };
00163
00164 struct RemoveMoveFromYUnder :
00165 public std::unary_function<osl::Move, bool>
00166 {
00167 const int max_y;
00168 RemoveMoveFromYUnder(const int max_y)
00169 : max_y(max_y)
00170 {}
00171
00172 bool operator()(const osl::Move& m) const
00173 {
00174 const osl::Square& p = m.from();
00175 return p.y() < max_y;
00176 }
00177 };
00178
00179 struct RemoveMoveFromYLTE :
00180 public std::unary_function<osl::Move, bool>
00181 {
00182 const int max_y;
00183 RemoveMoveFromYLTE(const int max_y)
00184 : max_y(max_y)
00185 {}
00186
00187 bool operator()(const osl::Move& m) const
00188 {
00189 const osl::Square& p = m.from();
00190 return p.y() <= max_y;
00191 }
00192 };
00193
00194 struct RemoveMoveFromXEqual :
00195 public std::unary_function<osl::Move, bool>
00196 {
00197 const int x;
00198 RemoveMoveFromXEqual(const int x)
00199 : x(x)
00200 {}
00201
00202 bool operator()(const osl::Move& m) const
00203 {
00204 const osl::Square& p = m.from();
00205 return p.x() == x;
00206 }
00207 };
00208
00209 struct RemoveMoveFromYEqual :
00210 public std::unary_function<osl::Move, bool>
00211 {
00212 const int y;
00213 RemoveMoveFromYEqual(const int y)
00214 : y(y)
00215 {}
00216
00217 bool operator()(const osl::Move& m) const
00218 {
00219 const osl::Square& p = m.from();
00220 return p.y() == y;
00221 }
00222 };
00223 }
00224
00225 osl::record::
00226 KanjiMove::KanjiMove()
00227 : verbose(false)
00228 {
00229 for (size_t x=1; x<=9; ++x)
00230 {
00231 for (size_t y=1; y<=9; ++y)
00232 {
00233 const std::string str = StandardCharacters::suji[x] +
00234 StandardCharacters::dan[y];
00235 str2position[str] = Square(x,y);
00236 }
00237 }
00238 str2piece[K_PAWN] = PAWN;
00239 str2piece[K_PPAWN] = PPAWN;
00240 str2piece[K_LANCE] = LANCE;
00241 str2piece[K_PLANCE_D] = PLANCE;
00242 str2piece[K_KNIGHT] = KNIGHT;
00243 str2piece[K_PKNIGHT_D] = PKNIGHT;
00244 str2piece[K_SILVER] = SILVER;
00245 str2piece[K_PSILVER_D] = PSILVER;
00246 str2piece[K_GOLD] = GOLD;
00247 str2piece[K_BISHOP] = BISHOP;
00248 str2piece[K_PBISHOP] = PBISHOP;
00249 str2piece[K_ROOK] = ROOK;
00250 str2piece[K_PROOK] = PROOK;
00251 str2piece[K_PROOK2] = PROOK;
00252 str2piece[K_KING] = KING;
00253
00254
00255 str2piece[K_PLANCE] = PLANCE;
00256 str2piece[K_PKNIGHT] = PKNIGHT;
00257 str2piece[K_PSILVER] = PSILVER;
00258 }
00259
00260 osl::record::
00261 KanjiMove::~KanjiMove()
00262 {
00263 }
00264
00265 osl::Square osl::record::
00266 KanjiMove::toSquare(const std::string& s) const
00267 {
00268 str2position_t::const_iterator p=str2position.find(s);
00269 if (p == str2position.end())
00270 return Square();
00271 return p->second;
00272 }
00273
00274 osl::Ptype osl::record::
00275 KanjiMove::toPtype(const std::string& s) const
00276 {
00277 str2piece_t::const_iterator p=str2piece.find(s);
00278 if (p == str2piece.end())
00279 return Ptype();
00280 return p->second;
00281 }
00282
00283 void osl::record::
00284 KanjiMove::selectCandidates(found_moves_t& found,
00285 std::string& str,
00286 const osl::Square& to_pos,
00287 const osl::Player& player) const
00288 {
00289 assert(!str.empty());
00290 assert(found.size() >= 2);
00291
00292 if ( (str.substr(0,2) == K_MIGI && player == BLACK) ||
00293 (str.substr(0,2) == K_HIDARI && player == WHITE) )
00294 {
00295 found.sort( bind(moveFromX, boost::lambda::_1) < bind(moveFromX, boost::lambda::_2) );
00296 const osl::Move min = found.front();
00297 found.remove_if( RemoveMoveFromXOver(min.from().x()) );
00298 }
00299 else if ( (str.substr(0,2) == K_HIDARI && player == BLACK) ||
00300 (str.substr(0,2) == K_MIGI && player == WHITE) )
00301 {
00302 found.sort( bind(moveFromX, boost::lambda::_1) < bind(moveFromX, boost::lambda::_2) );
00303 const Move max = found.back();
00304 found.remove_if( RemoveMoveFromXUnder(max.from().x()) );
00305 }
00306 else if ( (str.substr(0,2) == K_SHITA && player == BLACK) ||
00307 (str.substr(0,2) == K_UE && player == WHITE) )
00308 {
00309 found.sort( bind(moveFromY, boost::lambda::_1) < bind(moveFromY, boost::lambda::_2) );
00310 const Move min = found.front();
00311 found.remove_if( RemoveMoveFromYOver(min.from().y()) );
00312 }
00313 else if ( (str.substr(0,2) == K_UE && player == BLACK) ||
00314 (str.substr(0,2) == K_SHITA && player == WHITE) )
00315 {
00316 found.sort( bind(moveFromY, boost::lambda::_1) > bind(moveFromY, boost::lambda::_2) );
00317 const Move max = found.front();
00318 found.remove_if( RemoveMoveFromYUnder(max.from().y()) );
00319 }
00320 else if (str.substr(0,2) == K_YORU)
00321 {
00322 found.remove_if( std::not1(RemoveMoveFromYEqual(to_pos.y())) );
00323 }
00324 else if (str.substr(0,2) == K_SUGU && player == WHITE)
00325 {
00326 found.remove_if( std::not1(RemoveMoveFromXEqual(to_pos.x())) );
00327 found.remove_if( std::not1(RemoveMoveFromYEqual(to_pos.y()-1)) );
00328 }
00329 else if (str.substr(0,2) == K_SUGU && player == BLACK)
00330
00331 {
00332 found.remove_if( std::not1(RemoveMoveFromXEqual(to_pos.x())) );
00333 found.remove_if( std::not1(RemoveMoveFromYEqual(to_pos.y()+1)) );
00334 }
00335 else if (str.substr(0,2) == K_HIKU && player == BLACK)
00336 {
00337 found.remove_if( RemoveMoveFromYGTE(to_pos.y()) );
00338 }
00339 else if (str.substr(0,2) == K_HIKU && player == WHITE)
00340 {
00341 found.remove_if( RemoveMoveFromYLTE(to_pos.y()) );
00342 }
00343 else if (str.substr(0,2) == K_YUKU && player == BLACK)
00344 {
00345 found.remove_if( RemoveMoveFromYLTE(to_pos.y()) );
00346 }
00347 else if (str.substr(0,2) == K_YUKU && player == WHITE)
00348 {
00349 found.remove_if( RemoveMoveFromYGTE(to_pos.y()) );
00350 }
00351
00352 str.erase(0,2);
00353 assert(!found.empty());
00354
00355 if (found.size() > 1)
00356 {
00357 assert(!str.empty());
00358 selectCandidates(found, str, to_pos, player);
00359 }
00360
00361 assert(found.size() == 1);
00362 if (!str.empty())
00363 std::cerr << "WARNING: A single candidate is selected, but the input string still has some characters: " << str << std::endl;
00364 }
00365
00366 const osl::Move osl::record::
00367 KanjiMove::strToMove(const std::string& orig,
00368 const osl::NumEffectState& state,
00369 const osl::Move& last_move) const
00370 {
00371 std::string str(orig);
00372 assert(orig.size() >= 4*2 || (str.substr(2,2) == K_ONAZI && orig.size() >= 3*2));
00373 const Player player = str.substr(0,2) == K_BLACK_SIGN ? BLACK : WHITE;
00374 assert(player == state.turn());
00375 str.erase(0,2);
00376
00377 Square to_pos;
00378 if (str.substr(0,2) == K_ONAZI)
00379 {
00380 to_pos = last_move.to();
00381 str.erase(0,2);
00382 if (str.substr(0,2) == K_SPACE)
00383 str.erase(0,2);
00384 }
00385 else
00386 {
00387 to_pos = toSquare(str.substr(0,4));
00388 str.erase(0,4);
00389 }
00390
00391 Ptype ptype;
00392 if (str.substr(0,2) == K_NARU)
00393 {
00394 ptype = toPtype(str.substr(0,4));
00395 str.erase(0,4);
00396 }
00397 else
00398 {
00399 ptype = toPtype(str.substr(0,2));
00400 str.erase(0,2);
00401 }
00402
00403
00404 bool is_promote = false;
00405 if (str.size() >= 4 && str.substr(0,4) == K_FUNARI)
00406 str.erase(0,4);
00407 else if (str.size() >= 4 && str.substr(str.size()-4,4) == K_FUNARI)
00408 str.erase(str.size()-4,4);
00409 else if (str.size() >= 2 && str.substr(0,2) == K_NARU)
00410 {
00411 is_promote = true;
00412 str.erase(0,2);
00413 }
00414 else if (str.size() >= 2 && str.substr(str.size()-2,2) == K_NARU)
00415 {
00416 is_promote = true;
00417 str.erase(str.size()-2,2);
00418 }
00419
00420 MoveVector moves;
00421 LegalMoves::generateWithFullUnpromotions(state, moves);
00422 found_moves_t found;
00423 BOOST_FOREACH(Move move, moves)
00424 {
00425 if (move.oldPtype() == ptype &&
00426 move.to() == to_pos &&
00427 move.isPromotion() == is_promote)
00428 {
00430 if (std::find(found.begin(), found.end(), move) == found.end())
00431 found.push_back(move);
00432 }
00433 }
00434 if (verbose)
00435 {
00436 std::cerr << "\n" << orig << "\n" << state;
00437 std::cerr << "remain: " << str << " (" << str.size() << " bytes)\n";
00438 std::cerr << "promote: " << is_promote << "\n";
00439 std::cerr << "ptype: " << ptype << "\n";
00440 std::cerr << "to_position: " << to_pos << "\n";
00441 std::cerr << "candidates: " << found.size() << std::endl;
00442 if (found.size() >=2) {
00443 BOOST_FOREACH(const Move move, found) {
00444 std::cerr << " " << move << std::endl;
00445 }
00446 }
00447 }
00448 if (found.empty()) {
00449
00450 return Move::INVALID();
00451 }
00452 assert(!found.empty());
00453
00454
00455 if (found.size() == 1)
00456 return found.front();
00457
00458
00459 assert(found.size() >= 2);
00460
00461
00462 if (str.substr(0,2) == K_UTSU)
00463 {
00464 found_moves_t::iterator it =
00465 std::find_if(found.begin(), found.end(),
00466 bind(boost::mem_fn(&Move::isDrop), boost::lambda::_1)
00467 );
00468 str.erase(0,2);
00469 assert(str.empty());
00470 assert(it != found.end());
00471 return *it;
00472 }
00473 else
00474 {
00475 found.remove_if(
00476 bind(boost::mem_fn(&Move::isDrop), boost::lambda::_1)
00477 );
00478 if (found.size() == 1)
00479 return found.front();
00480 }
00481
00482
00483 assert(found.size() >= 2);
00484 assert(!str.empty());
00485 selectCandidates(found, str, to_pos, player);
00486 assert(found.size() == 1);
00487 return found.front();
00488 }
00489
00490 const osl::record::KanjiMove& osl::record::
00491 KanjiMove::instance()
00492 {
00493 static const KanjiMove Kanji_Move;
00494 return Kanji_Move;
00495 }
00496
00497
00498
00499
00500