kakinoki.cc
Go to the documentation of this file.
00001 /* kakinoki.cc
00002  */
00003 #include "osl/record/kakinoki.h"
00004 #include "osl/record/kanjiMove.h"
00005 #include "osl/record/kanjiCode.h"
00006 #include "osl/misc/sjis2euc.h"
00007 #include "osl/state/simpleState.h"
00008 #include <iostream>
00009 #include <fstream>
00010 #include <stdexcept>
00011 #include <cassert>
00012 #include <string>
00013 #include <sstream>
00014 
00015 namespace osl
00016 {
00017   namespace record
00018   {
00019     void kakinokiParseLine(boost::shared_ptr<RecordVisitor>& rv,
00020                            std::string s)
00021     {
00022       Record *record=rv->getRecord();
00023       SimpleState* state=rv->getState();
00024       if (s[0] == '*') 
00025       {
00026         MoveRecord *mr = rv->getLastMove();
00027         if (mr)
00028           mr->addComment(s.substr(1));
00029         return;
00030       }
00031       if (s.size() > 6)
00032       {
00033         if (equal(K_BLACK.begin(), K_BLACK.end(), s.begin())) {
00034           record->setPlayer(BLACK, s.substr(6));
00035           return;
00036         }
00037         if (equal(K_WHITE.begin(), K_WHITE.end(), s.begin())) {
00038           record->setPlayer(WHITE, s.substr(6));
00039           return;
00040         }
00041         if (s.substr(0,6) == (K_KISEN+K_COLON))
00042         {
00043           record->setTounamentName(s.substr(6));
00044           return;
00045         }
00046       }
00047       if (s[0] != ' ') 
00048       {
00049         if (rv->getLastMove() == 0)
00050           record->addInitialComment(s);
00051         return;                 // otherwise ignore
00052       }
00053       if (s.find(K_TORYO) != s.npos)
00054       {
00055         record->setResult((state->turn() == BLACK)
00056                           ? Record::WHITE_WIN : Record::BLACK_WIN);
00057         return;
00058       }
00059 
00060       {
00061         // replace '(' and ')' with white space if exists
00062         size_t p = s.find('(');
00063         if (p != s.npos)
00064           s.replace(p, 1, 1, ' ');
00065         p = s.find(')');
00066         if (p != s.npos)
00067           s.replace(p, 1, 1, ' ');
00068       }      
00069       Move last_move;
00070       if (rv->getLastMove())
00071         last_move = rv->getLastMove()->getMove();
00072       const Move m = kakinoki::strToMove(s, *state, last_move);
00073       if (m.isNormal()) {
00074         if (! state->isValidMove(m)) {
00075           std::ostringstream ss;
00076           ss << *state << s << "\n" << m;
00077           std::cerr << ss.str();
00078           throw KakinokiIOError(ss.str());
00079         }       
00080         rv->addMoveAndAdvance(m);
00081       }
00082     }
00083   }
00084 }
00085 
00086 osl::Move osl::record::
00087 kakinoki::strToMove(const std::string& s, const SimpleState& state, Move last_move)
00088 {
00089   static KanjiMove Kanji_Move;
00090   std::istringstream is(s);
00091   int move_number, from_number;
00092   std::string move_string;
00093   is >> move_number >> move_string;
00094 
00095   Square to, from;
00096   if (move_string.substr(0,2) == K_ONAZI)
00097     to = last_move.to();
00098   else
00099     to = Kanji_Move.toSquare(move_string.substr(0,4));
00100   if (to == Square())           // resign?
00101     return Move();
00102   
00103   Ptype ptype;
00104   size_t cur = 4;
00105   if (move_string.substr(cur,2) == K_NARU) // PLANCE, PKIGHT, PSILVER
00106   {
00107     assert(move_string.size() >= cur+4);
00108     ptype = Kanji_Move.toPtype(move_string.substr(cur,4));
00109     cur += 4;
00110   }
00111   else
00112   {
00113     ptype = Kanji_Move.toPtype(move_string.substr(cur,2));
00114     cur += 2;
00115   }
00116   if (move_string.size() >= cur+2 && move_string.substr(cur,2)
00117       == K_UTSU)
00118     from = Square();
00119   else 
00120   {
00121     if (! (is >> from_number))
00122       throw KakinokiIOError("error in move from");
00123     from = Square(from_number / 10, from_number % 10);
00124   }
00125   
00126   bool is_promote = false;
00127   if (move_string.size() >= cur+2 && move_string.substr(cur,2) == K_NARU)
00128     is_promote = true;
00129 
00130   if (from.isPieceStand())
00131     return Move(to, ptype, state.turn());
00132   Ptype captured = state.pieceOnBoard(to).ptype();
00133   return Move(from, to, is_promote ? promote(ptype) : ptype,
00134               captured, is_promote, state.turn());
00135 }
00136 
00137 osl::record::kakinoki::
00138 InputStream::InputStream(std::istream& is) 
00139   : is(is), 
00140     rv(boost::shared_ptr<record::RecordVisitor>(new record::RecordVisitor()))
00141 {
00142   if (! is)
00143   {
00144     std::cerr << "InputStream::InputStream cannot read \n";
00145     abort();
00146   }
00147 }
00148   
00149 osl::record::kakinoki::
00150 InputStream::InputStream(std::istream& is, boost::shared_ptr<record::RecordVisitor> rv) 
00151   : is(is), rv(rv)
00152 {
00153   if (! is)
00154   {
00155     std::cerr << "InputStream::InputStream cannot read \n";
00156     throw KakinokiIOError("file open failed");
00157   }
00158 }
00159   
00160 osl::record::kakinoki::
00161 InputStream::~InputStream(){}
00162   
00163 void osl::record::kakinoki::
00164 InputStream::load(Record* rec)
00165 {
00166   //  rec->init();
00167   state.init(HIRATE);
00168   rv->setState(&state);
00169   rv->setRecord(rec);
00170   std::string line;
00171   while (std::getline(is, line)) 
00172   {
00173     // quick hack for \r
00174     if ((! line.empty())
00175         && (line[line.size()-1] == 13))
00176       line.erase(line.size()-1);
00177     if (line.length()==0) 
00178       continue;
00179     // to euc
00180     line = misc::sjis2euc(line);
00181     // skip variations
00182     if (line.find(K_HENKA) == 0)
00183       break;
00184     if (! line.empty() && line[0] == '#' 
00185         && line.find("separator") != line.npos)
00186       break;                    // tanase shogi
00187     
00188     kakinokiParseLine(rv, line);
00189   }
00190   assert(state.isConsistent());
00191 }
00192 
00193 osl::record::kakinoki::
00194 KakinokiFile::KakinokiFile(const std::string& filename)
00195 {
00196   std::ifstream ifs(filename.c_str());
00197   if (! ifs)
00198   {
00199     const std::string msg = "KakinokiFile::KakinokiFile file cannot read ";
00200     std::cerr << msg << filename << "\n";
00201     throw KakinokiIOError(msg + filename);
00202   }
00203   InputStream irs(ifs);
00204   irs.load(&rec);
00205 }
00206 
00207 osl::record::kakinoki::
00208 KakinokiFile::~KakinokiFile()
00209 {
00210 }
00211 
00212 const osl::record::Record& osl::record::kakinoki::
00213 KakinokiFile::getRecord() const
00214 {
00215   return rec;
00216 }
00217 
00218 const osl::NumEffectState osl::record::kakinoki::
00219 KakinokiFile::getInitialState() const
00220 {
00221   return NumEffectState(rec.getInitialState());
00222 }
00223 
00224 bool osl::record::kakinoki::
00225 KakinokiFile::isKakinokiFile(const std::string& filename)
00226 {
00227   std::ifstream is(filename.c_str());
00228   std::string line;
00229   if (! is || ! getline(is, line)) 
00230     return false;
00231   line = misc::sjis2euc(line);
00232   return line.find("Kifu for Windows") != line.npos
00233     || line.find("KIFU") != line.npos
00234     || line.find(K_SENKEI) == 0
00235     || (line.find("#") == 0 && line.find(K_KIFU) != line.npos);
00236 }
00237 
00238 // ;;; Local Variables:
00239 // ;;; mode:c++
00240 // ;;; c-basic-offset:2
00241 // ;;; End:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines