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>& board_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 {
00074 MoveRecord *mr = rv->getLastMove();
00075 if (mr)
00076 mr->addComment(s.substr(3));
00077 }
00078 else if (s.substr(1,2) == "**" && parse_move_comment)
00079 {
00080 MoveRecord *mr = rv->getLastMove();
00081 if (mr)
00082 mr->info = makeInfo(*state, s.substr(3), mr->getMove());
00083 }
00084 return;
00085 case '$':
00086 if (s.find("$START_TIME:") == 0) {
00087 const std::string YYMMDD = s.substr(12,10);
00088 rec->setDate(YYMMDD);
00089 return;
00090 }
00091 rec->addInitialComment(s.substr(1));
00092 return;
00093 case 'V':
00094 rec->setVersion(s.substr(1));
00095 return;
00096 case 'N':
00097 switch(s.at(1)){
00098 case '+':
00099 case '-':
00100 rec->setPlayer(csa::charToPlayer(s.at(1)),s.substr(2));
00101 break;
00102 default:
00103 std::cerr << "Illegal csa line " << s << std::endl;
00104 throw CsaIOError("illegal csa line "+s);
00105 }
00106 break;
00107 case 'P':
00108 switch(s.at(1)){
00109 case 'I':
00110 board_parsed.fill(true);
00111 state->init(HIRATE);
00112 break;
00113 case '+':
00114 case '-':{
00115 Player pl=csa::charToPlayer(s.at(1));
00116 for(int i=2;i<=(int)s.length()-4;i+=4){
00117 Square pos=csa::strToPos(s.substr(i,2));
00118 if(s.substr(i+2,2) == "AL"){
00119 state->setPieceAll(pl);
00120 }
00121 else{
00122 Ptype ptype=csa::strToPtype(s.substr(i+2,2));
00123 state->setPiece(pl,pos,ptype);
00124 }
00125 }
00126 break;
00127 }
00128 default:
00129 if(isdigit(s.at(1))){
00130 const int y=s.at(1)-'0';
00131 board_parsed[y-1] = true;
00132 for(unsigned int x=9,i=2;i<s.length();i+=3,x--){
00133 if (s.at(i) != '+' && s.at(i) != '-' && s.find(" *",i)!=i) {
00134 if (OslConfig::inUnitTest())
00135 throw CsaIOError("parse board error " + s);
00136 else
00137 std::cerr << "possible typo for empty square " << s << "\n";
00138 }
00139 if (s.at(i) != '+' && s.at(i) != '-') continue;
00140 Player pl=csa::charToPlayer(s.at(i));
00141 Square pos(x,y);
00142 Ptype ptype=csa::strToPtype(s.substr(i+1,2));
00143 state->setPiece(pl,pos,ptype);
00144 }
00145 }
00146 }
00147 break;
00148 case '+':
00149 case '-':{
00150 Player pl=csa::charToPlayer(s.at(0));
00151 if(s.length()==1){
00152 state->setTurn(pl);
00153 rec->setInitialState(*state);
00154 state->initPawnMask();
00155 }
00156 else{
00157 const Move m = csa::strToMove(s,*state);
00158 if (! state->isValidMove(m))
00159 {
00160 std::cerr << "Illegal move " << m << std::endl;
00161 throw CsaIOError("illegal move "+s);
00162 }
00163 rv->addMoveAndAdvance(m);
00164 return;
00165 }
00166 break;
00167 }
00168 case 'T':
00169 {
00170 MoveRecord *mr = rv->getLastMove();
00171 if (mr)
00172 mr->setTime(atoi(s.c_str()+1));
00173 return;
00174 }
00175 case '%':
00176 if (s.find("%TORYO") == 0 || s.find("%ILLEGAL_MOVE") == 0)
00177 rec->setResult((state->turn() == BLACK)
00178 ? Record::WHITE_WIN : Record::BLACK_WIN);
00179 else if (s.find("%SENNICHITE") == 0)
00180 rec->setResult(Record::SENNNICHITE);
00181 else if (s.find("%KACHI") == 0)
00182 rec->setResult((state->turn() == BLACK)
00183 ? Record::BLACK_WIN : Record::WHITE_WIN);
00184 else if (s.find("%JISHOGI") == 0 || s.find("%HIKIWAKE") == 0)
00185 rec->setResult(Record::JISHOGI);
00186 else if (s.find("%+ILLEGAL_ACTION") == 0)
00187 rec->setResult(Record::WHITE_WIN);
00188 else if (s.find("%-ILLEGAL_ACTION") == 0)
00189 rec->setResult(Record::BLACK_WIN);
00190 return;
00191 default:
00192 throw CsaIOError("unknown character in csaParseLine "+s);
00193 }
00194 }
00195 }
00196 }
00197 }
00198
00199 osl::record::csa::
00200 InputStream::InputStream(std::istream& is)
00201 : is(is),
00202 rv(boost::shared_ptr<record::RecordVisitor>(new record::RecordVisitor()))
00203 {
00204 if (! is)
00205 {
00206 std::cerr << "InputStream::InputStream cannot read \n";
00207 abort();
00208 }
00209 }
00210
00211 osl::record::csa::
00212 InputStream::InputStream(std::istream& is, boost::shared_ptr<record::RecordVisitor> rv)
00213 : is(is), rv(rv)
00214 {
00215 if (! is)
00216 {
00217 std::cerr << "InputStream::InputStream cannot read \n";
00218 abort();
00219 }
00220 }
00221
00222 osl::record::csa::
00223 InputStream::~InputStream(){}
00224
00225 void osl::record::csa::
00226 InputStream::load(Record* rec)
00227 {
00228
00229 state.init();
00230 rv->setState(&state);
00231 rv->setRecord(rec);
00232 std::string line;
00233 CArray<bool, 9> board_parsed = {{ false }};
00234 while (std::getline(is, line))
00235 {
00236
00237 if ((! line.empty())
00238 && (line[line.size()-1] == 13))
00239 line.erase(line.size()-1);
00240
00241 std::vector<std::string> elements;
00242 boost::algorithm::split(elements, line, boost::algorithm::is_any_of(","));
00243 BOOST_FOREACH(std::string e, elements) {
00244 boost::algorithm::trim(e);
00245 boost::algorithm::trim_left(e);
00246 csaParseLine(rv, e, board_parsed, !OslConfig::inUnitTest());
00247 }
00248 }
00249 if (*std::min_element(board_parsed.begin(), board_parsed.end()) == false)
00250 throw CsaIOError("incomplete position description in csaParseLine");
00251 assert(state.isConsistent());
00252 }
00253
00254 osl::record::csa::
00255 CsaFile::CsaFile(const std::string& fileName)
00256 {
00257 std::ifstream ifs(fileName.c_str());
00258 if (! ifs)
00259 {
00260 const std::string msg = "CsaFile::CsaFile file cannot read ";
00261 std::cerr << msg << fileName << "\n";
00262 throw CsaIOError(msg + fileName);
00263 }
00264 InputStream irs(ifs);
00265 irs.load(&rec);
00266 }
00267
00268 osl::record::csa::
00269 CsaFile::~CsaFile()
00270 {
00271 }
00272
00273 const osl::record::Record& osl::record::csa::
00274 CsaFile::getRecord() const
00275 {
00276 return rec;
00277 }
00278
00279 const osl::NumEffectState osl::record::csa::
00280 CsaFile::getInitialState() const
00281 {
00282 return NumEffectState(rec.getInitialState());
00283 }
00284
00285
00286
00287
00288
00289