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 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;
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
00282
00283
00284