usi.cc
Go to the documentation of this file.
00001 /* usi.cc
00002  */
00003 #include "osl/record/usi.h"
00004 #include "osl/record/psn.h"
00005 #include "osl/state/simpleState.h"
00006 #include "osl/pieceStand.h"
00007 #include <boost/algorithm/string/replace.hpp>
00008 #include <boost/foreach.hpp>
00009 #include <iostream>
00010 #include <fstream>
00011 #include <sstream>
00012 #include <cctype>
00013 
00014 const std::string osl::record::usi::
00015 show(Move m)
00016 {
00017   if (m.isPass())
00018     return "pass";
00019   if (m == Move::DeclareWin())
00020     return "win";
00021   if (! m.isNormal())
00022     return "resign";
00023   return psn::show(m);
00024 }
00025 
00026 const std::string osl::record::usi::
00027 show(PtypeO ptypeo)
00028 {
00029   if (! isPiece(ptypeo))
00030     return "";
00031 
00032   char c = psn::show(unpromote(getPtype(ptypeo)));
00033   if (getOwner(ptypeo) == WHITE)
00034     c = tolower(c);
00035   std::string ret(1,c);
00036   if (isPromoted(ptypeo))
00037     ret = "+" + ret;
00038   return ret;
00039 }
00040 
00041 const std::string osl::record::usi::
00042 show(Piece p)
00043 {
00044   return show(p.ptypeO());
00045 }
00046 
00047 const std::string osl::record::usi::
00048 show(const SimpleState& state)
00049 {
00050   std::ostringstream ret;
00051   if (state == SimpleState(HIRATE)) {
00052     ret << "startpos";
00053     return ret.str();
00054   }
00055   ret << "sfen ";
00056   for (int y=1; y<=9; ++y) {
00057     int empty_count = 0;
00058     for (int x=9; x>=1; --x) {
00059       const Piece p = state.pieceOnBoard(Square(x,y));
00060       if (p.isEmpty()) {
00061         ++empty_count;
00062         continue;
00063       }
00064       if (empty_count) {
00065         ret << empty_count;
00066         empty_count = 0;
00067       }
00068       ret << show(p);
00069     }
00070     if (empty_count)
00071       ret << empty_count;
00072     if (y < 9) ret << "/";
00073   }
00074   ret << " " << "bw"[state.turn() == WHITE] << " ";
00075   bool has_any = false;
00076   for (int z=0; z<2; ++z) {
00077     const Player player = indexToPlayer(z);
00078     BOOST_FOREACH(Ptype ptype, PieceStand::order) {
00079       const int count = state.countPiecesOnStand(player, ptype);
00080       if (count == 0)
00081         continue;
00082       if (count > 1)
00083         ret << count;
00084       ret << show(newPtypeO(player, ptype));
00085       has_any = true;
00086     }
00087   }
00088   if (! has_any)
00089     ret << "-";
00090   ret << " 1";
00091   return ret.str();
00092 }
00093 
00094 const osl::Move osl::record::usi::
00095 strToMove(const std::string& str, const SimpleState& s)
00096 {
00097   if (str == "win")
00098     return Move::DeclareWin();
00099   if (str == "pass")
00100     return Move::PASS(s.turn());
00101   if (str == "resign")
00102     return Move::INVALID();
00103   try {
00104     return psn::strToMove(str, s);
00105   }
00106   catch (...) {
00107     throw ParseError("usi::strToMove failed for " + str);
00108   }
00109 }
00110 
00111 osl::PtypeO osl::record::usi::
00112 charToPtypeO(char c)
00113 {
00114   const Ptype ptype = psn::charToPtype(toupper(c));
00115   if (ptype == PTYPE_EMPTY)
00116     throw ParseError("Invalid piece character: " + c);
00117   const Player pl = isupper(c) ? BLACK : WHITE;
00118   return newPtypeO(pl, ptype);
00119 }
00120 
00121 void osl::record::usi::parseBoard(const std::string& word, SimpleState& state)
00122 {
00123   if (word.empty())
00124     throw ParseError(word);
00125 
00126   state.init();
00127   int x=9, y=1;
00128   for (size_t i=0; i<word.size(); ++i) {
00129     const char c = word[i];
00130     if (isalpha(c)) {
00131       const PtypeO ptypeo = charToPtypeO(c);
00132       state.setPiece(getOwner(ptypeo), Square(x,y), getPtype(ptypeo));
00133       --x;
00134     } else if (c == '+') {
00135       if ( (i+1) >= word.size() )
00136         throw ParseError(word);
00137       const char next = word[i+1];
00138       if (!isalpha(next))
00139         throw ParseError(word);
00140       const PtypeO ptypeo = charToPtypeO(next);
00141       if (!canPromote(ptypeo))
00142         throw ParseError(word);
00143       const PtypeO promoted = promote(ptypeo);
00144       state.setPiece(getOwner(promoted), Square(x,y), getPtype(promoted));
00145       --x;
00146       ++i;
00147     } else if (c == '/') {
00148       if (x != 0)
00149         throw ParseError(word);
00150       x = 9;
00151       ++y;
00152     } else if (isdigit(c)) {
00153       const int n = c - '0';
00154       if (n == 0)
00155         throw ParseError(word);
00156       x -= n;
00157     } else {
00158       throw ParseError("usi: unknown input " + c);
00159     }
00160     if (x < 0 || x > 9 || y < 0 || y > 9)
00161       throw ParseError(word);
00162   }
00163 }
00164 
00165 void osl::record::usi::parse(const std::string& line, NumEffectState& state)
00166 {
00167   SimpleState board;
00168   vector<Move> moves;
00169   parse(line, board, moves);
00170   state.copyFrom(NumEffectState(board));
00171   BOOST_FOREACH(Move move, moves) {
00172     state.makeMove(move);
00173   }
00174 }
00175 
00176 void osl::record::usi::parse(const std::string& line, SimpleState& state, vector<Move>& moves)
00177 {
00178   moves.clear();
00179   std::istringstream is(line);
00180   std::string word;
00181   is >> word;
00182   if (word == "position")
00183     is >> word;
00184   if (word == "startpos") 
00185     state.init(HIRATE);
00186   else {
00187     if (word != "sfen")
00188         throw ParseError("sfen not found "+word);
00189     is >> word;
00190     parseBoard(word, state);
00191     is >> word;
00192     if (word != "b" && word != "w")
00193         throw ParseError(" turn error "+word);
00194     state.setTurn((word == "b") ? BLACK : WHITE);
00195     is >> word;
00196     if (word != "-") {
00197       int prefix = 0;
00198       BOOST_FOREACH(char c, word) {
00199         if (isalpha(c)) {
00200           PtypeO ptypeo = charToPtypeO(c);
00201           for (int j=0; j<std::max(1, prefix); ++j)
00202             state.setPiece(getOwner(ptypeo), Square::STAND(), getPtype(ptypeo));
00203           prefix = 0;
00204         }
00205         else {
00206           if (!isdigit(c))
00207             throw ParseError(word);
00208           prefix = (c - '0') + prefix*10;
00209           if (prefix == 0)
00210             throw ParseError(word);
00211         }
00212       }
00213     }
00214     state.initPawnMask();
00215     int move_number; // will not be used
00216     if (! (is >> move_number))
00217       return;
00218     assert(is);
00219   }
00220   if (! (is >> word))
00221     return;
00222   if (word != "moves")
00223     throw ParseError("moves not found "+word);
00224   NumEffectState state_copy(state);
00225   while (is >> word) {
00226     Move m = strToMove(word, state_copy);
00227     moves.push_back(m);
00228     if (! m.isNormal() || ! state_copy.isValidMove(m))
00229       throw ParseError("invalid move "+word);
00230     state_copy.makeMove(m);
00231   }
00232 } 
00233 
00234 void osl::record::usi::
00235 escape(std::string& str)
00236 {
00237   boost::algorithm::replace_all(str, "/", "_");
00238   boost::algorithm::replace_all(str, "+", "@");
00239   boost::algorithm::replace_all(str, " ", ".");
00240 }
00241 
00242 void osl::record::usi::
00243 unescape(std::string& str)
00244 {
00245   boost::algorithm::replace_all(str, "_", "/");
00246   boost::algorithm::replace_all(str, "@", "+");
00247   boost::algorithm::replace_all(str, ".", " ");
00248 }
00249 
00250 
00251 osl::record::usi::
00252 UsiFile::UsiFile(const std::string& filename)
00253 {
00254   std::ifstream is(filename.c_str());
00255   std::string line;
00256   if (! std::getline(is, line))
00257   {
00258     const std::string msg = "UsiFile::UsiFile file cannot read ";
00259     std::cerr << msg << filename << "\n";
00260     throw usi::ParseError(msg + filename);
00261   }
00262   SimpleState initial;
00263   vector<Move> moves;
00264   parse(line, initial, moves);
00265   assert(initial.isConsistent());
00266   record.setInitialState(initial);
00267   record::RecordVisitor visitor;
00268   visitor.setRecord(&record);
00269   visitor.setState(&initial);
00270   BOOST_FOREACH(Move move, moves)
00271     visitor.addMoveAndAdvance(move);
00272 }
00273 
00274 osl::record::usi::
00275 UsiFile::~UsiFile()
00276 {
00277 }
00278 
00279 const osl::record::Record& osl::record::usi::
00280 UsiFile::getRecord() const
00281 {
00282   return record;
00283 }
00284 
00285 const osl::NumEffectState osl::record::usi::
00286 UsiFile::getInitialState() const
00287 {
00288   return NumEffectState(record.getInitialState());
00289 }
00290 
00291 /* ------------------------------------------------------------------------- */
00292 // ;;; Local Variables:
00293 // ;;; mode:c++
00294 // ;;; c-basic-offset:2
00295 // ;;; End:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines