kisen.cc
Go to the documentation of this file.
00001 #include "osl/record/kisen.h"
00002 #include "osl/record/csaIOError.h"
00003 #include "osl/pieceStand.h"
00004 #include "osl/misc/filePath.h"
00005 #include "osl/misc/iconvConvert.h"
00006 #include "osl/misc/sjis2euc.h"
00007 #include <boost/filesystem/convenience.hpp>
00008 #include <boost/foreach.hpp>
00009 #include <iostream>
00010 
00011 namespace osl
00012 {
00013 namespace record
00014 {
00015   Square KisenUtils::convertSquare( int pos ){
00016     assert(1<=pos && pos<=0x51);
00017     int y=((pos-1)/9)+1, x=((pos-1)%9)+1;
00018     return Square(x,y);
00019   }
00020   int KisenUtils::convertSquare(Square pos)
00021   {
00022     return ((pos.y() - 1) * 9 + 1) + pos.x() - 1;
00023   }
00024 
00025   Move KisenUtils::convertMove(SimpleState const& state,int c0,int c1){
00026     Move move;
00027 
00028     if(1<=c1 && c1<=0x51){
00029       Square from=convertSquare(c1),to;
00030       Piece fromPiece=state.pieceOnBoard(from);
00031       if (! fromPiece.isPiece()) 
00032         throw CsaIOError("Square error");
00033       assert(fromPiece.isPiece());
00034       assert(fromPiece.owner()==state.turn() ||
00035              (std::cerr << c1 << "," << from << "," << fromPiece << std::endl,0)
00036              );
00037       bool isPromote=false;
00038       if(1<=c0 && c0<=0x51){
00039         to=convertSquare(c0);
00040       }
00041       else if(0x65<=c0 && c0<=0xb5){
00042         to=convertSquare(c0-0x64);
00043         isPromote=true;
00044       }
00045       else{
00046         throw CsaIOError("c0 range error");
00047       }
00048       Piece toPiece=state.pieceAt(to);
00049       if (! toPiece.isEmpty() && toPiece.owner()!=alt(state.turn()))
00050         throw CsaIOError("inconsintent move (to)");
00051       Ptype ptype=fromPiece.ptype();
00052       if(isPromote)ptype=promote(ptype);
00053       const Ptype captured = toPiece.ptype();
00054       if (captured == KING)
00055         return Move::INVALID();
00056       move=Move(from,to,ptype,captured,isPromote,state.turn());
00057     }
00058     else{
00059       assert(0x65<=c1);
00060       assert(1<=c0&&c0<=0x51);
00061       Square to=convertSquare(c0);
00062       Ptype ptype=PTYPE_EMPTY;
00063       int piece_on_stand = c1;
00064       const Ptype ptypes[]={ROOK,BISHOP,GOLD,SILVER,KNIGHT,LANCE,PAWN};
00065       for(size_t i=0;i<sizeof(ptypes)/sizeof(Ptype);i++){
00066         int count=state.countPiecesOnStand(state.turn(),ptypes[i]);
00067         if(count>0){
00068           if(piece_on_stand>0x64){
00069             piece_on_stand-=count;
00070             if(piece_on_stand<=0x64) ptype=ptypes[i];
00071           }
00072         }
00073       }
00074       assert(ptype!=PTYPE_EMPTY ||
00075              (std::cerr << state << to << " " << c1
00076               << " " << piece_on_stand << std::endl, false));
00077       move=Move(to,ptype,state.turn());
00078     }
00079     if (! state.isValidMove(move,true)) {
00080       std::cerr << "warning: bad move in kisen\n" << state << move << "\n";
00081       return Move();
00082     }
00083     assert(state.isValidMove(move,true) ||
00084            (std::cerr << state << move << std::endl, false));
00085     return move;
00086   }
00087 
00088 
00089   KisenFile::KisenFile(const std::string& fileName) 
00090     :ifs(fileName.c_str()),initialState(HIRATE), fileName(fileName) 
00091   {
00092     if (! ifs)
00093       throw CsaIOError("KisenFile not found");
00094     ifs.seekg(0,std::ios::end);
00095     assert((ifs.tellg() % 512)==0);
00096     numberOfGames=ifs.tellg()/512;
00097   }
00098 
00099   const vector<Move> KisenFile::getMoves(size_t index)
00100   {
00101     assert(index<size());
00102     vector<Move> moves;
00103     //    std::cerr << "Game[" << index << "]" << std::endl;
00104     ifs.seekg(index*512,std::ios::beg);
00105     CArray<unsigned char, 512> cbuf;
00106     ifs.read(reinterpret_cast<char *>(&cbuf[0]),512);
00107     NumEffectState state;
00108     //
00109     Player turn=BLACK;
00110     for(size_t turnCount=0; 
00111         (turnCount*2 < cbuf.size())
00112           && cbuf[turnCount*2]!=0 && cbuf[turnCount*2+1]!=0;
00113         turnCount++, turn=alt(turn)){
00114       if(turnCount==KisenFile::maxMoves || cbuf[  turnCount *2 ] == 0 || cbuf[ turnCount * 2 + 1 ] == 0 ){ break; }
00115       int c0=cbuf[turnCount*2], c1=cbuf[turnCount*2+1];
00116       if (moves.empty() && c0 == 0xff && c1 == 0xff) // komaochi
00117         break;
00118       const Move move=KisenUtils::convertMove(state,c0,c1);
00119       if (move.isInvalid())
00120         break;
00121       moves.push_back(move);
00122       state.makeMove(move);
00123       assert(state.isConsistent( true ) );
00124     }
00125     return moves;
00126   }
00127 #ifndef MINIMAL
00128   const std::string KisenFile::ipxFileName(const std::string& filename) 
00129   {
00130     namespace bf = boost::filesystem;
00131     const bf::path ipxfilename = bf::change_extension(bf::path(filename), ".ipx");
00132     return misc::file_string(ipxfilename);
00133   }
00134 
00135   KisenIpxFile::KisenIpxFile(const std::string& fileName) 
00136     :ifs(fileName.c_str()), file_name(fileName) 
00137   {
00138     if (! ifs)
00139       throw CsaIOError("KisenIpxFile not found");
00140     ifs.seekg(0,std::ios::end);
00141     assert((ifs.tellg() % 256)==0);
00142     numberOfGames=ifs.tellg()/256;
00143   }
00144   const std::string KisenIpxFile::getPlayer(size_t index,Player pl)
00145   {
00146     assert(index<size());
00147     vector<Move> moves;
00148     ifs.seekg(index*256,std::ios::beg);
00149     CArray<unsigned char, 256> cbuf;
00150     ifs.read(reinterpret_cast<char *>(&cbuf[0]),256);
00151     int startIndex=0;
00152     if(pl==WHITE)startIndex=14;
00153     CArray<char,15> buf;
00154     buf[14]='\0';
00155     strncpy(&buf[0],reinterpret_cast<char *>(&cbuf[startIndex]),14);
00156     return misc::sjis2euc(std::string(&buf[0]));
00157   }
00158   unsigned int KisenIpxFile::getRating(size_t index,Player pl)
00159   {
00160     assert(index<size());
00161     vector<Move> moves;
00162     ifs.seekg(index*256,std::ios::beg);
00163     CArray<unsigned char, 256> cbuf;
00164     ifs.read(reinterpret_cast<char *>(&cbuf[0]),256);
00165     int startIndex=0324;
00166     if(pl==WHITE)startIndex=0326;
00167     return cbuf[startIndex]+256*cbuf[startIndex+1];
00168   }
00169   unsigned int KisenIpxFile::getResult(size_t index)
00170   {
00171     assert(index<size());
00172     ifs.seekg(index*256,std::ios::beg);
00173     CArray<unsigned char, 256> cbuf;
00174     ifs.read(reinterpret_cast<char *>(&cbuf[0]),256);
00175     return cbuf[64+48+6];
00176   }
00177   const std::string KisenIpxFile::getTitle(size_t index,Player pl)
00178   {
00179     assert(index<size());
00180     vector<Move> moves;
00181     ifs.seekg(index*256,std::ios::beg);
00182     CArray<unsigned char, 256> cbuf;
00183     ifs.read(reinterpret_cast<char *>(&cbuf[0]),256);
00184     int startIndex=28;
00185     if(pl==WHITE)startIndex+=8;
00186     CArray<char,9> buf;
00187     buf[8]='\0';
00188     strncpy(&buf[0],reinterpret_cast<const char*>(&cbuf[startIndex]),8);
00189     return misc::sjis2euc(std::string(&buf[0]));
00190   }
00191   boost::gregorian::date KisenIpxFile::getStartDate(size_t index)
00192   {
00193     assert(index<size());
00194     ifs.seekg(index*256,std::ios::beg);
00195     CArray<unsigned char, 256> cbuf;
00196     ifs.read(reinterpret_cast<char *>(&cbuf[0]),256);
00197     const int startIndex=84;
00198     const unsigned int year  = cbuf[startIndex] + 256*cbuf[startIndex+1];
00199     const unsigned int month = cbuf[startIndex+2];
00200     const unsigned int day   = cbuf[startIndex+3];
00201     try {
00202       const boost::gregorian::date d = boost::gregorian::date(year, month, day);
00203       return d;
00204     } catch (std::out_of_range& e) {
00205       std::cerr << e.what() << ": ["
00206         << index << "] " << year << "-" << month << "-" << day << "\n"; 
00207       return boost::gregorian::date(boost::gregorian::not_a_date_time); 
00208     }
00209   }
00210 
00211   KisenPlusFile::KisenPlusFile(const std::string& fileName) 
00212     :ifs(fileName.c_str()),initialState(HIRATE) 
00213   {
00214     if (! ifs)
00215       throw CsaIOError("KisenPlusFile not found");
00216     ifs.seekg(0,std::ios::end);
00217     assert((ifs.tellg() % 2048)==0);
00218     numberOfGames=ifs.tellg()/2048;
00219   }
00220 
00221   const vector<Move> KisenPlusFile::getMoves(size_t index)
00222   {
00223     vector<Move> moves;
00224     vector<int> times;
00225     getMoves(index, moves, times);
00226     return moves;
00227   }
00228 
00229   void KisenPlusFile::getMoves(size_t index,
00230                                vector<Move>& moves, vector<int>& times)
00231   {
00232     assert(index<size());
00233     //    std::cerr << "Game[" << index << "]" << std::endl;
00234     ifs.seekg(index*2048,std::ios::beg);
00235     CArray<unsigned char, 2048> cbuf;
00236     ifs.read(reinterpret_cast<char *>(&cbuf[0]),2048);
00237     NumEffectState state;
00238     for (size_t i = 0; 
00239          i < 2048 && cbuf[i]!=0 && cbuf[i+1]!=0;
00240          i += 8)
00241     {
00242       int c0 = cbuf[i];
00243       int c1 = cbuf[i + 1];
00244       bool is_promote = false;
00245       Move move;
00246 
00247       if (c0 > 100)
00248       {
00249         is_promote = true;
00250         c0 = 256 - c0;
00251       }
00252 
00253       Square to(c0 % 10, c0 / 10);
00254 
00255       if (c1 < 10)
00256       {
00257         // drop
00258         move = Move(to,
00259                     PieceStand::order[c1 - 1],
00260                     state.turn());
00261       }
00262       else
00263       {
00264         Square from(c1 % 10, c1 / 10);
00265         Ptype type = state.pieceAt(from).ptype();
00266         if (is_promote)
00267           type = promote(type);
00268         move = Move(from, to,
00269                     type, state.pieceAt(to).ptype(),
00270                     is_promote, state.turn());
00271       }
00272       moves.push_back(move);
00273       times.push_back(cbuf[i + 7] * 60 + cbuf[i + 6]);
00274       state.makeMove(move);
00275       assert(state.isConsistent( true ) );
00276     }
00277   }
00278 #endif
00279 } // namespace record
00280 } // namespace osl
00281 
00282 osl::record::
00283 KisenFile::~KisenFile()
00284 {
00285 }
00286 #ifndef MINIMAL
00287 osl::record::
00288 KisenIpxFile::~KisenIpxFile()
00289 {
00290 }
00291 
00292 void osl::record::
00293 OKisenStream::save(const SimpleState& src, const vector<Move> &moves)
00294 {
00295   if (!(src == SimpleState(HIRATE)))
00296   {
00297     std::cerr << "Can not save non-HIRATE record" << std::endl;
00298     return;
00299   }
00300   NumEffectState state;
00301   const int max_length = std::min(256, static_cast<int>(moves.size()));
00302   for (int i = 0; i < max_length; ++i)
00303   {
00304     const Move move = moves[i];
00305     if (!move.isDrop())
00306     {
00307       int from = KisenUtils::convertSquare(move.from());
00308       int to = KisenUtils::convertSquare(move.to());
00309       if (move.isPromotion())
00310       {
00311         to += 100;
00312       }
00313       os << static_cast<char>(to) << static_cast<char>(from);
00314     }
00315     else
00316     {
00317       int to = KisenUtils::convertSquare(move.to());
00318       int count = 1;
00319       BOOST_FOREACH(Ptype ptype, PieceStand::order)
00320       {
00321         if (ptype == move.ptype())
00322         {
00323           break;
00324         }
00325         count += state.countPiecesOnStand(move.player(), ptype);
00326       }
00327       count += 100;
00328       os << static_cast<char>(to) << static_cast<char>(count);
00329     }
00330     state.makeMove(moves[i]);
00331   }
00332   for (int i = max_length; i < 256; ++i)
00333   {
00334     os << '\0' << '\0';
00335   }
00336 }
00337 
00338 void osl::record::
00339 OKisenStream::save(Record *record)
00340 {
00341   vector<Move> moves;
00342   vector<int> time;
00343   record->getMoves(moves, time);
00344   SimpleState state = record->getInitialState();
00345   save(state, moves);
00346 }
00347 
00348 void osl::record::
00349 KisenIpxWriter::writeString(const std::string &name, size_t length)
00350 {
00351   for (size_t i = 0; i < length; ++i)
00352   {
00353     if (i < name.length())
00354     {
00355       os << name[i];
00356     }
00357     else
00358     {
00359       os << '\0';
00360     }
00361   }
00362 }
00363 
00364 void osl::record::
00365 KisenIpxWriter::writeRating(int rating)
00366 {
00367   int high = rating / 256;
00368   int low = rating % 256;
00369   os << static_cast<char>(low) << static_cast<char>(high);
00370 }
00371 
00372 void osl::record::
00373 KisenIpxWriter::writeStartDate(int year, int month, int day, int hour, int min)
00374 {
00375   const int high_year = year / 256;
00376   const int low_year  = year % 256;
00377   os << static_cast<char>(low_year)
00378      << static_cast<char>(high_year)
00379      << static_cast<char>(month)
00380      << static_cast<char>(day)
00381      << static_cast<char>(hour)
00382      << static_cast<char>(min);
00383 }
00384 
00385 void osl::record::
00386 KisenIpxWriter::save(const Record &record,
00387                      int black_rating, int white_rating,
00388                      const std::string &black_title,
00389                      const std::string &white_title)
00390 {
00391   // total 256 bytes
00392   // Player name: 14 bytes each
00393 #ifndef _WIN32
00394   writeString(IconvConvert::convert("EUC-JP", "SJIS", record.getPlayer(BLACK)), 14);
00395   writeString(IconvConvert::convert("EUC-JP", "SJIS", record.getPlayer(WHITE)), 14);
00396   writeString(IconvConvert::convert("EUC-JP", "SJIS", black_title), 8);
00397   writeString(IconvConvert::convert("EUC-JP", "SJIS", white_title), 8);
00398 #else
00399   writeString("", 14);
00400   writeString("", 14);
00401   writeString("", 8);
00402   writeString("", 8);
00403 #endif
00404   for (int i = 44; i < 84; ++i)
00405   {
00406     os << '\0';
00407   }
00408   const boost::gregorian::date start_date = record.getDate();
00409   if (!start_date.is_special()) {
00410     // time is fixed with 9am
00411     writeStartDate(start_date.year(), start_date.month(), start_date.day(), 9, 0);
00412   } else {
00413     for (int i = 84; i < 90; ++i)
00414     {
00415       os << '\0';
00416     }
00417   }
00418   for (int i = 90; i < 118; ++i)
00419   {
00420     os << '\0';
00421   }
00422   vector<Move> moves;
00423   vector<int> time;
00424   record.getMoves(moves, time);
00425   // TODO: sennichite, jishogi
00426   if (moves.size() <= 256)
00427   {
00428     if (moves.size() % 2 == 0)
00429       os << static_cast<char>(KisenIpxFile::WHITE_WIN);
00430     else
00431       os << static_cast<char>(KisenIpxFile::BLACK_WIN);
00432   }
00433   else
00434   {
00435     if (moves.size() % 2 == 0)
00436       os << static_cast<char>(KisenIpxFile::WHITE_WIN_256);
00437     else
00438       os << static_cast<char>(KisenIpxFile::BLACK_WIN_256);
00439   }
00440   for (int i = 119; i < 212; ++i)
00441   {
00442     os << '\0';
00443   }
00444   writeRating(black_rating);
00445   writeRating(white_rating);
00446   for (int i = 216; i < 256; ++i)
00447   {
00448     os << '\0';
00449   }
00450 }
00451 #endif
00452 // ;;; Local Variables:
00453 // ;;; mode:c++
00454 // ;;; c-basic-offset:2
00455 // ;;; End:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines