All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
kisen.cc
Go to the documentation of this file.
1 #include "osl/record/kisen.h"
3 #include "osl/pieceStand.h"
4 #include "osl/misc/filePath.h"
6 #include "osl/misc/sjis2euc.h"
7 #include <boost/filesystem/convenience.hpp>
8 #include <boost/foreach.hpp>
9 #include <iostream>
10 
11 namespace osl
12 {
13 namespace record
14 {
16  assert(1<=pos && pos<=0x51);
17  int y=((pos-1)/9)+1, x=((pos-1)%9)+1;
18  return Square(x,y);
19  }
21  {
22  return ((pos.y() - 1) * 9 + 1) + pos.x() - 1;
23  }
24 
25  Move KisenUtils::convertMove(SimpleState const& state,int c0,int c1){
26  Move move;
27 
28  if(1<=c1 && c1<=0x51){
29  Square from=convertSquare(c1),to;
30  Piece fromPiece=state.pieceOnBoard(from);
31  if (! fromPiece.isPiece())
32  throw CsaIOError("Square error");
33  assert(fromPiece.isPiece());
34  assert(fromPiece.owner()==state.turn() ||
35  (std::cerr << c1 << "," << from << "," << fromPiece << std::endl,0)
36  );
37  bool isPromote=false;
38  if(1<=c0 && c0<=0x51){
39  to=convertSquare(c0);
40  }
41  else if(0x65<=c0 && c0<=0xb5){
42  to=convertSquare(c0-0x64);
43  isPromote=true;
44  }
45  else{
46  throw CsaIOError("c0 range error");
47  }
48  Piece toPiece=state.pieceAt(to);
49  if (! toPiece.isEmpty() && toPiece.owner()!=alt(state.turn()))
50  throw CsaIOError("inconsintent move (to)");
51  Ptype ptype=fromPiece.ptype();
52  if(isPromote)ptype=promote(ptype);
53  const Ptype captured = toPiece.ptype();
54  if (captured == KING)
55  return Move::INVALID();
56  move=Move(from,to,ptype,captured,isPromote,state.turn());
57  }
58  else{
59  assert(0x65<=c1);
60  assert(1<=c0&&c0<=0x51);
61  Square to=convertSquare(c0);
62  Ptype ptype=PTYPE_EMPTY;
63  int piece_on_stand = c1;
64  const Ptype ptypes[]={ROOK,BISHOP,GOLD,SILVER,KNIGHT,LANCE,PAWN};
65  for(size_t i=0;i<sizeof(ptypes)/sizeof(Ptype);i++){
66  int count=state.countPiecesOnStand(state.turn(),ptypes[i]);
67  if(count>0){
68  if(piece_on_stand>0x64){
69  piece_on_stand-=count;
70  if(piece_on_stand<=0x64) ptype=ptypes[i];
71  }
72  }
73  }
74  assert(ptype!=PTYPE_EMPTY ||
75  (std::cerr << state << to << " " << c1
76  << " " << piece_on_stand << std::endl, false));
77  move=Move(to,ptype,state.turn());
78  }
79  if (! state.isValidMove(move,true)) {
80  std::cerr << "warning: bad move in kisen\n" << state << move << "\n";
81  return Move();
82  }
83  assert(state.isValidMove(move,true) ||
84  (std::cerr << state << move << std::endl, false));
85  return move;
86  }
87 
88 
89  KisenFile::KisenFile(const std::string& fileName)
90  :ifs(fileName.c_str()),initialState(HIRATE), fileName(fileName)
91  {
92  if (! ifs)
93  throw CsaIOError("KisenFile not found");
94  ifs.seekg(0,std::ios::end);
95  assert((ifs.tellg() % 512)==0);
96  numberOfGames=ifs.tellg()/512;
97  }
98 
99  const vector<Move> KisenFile::getMoves(size_t index)
100  {
101  assert(index<size());
102  vector<Move> moves;
103  // std::cerr << "Game[" << index << "]" << std::endl;
104  ifs.seekg(index*512,std::ios::beg);
105  CArray<unsigned char, 512> cbuf;
106  ifs.read(reinterpret_cast<char *>(&cbuf[0]),512);
107  NumEffectState state;
108  //
109  Player turn=BLACK;
110  for(size_t turnCount=0;
111  (turnCount*2 < cbuf.size())
112  && cbuf[turnCount*2]!=0 && cbuf[turnCount*2+1]!=0;
113  turnCount++, turn=alt(turn)){
114  if(turnCount==KisenFile::maxMoves || cbuf[ turnCount *2 ] == 0 || cbuf[ turnCount * 2 + 1 ] == 0 ){ break; }
115  int c0=cbuf[turnCount*2], c1=cbuf[turnCount*2+1];
116  if (moves.empty() && c0 == 0xff && c1 == 0xff) // komaochi
117  break;
118  const Move move=KisenUtils::convertMove(state,c0,c1);
119  if (move.isInvalid())
120  break;
121  moves.push_back(move);
122  state.makeMove(move);
123  assert(state.isConsistent( true ) );
124  }
125  return moves;
126  }
127 #ifndef MINIMAL
128  const std::string KisenFile::ipxFileName(const std::string& filename)
129  {
130  namespace bf = boost::filesystem;
131  const bf::path ipxfilename = bf::change_extension(bf::path(filename), ".ipx");
132  return misc::file_string(ipxfilename);
133  }
134 
135  KisenIpxFile::KisenIpxFile(const std::string& fileName)
136  :ifs(fileName.c_str()), file_name(fileName)
137  {
138  if (! ifs)
139  throw CsaIOError("KisenIpxFile not found");
140  ifs.seekg(0,std::ios::end);
141  assert((ifs.tellg() % 256)==0);
142  numberOfGames=ifs.tellg()/256;
143  }
144  const std::string KisenIpxFile::getPlayer(size_t index,Player pl)
145  {
146  assert(index<size());
147  vector<Move> moves;
148  ifs.seekg(index*256,std::ios::beg);
149  CArray<unsigned char, 256> cbuf;
150  ifs.read(reinterpret_cast<char *>(&cbuf[0]),256);
151  int startIndex=0;
152  if(pl==WHITE)startIndex=14;
153  CArray<char,15> buf;
154  buf[14]='\0';
155  strncpy(&buf[0],reinterpret_cast<char *>(&cbuf[startIndex]),14);
156  return misc::sjis2euc(std::string(&buf[0]));
157  }
158  unsigned int KisenIpxFile::getRating(size_t index,Player pl)
159  {
160  assert(index<size());
161  vector<Move> moves;
162  ifs.seekg(index*256,std::ios::beg);
163  CArray<unsigned char, 256> cbuf;
164  ifs.read(reinterpret_cast<char *>(&cbuf[0]),256);
165  int startIndex=0324;
166  if(pl==WHITE)startIndex=0326;
167  return cbuf[startIndex]+256*cbuf[startIndex+1];
168  }
169  unsigned int KisenIpxFile::getResult(size_t index)
170  {
171  assert(index<size());
172  ifs.seekg(index*256,std::ios::beg);
173  CArray<unsigned char, 256> cbuf;
174  ifs.read(reinterpret_cast<char *>(&cbuf[0]),256);
175  return cbuf[64+48+6];
176  }
177  const std::string KisenIpxFile::getTitle(size_t index,Player pl)
178  {
179  assert(index<size());
180  vector<Move> moves;
181  ifs.seekg(index*256,std::ios::beg);
182  CArray<unsigned char, 256> cbuf;
183  ifs.read(reinterpret_cast<char *>(&cbuf[0]),256);
184  int startIndex=28;
185  if(pl==WHITE)startIndex+=8;
186  CArray<char,9> buf;
187  buf[8]='\0';
188  strncpy(&buf[0],reinterpret_cast<const char*>(&cbuf[startIndex]),8);
189  return misc::sjis2euc(std::string(&buf[0]));
190  }
191  boost::gregorian::date KisenIpxFile::getStartDate(size_t index)
192  {
193  assert(index<size());
194  ifs.seekg(index*256,std::ios::beg);
195  CArray<unsigned char, 256> cbuf;
196  ifs.read(reinterpret_cast<char *>(&cbuf[0]),256);
197  const int startIndex=84;
198  const unsigned int year = cbuf[startIndex] + 256*cbuf[startIndex+1];
199  const unsigned int month = cbuf[startIndex+2];
200  const unsigned int day = cbuf[startIndex+3];
201  try {
202  const boost::gregorian::date d = boost::gregorian::date(year, month, day);
203  return d;
204  } catch (std::out_of_range& e) {
205  std::cerr << e.what() << ": ["
206  << index << "] " << year << "-" << month << "-" << day << "\n";
207  return boost::gregorian::date(boost::gregorian::not_a_date_time);
208  }
209  }
210 
211  KisenPlusFile::KisenPlusFile(const std::string& fileName)
212  :ifs(fileName.c_str()),initialState(HIRATE)
213  {
214  if (! ifs)
215  throw CsaIOError("KisenPlusFile not found");
216  ifs.seekg(0,std::ios::end);
217  assert((ifs.tellg() % 2048)==0);
218  numberOfGames=ifs.tellg()/2048;
219  }
220 
221  const vector<Move> KisenPlusFile::getMoves(size_t index)
222  {
223  vector<Move> moves;
224  vector<int> times;
225  getMoves(index, moves, times);
226  return moves;
227  }
228 
229  void KisenPlusFile::getMoves(size_t index,
230  vector<Move>& moves, vector<int>& times)
231  {
232  assert(index<size());
233  // std::cerr << "Game[" << index << "]" << std::endl;
234  ifs.seekg(index*2048,std::ios::beg);
235  CArray<unsigned char, 2048> cbuf;
236  ifs.read(reinterpret_cast<char *>(&cbuf[0]),2048);
237  NumEffectState state;
238  for (size_t i = 0;
239  i < 2048 && cbuf[i]!=0 && cbuf[i+1]!=0;
240  i += 8)
241  {
242  int c0 = cbuf[i];
243  int c1 = cbuf[i + 1];
244  bool is_promote = false;
245  Move move;
246 
247  if (c0 > 100)
248  {
249  is_promote = true;
250  c0 = 256 - c0;
251  }
252 
253  Square to(c0 % 10, c0 / 10);
254 
255  if (c1 < 10)
256  {
257  // drop
258  move = Move(to,
259  PieceStand::order[c1 - 1],
260  state.turn());
261  }
262  else
263  {
264  Square from(c1 % 10, c1 / 10);
265  Ptype type = state.pieceAt(from).ptype();
266  if (is_promote)
267  type = promote(type);
268  move = Move(from, to,
269  type, state.pieceAt(to).ptype(),
270  is_promote, state.turn());
271  }
272  moves.push_back(move);
273  times.push_back(cbuf[i + 7] * 60 + cbuf[i + 6]);
274  state.makeMove(move);
275  assert(state.isConsistent( true ) );
276  }
277  }
278 #endif
279 } // namespace record
280 } // namespace osl
281 
284 {
285 }
286 #ifndef MINIMAL
289 {
290 }
291 
292 void osl::record::
293 OKisenStream::save(const SimpleState& src, const vector<Move> &moves)
294 {
295  if (!(src == SimpleState(HIRATE)))
296  {
297  std::cerr << "Can not save non-HIRATE record" << std::endl;
298  return;
299  }
300  NumEffectState state;
301  const int max_length = std::min(256, static_cast<int>(moves.size()));
302  for (int i = 0; i < max_length; ++i)
303  {
304  const Move move = moves[i];
305  if (!move.isDrop())
306  {
307  int from = KisenUtils::convertSquare(move.from());
308  int to = KisenUtils::convertSquare(move.to());
309  if (move.isPromotion())
310  {
311  to += 100;
312  }
313  os << static_cast<char>(to) << static_cast<char>(from);
314  }
315  else
316  {
317  int to = KisenUtils::convertSquare(move.to());
318  int count = 1;
319  BOOST_FOREACH(Ptype ptype, PieceStand::order)
320  {
321  if (ptype == move.ptype())
322  {
323  break;
324  }
325  count += state.countPiecesOnStand(move.player(), ptype);
326  }
327  count += 100;
328  os << static_cast<char>(to) << static_cast<char>(count);
329  }
330  state.makeMove(moves[i]);
331  }
332  for (int i = max_length; i < 256; ++i)
333  {
334  os << '\0' << '\0';
335  }
336 }
337 
338 void osl::record::
340 {
341  vector<Move> moves;
342  vector<int> time;
343  record->getMoves(moves, time);
344  SimpleState state = record->getInitialState();
345  save(state, moves);
346 }
347 
348 void osl::record::
349 KisenIpxWriter::writeString(const std::string &name, size_t length)
350 {
351  for (size_t i = 0; i < length; ++i)
352  {
353  if (i < name.length())
354  {
355  os << name[i];
356  }
357  else
358  {
359  os << '\0';
360  }
361  }
362 }
363 
364 void osl::record::
366 {
367  int high = rating / 256;
368  int low = rating % 256;
369  os << static_cast<char>(low) << static_cast<char>(high);
370 }
371 
372 void osl::record::
373 KisenIpxWriter::writeStartDate(int year, int month, int day, int hour, int min)
374 {
375  const int high_year = year / 256;
376  const int low_year = year % 256;
377  os << static_cast<char>(low_year)
378  << static_cast<char>(high_year)
379  << static_cast<char>(month)
380  << static_cast<char>(day)
381  << static_cast<char>(hour)
382  << static_cast<char>(min);
383 }
384 
385 void osl::record::
387  int black_rating, int white_rating,
388  const std::string &black_title,
389  const std::string &white_title)
390 {
391  // total 256 bytes
392  // Player name: 14 bytes each
393 #ifndef _WIN32
394  writeString(IconvConvert::convert("EUC-JP", "SJIS", record.getPlayer(BLACK)), 14);
395  writeString(IconvConvert::convert("EUC-JP", "SJIS", record.getPlayer(WHITE)), 14);
396  writeString(IconvConvert::convert("EUC-JP", "SJIS", black_title), 8);
397  writeString(IconvConvert::convert("EUC-JP", "SJIS", white_title), 8);
398 #else
399  writeString("", 14);
400  writeString("", 14);
401  writeString("", 8);
402  writeString("", 8);
403 #endif
404  for (int i = 44; i < 84; ++i)
405  {
406  os << '\0';
407  }
408  const boost::gregorian::date start_date = record.getDate();
409  if (!start_date.is_special()) {
410  // time is fixed with 9am
411  writeStartDate(start_date.year(), start_date.month(), start_date.day(), 9, 0);
412  } else {
413  for (int i = 84; i < 90; ++i)
414  {
415  os << '\0';
416  }
417  }
418  for (int i = 90; i < 118; ++i)
419  {
420  os << '\0';
421  }
422  vector<Move> moves;
423  vector<int> time;
424  record.getMoves(moves, time);
425  // TODO: sennichite, jishogi
426  if (moves.size() <= 256)
427  {
428  if (moves.size() % 2 == 0)
429  os << static_cast<char>(KisenIpxFile::WHITE_WIN);
430  else
431  os << static_cast<char>(KisenIpxFile::BLACK_WIN);
432  }
433  else
434  {
435  if (moves.size() % 2 == 0)
436  os << static_cast<char>(KisenIpxFile::WHITE_WIN_256);
437  else
438  os << static_cast<char>(KisenIpxFile::BLACK_WIN_256);
439  }
440  for (int i = 119; i < 212; ++i)
441  {
442  os << '\0';
443  }
444  writeRating(black_rating);
445  writeRating(white_rating);
446  for (int i = 216; i < 256; ++i)
447  {
448  os << '\0';
449  }
450 }
451 #endif
452 // ;;; Local Variables:
453 // ;;; mode:c++
454 // ;;; c-basic-offset:2
455 // ;;; End: