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