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