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   return psn::strToMove(str, s);
00098 }
00099 
00100 osl::PtypeO osl::record::usi::
00101 charToPtypeO(char c)
00102 {
00103   const Ptype ptype = psn::charToPtype(toupper(c));
00104   if (ptype == PTYPE_EMPTY)
00105     throw ParseError("Invalid piece character: " + c);
00106   const Player pl = isupper(c) ? BLACK : WHITE;
00107   return newPtypeO(pl, ptype);
00108 }
00109 
00110 void osl::record::usi::parseBoard(const std::string& word, SimpleState& state)
00111 {
00112   if (word.empty())
00113     throw ParseError(word);
00114 
00115   state.init();
00116   int x=9, y=1;
00117   for (size_t i=0; i<word.size(); ++i) {
00118     const char c = word[i];
00119     if (isalpha(c)) {
00120       const PtypeO ptypeo = charToPtypeO(c);
00121       state.setPiece(getOwner(ptypeo), Square(x,y), getPtype(ptypeo));
00122       --x;
00123     } else if (c == '+') {
00124       if ( (i+1) >= word.size() )
00125         throw ParseError(word);
00126       const char next = word[i+1];
00127       if (!isalpha(next))
00128         throw ParseError(word);
00129       const PtypeO ptypeo = charToPtypeO(next);
00130       if (!canPromote(ptypeo))
00131         throw ParseError(word);
00132       const PtypeO promoted = promote(ptypeo);
00133       state.setPiece(getOwner(promoted), Square(x,y), getPtype(promoted));
00134       --x;
00135       ++i;
00136     } else if (c == '/') {
00137       if (x != 0)
00138         throw ParseError(word);
00139       x = 9;
00140       ++y;
00141     } else if (isdigit(c)) {
00142       const int n = c - '0';
00143       if (n == 0)
00144         throw ParseError(word);
00145       x -= n;
00146     } else {
00147       throw ParseError("usi: unknown input " + c);
00148     }
00149     if (x < 0 || x > 9 || y < 0 || y > 9)
00150       throw ParseError(word);
00151   }
00152 }
00153 
00154 void osl::record::usi::parse(const std::string& line, NumEffectState& state)
00155 {
00156   SimpleState board;
00157   vector<Move> moves;
00158   parse(line, board, moves);
00159   state.copyFrom(NumEffectState(board));
00160   BOOST_FOREACH(Move move, moves) {
00161     state.makeMove(move);
00162   }
00163 }
00164 
00165 void osl::record::usi::parse(const std::string& line, SimpleState& state, vector<Move>& moves)
00166 {
00167   moves.clear();
00168   std::istringstream is(line);
00169   std::string word;
00170   is >> word;
00171   if (word == "position")
00172     is >> word;
00173   if (word == "startpos") 
00174     state.init(HIRATE);
00175   else {
00176     if (word != "sfen")
00177         throw ParseError("sfen not found "+word);
00178     is >> word;
00179     parseBoard(word, state);
00180     is >> word;
00181     if (word != "b" && word != "w")
00182         throw ParseError(" turn error "+word);
00183     state.setTurn((word == "b") ? BLACK : WHITE);
00184     is >> word;
00185     if (word != "-") {
00186       int prefix = 0;
00187       BOOST_FOREACH(char c, word) {
00188         if (isalpha(c)) {
00189           PtypeO ptypeo = charToPtypeO(c);
00190           for (int j=0; j<std::max(1, prefix); ++j)
00191             state.setPiece(getOwner(ptypeo), Square::STAND(), getPtype(ptypeo));
00192           prefix = 0;
00193         }
00194         else {
00195           if (!isdigit(c))
00196             throw ParseError(word);
00197           prefix = (c - '0') + prefix*10;
00198           if (prefix == 0)
00199             throw ParseError(word);
00200         }
00201       }
00202     }
00203     state.initPawnMask();
00204     int move_number; // will not be used
00205     if (! (is >> move_number))
00206       return;
00207     assert(is);
00208   }
00209   if (! (is >> word))
00210     return;
00211   if (word != "moves")
00212     throw ParseError("moves not found "+word);
00213   NumEffectState state_copy(state);
00214   while (is >> word) {
00215     Move m = strToMove(word, state_copy);
00216     moves.push_back(m);
00217     if (! m.isNormal() || ! state_copy.isValidMove(m))
00218       throw ParseError("invalid move "+word);
00219     state_copy.makeMove(m);
00220   }
00221 } 
00222 
00223 void osl::record::usi::
00224 escape(std::string& str)
00225 {
00226   boost::algorithm::replace_all(str, "/", "_");
00227   boost::algorithm::replace_all(str, "+", "@");
00228   boost::algorithm::replace_all(str, " ", ".");
00229 }
00230 
00231 void osl::record::usi::
00232 unescape(std::string& str)
00233 {
00234   boost::algorithm::replace_all(str, "_", "/");
00235   boost::algorithm::replace_all(str, "@", "+");
00236   boost::algorithm::replace_all(str, ".", " ");
00237 }
00238 
00239 
00240 osl::record::usi::
00241 UsiFile::UsiFile(const std::string& filename)
00242 {
00243   std::ifstream is(filename.c_str());
00244   std::string line;
00245   if (! std::getline(is, line))
00246   {
00247     const std::string msg = "UsiFile::UsiFile file cannot read ";
00248     std::cerr << msg << filename << "\n";
00249     throw usi::ParseError(msg + filename);
00250   }
00251   SimpleState initial;
00252   vector<Move> moves;
00253   parse(line, initial, moves);
00254   assert(initial.isConsistent());
00255   record.setInitialState(initial);
00256   record::RecordVisitor visitor;
00257   visitor.setRecord(&record);
00258   visitor.setState(&initial);
00259   BOOST_FOREACH(Move move, moves)
00260     visitor.addMoveAndAdvance(move);
00261 }
00262 
00263 osl::record::usi::
00264 UsiFile::~UsiFile()
00265 {
00266 }
00267 
00268 const osl::record::Record& osl::record::usi::
00269 UsiFile::getRecord() const
00270 {
00271   return record;
00272 }
00273 
00274 const osl::NumEffectState osl::record::usi::
00275 UsiFile::getInitialState() const
00276 {
00277   return NumEffectState(record.getInitialState());
00278 }
00279 
00280 /* ------------------------------------------------------------------------- */
00281 // ;;; Local Variables:
00282 // ;;; mode:c++
00283 // ;;; c-basic-offset:2
00284 // ;;; End:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines