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