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