Go to the documentation of this file.00001
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;
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
00293
00294
00295