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