All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
ki2.cc
Go to the documentation of this file.
1 #include "osl/record/ki2.h"
2 #include "osl/record/kanjiCode.h"
5 #include "osl/misc/sjis2euc.h"
6 #include "osl/ptypeTable.h"
7 #include <boost/foreach.hpp>
8 #include <boost/algorithm/string/trim.hpp>
9 #include <fstream>
10 #include <iostream>
11 
12 namespace osl
13 {
14  namespace record
15  {
16  namespace // anonymous
17  {
18  enum ParseResult
19  {
20  OK = 0,
21  KOMAOCHI,
22  ILLEGAL,
23  };
24 
25  ParseResult ki2ParseLine(RecordVisitor& rv,
26  std::string line,
27  const osl::record::KanjiMove& kmove)
28  {
29  boost::algorithm::trim(line);
30 
31  if (line.empty() || line.at(0) == '*')
32  return OK;
33  else if (line.size() > 10 && line.substr(0,10) == (K_KAISHI K_NICHIJI K_COLON))
34  {
35  Record *record = rv.getRecord();
36  std::string date_str(line.substr(10)); // this may or may not include HH:MM
38  const static std::string spaces[] = {" ", K_SPACE};
39  BOOST_FOREACH(const std::string& space, spaces) {
40  const std::string::size_type pos_space = date_str.find(space);
41  if (pos_space != std::string::npos)
42  date_str = date_str.substr(0, pos_space);
43  }
44  record->setDate(date_str);
45  // an invalid date_str results in an invalid boost::gregorian::date value
46  // you can check it date.is_special()
47  return OK;
48  }
49  else if (line.size() > 6 && line.substr(0,6) == (K_BLACK K_COLON))
50  {
51  Record *record = rv.getRecord();
52  const std::string player_name(line.substr(6));
53  record->setPlayer(osl::BLACK, player_name);
54  return OK;
55  }
56  else if (line.size() > 6 && line.substr(0,6) == (K_WHITE K_COLON))
57  {
58  Record *record = rv.getRecord();
59  const std::string player_name(line.substr(6));
60  record->setPlayer(osl::WHITE, player_name);
61  return OK;
62  }
63  else if (line.size() > 6 && line.substr(0,6) == (K_KISEN K_COLON))
64  {
65  Record *record = rv.getRecord();
66  record->setTounamentName(line.substr(6));
67  return OK;
68  }
69  else if (line.size() > 8 && line.substr(0,8) == (K_TEAIWARI K_COLON))
70  return KOMAOCHI;
71  else if (line.substr(0,2) != K_BLACK_SIGN && line.substr(0,2) != K_WHITE_SIGN)
72  return OK;
73 
74  std::string move_str;
75  for (size_t i = 0; ; )
76  {
77  if (i < line.size() &&
78  (line.at(i) == ' ' || line.at(i) == '\t'))
79  {
80  ++i;
81  continue;
82  }
83 
84  if ( (line.substr(i,2) == K_BLACK_SIGN ||
85  line.substr(i,2) == K_WHITE_SIGN ||
86  i+1 >= line.size())
87  && !move_str.empty())
88  {
89  // apply move_str
90  Move last_move;
91  if (rv.getLastMove())
92  last_move = rv.getLastMove()->getMove();
93  const NumEffectState state(*rv.getState());
94  const Move move = kmove.strToMove(move_str, state, last_move);
95  if (!move.isValid()) {
96  if (move_str.find(K_RESIGN) != move_str.npos)
97  return OK;
98  return ILLEGAL;
99  }
100  rv.addMoveAndAdvance(move);
101  move_str.clear();
102  }
103  if (i+1 >= line.size())
104  return OK;
105  move_str.append(line.substr(i,2));
106  i += 2;
107  } // for
108  }
109 
110  } // anonymous namespace
111  } //namespace record
112 } // namespace osl
113 
114 
116 InputStream::InputStream(std::istream& is, bool verbose)
117  : is(is), state(SimpleState(HIRATE))
118 {
119  if (! is)
120  {
121  std::cerr << "InputStream::InputStream cannot read \n";
122  abort();
123  }
124  kmove.setVerbose(verbose);
125 }
126 
129 
132 {
133  rv.setState(&state);
134  rv.setRecord(rec);
135  std::string line;
136  while (std::getline(is, line))
137  {
138  line = misc::sjis2euc(line);
139  const ParseResult result = ki2ParseLine(rv, line, kmove);
140  switch (result)
141  {
142  case OK:
143  continue;
144  case KOMAOCHI:
145  {
146  const std::string msg = "ERROR: Komaochi (handicapped game) records are not available: ";
147  std::cerr << msg << "\n";
148  throw Ki2IOError(msg);
149  }
150  case ILLEGAL:
151  {
152  const std::string msg = "ERROR: An illegal move found in a record.";
153  throw Ki2IOError(msg);
154  }
155  default:
156  assert(false);
157  }
158  }
159 }
160 
162 Ki2File::Ki2File(const std::string& fileName, bool verbose)
163  : verbose(verbose)
164 {
165  std::ifstream ifs(fileName.c_str());
166  if (! ifs)
167  {
168  const std::string msg = "Ki2File::Ki2File file cannot read ";
169  std::cerr << msg << fileName << "\n";
170  throw Ki2IOError(msg + fileName);
171  }
172  InputStream irs(ifs, verbose);
173  irs.load(&rec);
174 }
175 
178 {
179  return rec;
180 }
181 
182 const osl::NumEffectState osl::record::ki2::
184 {
185  return rec.getInitialState();
186 }
187 
188 const std::string osl::record::ki2::show(Square position)
189 {
190  if (position.isPieceStand())
191  return "";
192  const int x = position.x(), y = position.y();
194 }
195 
196 const std::string osl::record::ki2::show(Ptype ptype)
197 {
198  switch (ptype)
199  {
200  case PSILVER: case PKNIGHT: case PLANCE:
201  return K_NARU + StandardCharacters().kanji(unpromote(ptype));
202  default:
203  ;
204  }
205  return StandardCharacters().kanji(ptype);
206 }
207 
208 const std::string osl::record::ki2::showPromote(bool promote)
209 {
210  return promote ? K_NARU : K_FUNARI;
211 }
212 
213 const std::string osl::record::ki2::show(Square cur, Square prev)
214 {
215  if (cur == prev)
216  return K_ONAZI;
217  return show(cur);
218 }
219 
220 const std::string osl::record::ki2::show(Move m, const NumEffectState& state,
221  Move prev)
222 {
223  std::string ret = (m.player() == BLACK) ? K_BLACK_SIGN : K_WHITE_SIGN;
224  if (m.isPass()) {
225  ret += K_PASS;
226  return ret;
227  }
228  const Square from = m.from(), to = m.to();
229  const Ptype ptype = m.oldPtype();
230  const Player player = m.player();
231  mask_t pieces = state.allEffectAt(player, ptype, to);
232  const mask_t promoted = state.promotedPieces().getMask(Ptype_Table.getIndex(ptype));
233  if (isPromoted(ptype))
234  pieces &= promoted;
235  else
236  pieces &= ~promoted;
237  if (from.isPieceStand()) {
238  ret += show(to) + show(ptype);
239  int has_effect = 0;
240  while (pieces.any()) {
241  const Piece p = state.pieceOf(pieces.takeOneBit());
242  if (p.ptype() == ptype)
243  ++has_effect;
244  }
245  if (has_effect)
246  ret += K_UTSU;
247  return ret;
248  }
249  ret += prev.isNormal() && (to == prev.to())
250  ? K_ONAZI : show(to);
251  ret += show(m.oldPtype());
252  const int count = pieces.countBit();
253  if (count >= 2) {
254  CArray<int,3> x_count = {{ 0 }}, y_count = {{ 0 }};
255  int my_x = 0, my_y = 0;
256  while (pieces.any()) {
257  const int n = pieces.takeOneBit() + Ptype_Table.getIndex(ptype)*32;
258  const Piece p = state.pieceOf(n);
259  if (p.ptype() != ptype)
260  continue;
261  int index_x = 1, index_y = 1;
262  if (p.square().x() != to.x())
263  index_x = ((p.square().x() - to.x()) * playerToMul(player) > 0)
264  ? 2 : 0;
265  if (p.square().y() != to.y())
266  index_y = ((p.square().y() - to.y()) * playerToMul(player) > 0)
267  ? 2 : 0;
268  if (p.square() == from)
269  my_x = index_x, my_y = index_y;
270  x_count[index_x]++;
271  y_count[index_y]++;
272  }
273  if (y_count[my_y] == 1) {
274  if (from.y() == to.y())
275  ret += K_YORU;
276  else if ((to.y() - from.y())*playerToMul(player) > 0)
277  ret += K_HIKU;
278  else
279  ret += K_UE;
280  }
281  else if (x_count[my_x] == 1) {
282  if (from.x() == to.x()) {
283  if (isPromoted(ptype) && isMajor(ptype)) {
284  const Piece l = state.pieceAt
285  (Square(from.x() - playerToMul(player), from.y()));
286  if (l.isOnBoardByOwner(player) && l.ptype() == ptype)
287  ret += K_HIDARI;
288  else
289  ret += K_MIGI;
290  }
291  else
292  ret += K_SUGU;
293  }
294  else if ((to.x() - from.x())*playerToMul(player) > 0)
295  ret += K_MIGI;
296  else
297  ret += K_HIDARI;
298  }
299  else if (from.x() == to.x()) {
300  if ((to.y() - from.y())*playerToMul(player) > 0)
301  ret += K_HIKU;
302  else
303  ret += K_SUGU;
304  }
305  else {
306  if ((to.x() - from.x())*playerToMul(player) > 0)
307  ret += K_MIGI;
308  else
309  ret += K_HIDARI;
310  if ((to.y() - from.y())*playerToMul(player) > 0)
311  ret += K_HIKU;
312  else
313  ret += K_UE;
314  }
315  }
316  if (canPromote(m.oldPtype()))
317  if (m.isPromotion()
318  || to.canPromote(player) || from.canPromote(player)) {
319  ret += showPromote(m.isPromotion());
320  }
321  return ret;
322 }
323 
324 const std::string osl::record::
325 ki2::show(const Move *first, const Move *last,
326  const char *threatmate_first, const char *threatmate_last,
327  const NumEffectState& initial, Move prev)
328 {
329  if (first == last || first->isInvalid())
330  return "";
331  NumEffectState state(initial);
332  std::string ret = show(*first, state, prev);
333  if (threatmate_first != threatmate_last
334  && *threatmate_first++)
335  ret += "(" K_TSUMERO ")";
336  for (; first+1 != last; ++first) {
337  if (first->isInvalid())
338  break;
339  state.makeMove(*first);
340  ret += show(*(first+1), state, *first);
341  if (threatmate_first != threatmate_last
342  && *threatmate_first++)
343  ret += "(" K_TSUMERO ")";
344  }
345  return ret;
346 }
347 
348 const std::string osl::record::
349 ki2::show(const Move *first, const Move *last, const NumEffectState& initial, Move prev)
350 {
351  vector<char> threatmate(last-first, false);
352  return show(first, last, &*threatmate.begin(), &*threatmate.end(), initial, prev);
353 }
354 
355 // ;;; Local Variables:
356 // ;;; mode:c++
357 // ;;; c-basic-offset:2
358 // ;;; End: