csaRecord.cc
Go to the documentation of this file.
00001 #include "osl/record/csaRecord.h"
00002 #include "osl/record/csaIOError.h"
00003 #include "osl/state/simpleState.h"
00004 #include "osl/oslConfig.h"
00005 #include <iostream>
00006 #include <fstream>
00007 #include <stdexcept>
00008 #include <cassert>
00009 #include <string>
00010 #include <sstream>
00011 
00012 /* ------------------------------------------------------------------------- */
00013 
00014 namespace osl
00015 {
00016   namespace record
00017   {
00018     namespace
00019     {
00020       const SearchInfo makeInfo(const SimpleState& initial,
00021                                 const std::string& line,
00022                                 Move last_move)
00023       {
00024         std::istringstream is(line);
00025         SearchInfo info;
00026         is >> info.value;
00027 
00028         NumEffectState state(initial);
00029         std::string s;
00030         while (is >> s)
00031         {
00032           if (s == csa::show(last_move)) // effective only if s is the first move in a comment
00033             continue;
00034           last_move = Move::INVALID();
00035           try
00036           {
00037             const Move move = ((s == "%PASS" || /* gekisashi */ s == "<PASS>")
00038                                ? Move::PASS(state.turn())
00039                                : csa::strToMove(s, state));
00040             if (move.isPass() || (move.isNormal() && state.isValidMove(move,false)))
00041             {
00042               info.moves.push_back(move);
00043               state.makeMove(move);
00044               continue;
00045             }
00046           }
00047           catch(CsaIOError& e)
00048           {
00049             // fall through
00050           }
00051           std::cerr << "drop illegal move in comment " << s << std::endl;
00052           break;
00053         }
00054         return info;
00055       }
00056       void csaParseLine(boost::shared_ptr<RecordVisitor>& rv, std::string s,
00057                         CArray<bool,9>& line_parsed,
00058                         bool parse_move_comment=true)
00059       {
00060         Record *rec=rv->getRecord();
00061         SimpleState* state=rv->getState();
00062         while (! s.empty() && isspace(s[s.size()-1])) // ignore trailing garbage
00063           s.resize(s.size()-1);
00064         if (s.length()==0) 
00065           return;
00066         switch(s.at(0)){
00067         case '\'': /* コメント行 */
00068           if (s.substr(1,2) == "* ")
00069             rv->getLastMove()->addComment(s.substr(3));
00070           else if (s.substr(1,2) == "**" && parse_move_comment) 
00071           {
00072             MoveRecord *mr = rv->getLastMove();
00073             rv->getLastMove()->info = makeInfo(*state, s.substr(3), mr ? mr->getMove() : Move::INVALID());
00074           }
00075           return;
00076         case '$': /* コメント行 */
00077           if (s.find("$START_TIME:") == 0) {
00078             const std::string YYMMDD = s.substr(12,10);
00079             rec->setDate(YYMMDD);
00080             return;
00081           }
00082           rec->addInitialComment(s.substr(1));
00083           return;
00084         case 'V': /* バージョン番号 */
00085           rec->setVersion(s.substr(1));
00086           return;
00087         case 'N': /* 対局者名 */
00088           switch(s.at(1)){
00089           case '+':
00090           case '-':
00091             rec->setPlayer(csa::charToPlayer(s.at(1)),s.substr(2));
00092             break;
00093           default:
00094             std::cerr << "Illegal csa line " << s << std::endl;
00095             throw CsaIOError("illegal csa line "+s);
00096           }
00097           break;
00098         case 'P': /* 開始盤面 */
00099           switch(s.at(1)){
00100           case 'I': /* 平手初期配置 */
00101             line_parsed.fill(true);
00102             state->init(HIRATE);
00103             break;
00104           case '+': /* 先手の駒 */
00105           case '-':{ /* 後手の駒 */
00106             Player pl=csa::charToPlayer(s.at(1));
00107             for(int i=2;i<=(int)s.length()-4;i+=4){
00108               Square pos=csa::strToPos(s.substr(i,2));
00109               if(s.substr(i+2,2) == "AL"){
00110                 state->setPieceAll(pl);
00111               }
00112               else{
00113                 Ptype ptype=csa::strToPtype(s.substr(i+2,2));
00114                 state->setPiece(pl,pos,ptype);
00115               }
00116             }
00117             break;
00118           }
00119           default:
00120             if(isdigit(s.at(1))){
00121               const int y=s.at(1)-'0';
00122               line_parsed[y-1] = true;
00123               for(unsigned int x=9,i=2;i<s.length();i+=3,x--){
00124                 if(s.at(i)==' ') continue;
00125                 Player pl=csa::charToPlayer(s.at(i));
00126                 Square pos(x,y);
00127                 Ptype ptype=csa::strToPtype(s.substr(i+1,2));
00128                 state->setPiece(pl,pos,ptype);
00129               }
00130             }
00131           }
00132           break;
00133         case '+':
00134         case '-':{
00135           Player pl=csa::charToPlayer(s.at(0));
00136           if(s.length()==1){
00137             state->setTurn(pl);
00138             rec->setInitialState(*state);
00139             state->initPawnMask();
00140           }
00141           else{ // actual moves
00142             const Move m = csa::strToMove(s,*state);
00143             if (! state->isValidMove(m))
00144             {
00145               std::cerr << "Illegal move " << m << std::endl;
00146               throw CsaIOError("illegal move "+s);
00147             }
00148             rv->addMoveAndAdvance(m);
00149             return;
00150           }
00151           break;
00152         }
00153         case 'T':
00154           (rv->getLastMove())->setTime(atoi(s.c_str()+1));
00155           return;
00156         case '%':
00157           if (s.find("%TORYO") == 0 || s.find("%ILLEGAL_MOVE") == 0)
00158             rec->setResult((state->turn() == BLACK) 
00159                            ? Record::WHITE_WIN : Record::BLACK_WIN);
00160           else if (s.find("%SENNICHITE") == 0)
00161             rec->setResult(Record::SENNNICHITE);
00162           else if (s.find("%KACHI") == 0)
00163             rec->setResult((state->turn() == BLACK) 
00164                            ? Record::BLACK_WIN : Record::WHITE_WIN);
00165           else if (s.find("%JISHOGI") == 0 || s.find("%HIKIWAKE") == 0)
00166             rec->setResult(Record::JISHOGI);
00167           else if (s.find("%+ILLEGAL_ACTION") == 0)
00168             rec->setResult(Record::WHITE_WIN);
00169           else if (s.find("%-ILLEGAL_ACTION") == 0)
00170             rec->setResult(Record::BLACK_WIN);
00171           return;
00172         default:
00173           throw CsaIOError("unknown character in csaParseLine "+s);
00174         }
00175       }
00176     } // anonymous namespace
00177   } // namespace record
00178 } // namespace osl
00179 
00180 osl::record::csa::
00181 InputStream::InputStream(std::istream& is) 
00182   : is(is), 
00183     rv(boost::shared_ptr<record::RecordVisitor>(new record::RecordVisitor()))
00184 {
00185   if (! is)
00186   {
00187     std::cerr << "InputStream::InputStream cannot read \n";
00188     abort();
00189   }
00190 }
00191   
00192 osl::record::csa::
00193 InputStream::InputStream(std::istream& is, boost::shared_ptr<record::RecordVisitor> rv) 
00194   : is(is), rv(rv)
00195 {
00196   if (! is)
00197   {
00198     std::cerr << "InputStream::InputStream cannot read \n";
00199     abort();
00200   }
00201 }
00202   
00203 osl::record::csa::
00204 InputStream::~InputStream(){}
00205   
00206 void osl::record::csa::
00207 InputStream::load(Record* rec)
00208 {
00209   //  rec->init();
00210   state.init();
00211   rv->setState(&state);
00212   rv->setRecord(rec);
00213   std::string line;
00214   CArray<bool, 9> line_parsed = {{ false }};
00215   while (std::getline(is, line)) 
00216   {
00217     // quick hack for \r
00218     if ((! line.empty())
00219         && (line[line.size()-1] == 13))
00220       line.erase(line.size()-1);
00221     csaParseLine(rv, line, line_parsed, !OslConfig::inUnitTest());
00222   }
00223   if (*std::min_element(line_parsed.begin(), line_parsed.end()) == false)
00224     throw CsaIOError("incomplete position description in csaParseLine");
00225   assert(state.isConsistent());
00226 }
00227 
00228 osl::record::csa::
00229 CsaFile::CsaFile(const std::string& fileName)
00230 {
00231   std::ifstream ifs(fileName.c_str());
00232   if (! ifs)
00233   {
00234     const std::string msg = "CsaFile::CsaFile file cannot read ";
00235     std::cerr << msg << fileName << "\n";
00236     throw CsaIOError(msg + fileName);
00237   }
00238   InputStream irs(ifs);
00239   irs.load(&rec);
00240 }
00241 
00242 osl::record::csa::
00243 CsaFile::~CsaFile()
00244 {
00245 }
00246 
00247 const osl::record::Record& osl::record::csa::
00248 CsaFile::getRecord() const
00249 {
00250   return rec;
00251 }
00252 
00253 const osl::NumEffectState osl::record::csa::
00254 CsaFile::getInitialState() const
00255 {
00256   return NumEffectState(rec.getInitialState());
00257 }
00258 
00259 /* ------------------------------------------------------------------------- */
00260 // ;;; Local Variables:
00261 // ;;; mode:c++
00262 // ;;; c-basic-offset:2
00263 // ;;; End:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines