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