All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
usi.cc
Go to the documentation of this file.
1 /* usi.cc
2  */
3 #include "osl/record/usi.h"
4 #include "osl/record/psn.h"
6 #include "osl/pieceStand.h"
7 #include <boost/algorithm/string/replace.hpp>
8 #include <boost/foreach.hpp>
9 #include <iostream>
10 #include <fstream>
11 #include <sstream>
12 #include <cctype>
13 
14 const std::string osl::record::usi::
16 {
17  if (m.isPass())
18  return "pass";
19  if (m == Move::DeclareWin())
20  return "win";
21  if (! m.isNormal())
22  return "resign";
23  return psn::show(m);
24 }
25 
26 const std::string osl::record::usi::
27 show(PtypeO ptypeo)
28 {
29  if (! isPiece(ptypeo))
30  return "";
31 
32  char c = psn::show(unpromote(getPtype(ptypeo)));
33  if (getOwner(ptypeo) == WHITE)
34  c = tolower(c);
35  std::string ret(1,c);
36  if (isPromoted(ptypeo))
37  ret = "+" + ret;
38  return ret;
39 }
40 
41 const std::string osl::record::usi::
43 {
44  return show(p.ptypeO());
45 }
46 
47 const std::string osl::record::usi::
48 show(const SimpleState& state)
49 {
50  std::ostringstream ret;
51  if (state == SimpleState(HIRATE)) {
52  ret << "startpos";
53  return ret.str();
54  }
55  ret << "sfen ";
56  for (int y=1; y<=9; ++y) {
57  int empty_count = 0;
58  for (int x=9; x>=1; --x) {
59  const Piece p = state.pieceOnBoard(Square(x,y));
60  if (p.isEmpty()) {
61  ++empty_count;
62  continue;
63  }
64  if (empty_count) {
65  ret << empty_count;
66  empty_count = 0;
67  }
68  ret << show(p);
69  }
70  if (empty_count)
71  ret << empty_count;
72  if (y < 9) ret << "/";
73  }
74  ret << " " << "bw"[state.turn() == WHITE] << " ";
75  bool has_any = false;
76  for (int z=0; z<2; ++z) {
77  const Player player = indexToPlayer(z);
78  BOOST_FOREACH(Ptype ptype, PieceStand::order) {
79  const int count = state.countPiecesOnStand(player, ptype);
80  if (count == 0)
81  continue;
82  if (count > 1)
83  ret << count;
84  ret << show(newPtypeO(player, ptype));
85  has_any = true;
86  }
87  }
88  if (! has_any)
89  ret << "-";
90  ret << " 1";
91  return ret.str();
92 }
93 
95 strToMove(const std::string& str, const SimpleState& s)
96 {
97  if (str == "win")
98  return Move::DeclareWin();
99  if (str == "pass")
100  return Move::PASS(s.turn());
101  if (str == "resign")
102  return Move::INVALID();
103  try {
104  return psn::strToMove(str, s);
105  }
106  catch (std::exception& e) {
107  throw ParseError("usi::strToMove failed for " + str + " by "+ e.what());
108  }
109  catch (...) {
110  throw ParseError("usi::strToMove failed for " + str);
111  }
112 }
113 
116 {
117  const Ptype ptype = psn::charToPtype(toupper(c));
118  if (ptype == PTYPE_EMPTY)
119  throw ParseError("Invalid piece character: " + c);
120  const Player pl = isupper(c) ? BLACK : WHITE;
121  return newPtypeO(pl, ptype);
122 }
123 
124 void osl::record::usi::parseBoard(const std::string& word, SimpleState& state)
125 {
126  if (word.empty())
127  throw ParseError(word);
128 
129  state.init();
130  int x=9, y=1;
131  for (size_t i=0; i<word.size(); ++i) {
132  const char c = word[i];
133  if (isalpha(c)) {
134  const PtypeO ptypeo = charToPtypeO(c);
135  state.setPiece(getOwner(ptypeo), Square(x,y), getPtype(ptypeo));
136  --x;
137  } else if (c == '+') {
138  if ( (i+1) >= word.size() )
139  throw ParseError(word);
140  const char next = word[i+1];
141  if (!isalpha(next))
142  throw ParseError(word);
143  const PtypeO ptypeo = charToPtypeO(next);
144  if (!canPromote(ptypeo))
145  throw ParseError(word);
146  const PtypeO promoted = promote(ptypeo);
147  state.setPiece(getOwner(promoted), Square(x,y), getPtype(promoted));
148  --x;
149  ++i;
150  } else if (c == '/') {
151  if (x != 0)
152  throw ParseError(word);
153  x = 9;
154  ++y;
155  } else if (isdigit(c)) {
156  const int n = c - '0';
157  if (n == 0)
158  throw ParseError(word);
159  x -= n;
160  } else {
161  throw ParseError("usi: unknown input " + c);
162  }
163  if (x < 0 || x > 9 || y < 0 || y > 9)
164  throw ParseError(word);
165  }
166 }
167 
168 void osl::record::usi::parse(const std::string& line, NumEffectState& state)
169 {
170  SimpleState board;
171  vector<Move> moves;
172  parse(line, board, moves);
173  state.copyFrom(NumEffectState(board));
174  BOOST_FOREACH(Move move, moves) {
175  state.makeMove(move);
176  }
177 }
178 
181  parse(line,state);
182  return state;
183 }
184 
185 void osl::record::usi::parse(const std::string& line, SimpleState& state, vector<Move>& moves)
186 {
187  moves.clear();
188  std::istringstream is(line);
189  std::string word;
190  is >> word;
191  if (word == "position")
192  is >> word;
193  if (word == "startpos")
194  state.init(HIRATE);
195  else {
196  if (word != "sfen")
197  throw ParseError("sfen not found "+word);
198  is >> word;
199  parseBoard(word, state);
200  is >> word;
201  if (word != "b" && word != "w")
202  throw ParseError(" turn error "+word);
203  state.setTurn((word == "b") ? BLACK : WHITE);
204  is >> word;
205  if (word != "-") {
206  int prefix = 0;
207  BOOST_FOREACH(char c, word) {
208  if (isalpha(c)) {
209  PtypeO ptypeo = charToPtypeO(c);
210  for (int j=0; j<std::max(1, prefix); ++j)
211  state.setPiece(getOwner(ptypeo), Square::STAND(), getPtype(ptypeo));
212  prefix = 0;
213  }
214  else {
215  if (!isdigit(c))
216  throw ParseError(word);
217  prefix = (c - '0') + prefix*10;
218  if (prefix == 0)
219  throw ParseError(word);
220  }
221  }
222  }
223  state.initPawnMask();
224  int move_number; // will not be used
225  if (! (is >> move_number))
226  return;
227  assert(is);
228  }
229  if (! (is >> word))
230  return;
231  if (word != "moves")
232  throw ParseError("moves not found "+word);
233  NumEffectState state_copy(state);
234  while (is >> word) {
235  Move m = strToMove(word, state_copy);
236  moves.push_back(m);
237  if (! m.isNormal() || ! state_copy.isValidMove(m))
238  throw ParseError("invalid move "+word);
239  state_copy.makeMove(m);
240  }
241 }
242 
244 escape(std::string& str)
245 {
246  boost::algorithm::replace_all(str, "/", "_");
247  boost::algorithm::replace_all(str, "+", "@");
248  boost::algorithm::replace_all(str, " ", ".");
249 }
250 
252 unescape(std::string& str)
253 {
254  boost::algorithm::replace_all(str, "_", "/");
255  boost::algorithm::replace_all(str, "@", "+");
256  boost::algorithm::replace_all(str, ".", " ");
257 }
258 
259 
261 UsiFile::UsiFile(const std::string& filename)
262 {
263  std::ifstream is(filename.c_str());
264  std::string line;
265  if (! std::getline(is, line))
266  {
267  const std::string msg = "UsiFile::UsiFile file cannot read ";
268  std::cerr << msg << filename << "\n";
269  throw usi::ParseError(msg + filename);
270  }
271  SimpleState initial;
272  vector<Move> moves;
273  parse(line, initial, moves);
274  assert(initial.isConsistent());
275  record.setInitialState(initial);
276  record::RecordVisitor visitor;
277  visitor.setRecord(&record);
278  visitor.setState(&initial);
279  BOOST_FOREACH(Move move, moves)
280  visitor.addMoveAndAdvance(move);
281 }
282 
285 {
286 }
287 
290 {
291  return record;
292 }
293 
294 const osl::NumEffectState osl::record::usi::
296 {
297  return NumEffectState(record.getInitialState());
298 }
299 
300 /* ------------------------------------------------------------------------- */
301 // ;;; Local Variables:
302 // ;;; mode:c++
303 // ;;; c-basic-offset:2
304 // ;;; End: