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