00001 #include "osl/record/ki2.h"
00002 #include "osl/record/kanjiCode.h"
00003 #include "osl/record/kanjiPrint.h"
00004 #include "osl/record/ki2IOError.h"
00005 #include "osl/misc/sjis2euc.h"
00006 #include "osl/ptypeTable.h"
00007 #include <boost/foreach.hpp>
00008 #include <boost/algorithm/string/trim.hpp>
00009 #include <fstream>
00010 #include <iostream>
00011
00012 namespace osl
00013 {
00014 namespace record
00015 {
00016 namespace
00017 {
00018 enum ParseResult
00019 {
00020 OK = 0,
00021 KOMAOCHI,
00022 ILLEGAL,
00023 };
00024
00025 ParseResult ki2ParseLine(RecordVisitor& rv,
00026 std::string line,
00027 const osl::record::KanjiMove& kmove)
00028 {
00029 boost::algorithm::trim(line);
00030
00031 if (line.empty() || line.at(0) == '*')
00032 return OK;
00033 else if (line.size() > 10 && line.substr(0,10) == (K_KAISHI K_NICHIJI K_COLON))
00034 {
00035 Record *record = rv.getRecord();
00036 std::string date_str(line.substr(10));
00038 const static std::string spaces[] = {" ", K_SPACE};
00039 BOOST_FOREACH(const std::string& space, spaces) {
00040 const std::string::size_type pos_space = date_str.find(space);
00041 if (pos_space != std::string::npos)
00042 date_str = date_str.substr(0, pos_space);
00043 }
00044 record->setDate(date_str);
00045
00046
00047 return OK;
00048 }
00049 else if (line.size() > 6 && line.substr(0,6) == (K_BLACK K_COLON))
00050 {
00051 Record *record = rv.getRecord();
00052 const std::string player_name(line.substr(6));
00053 record->setPlayer(osl::BLACK, player_name);
00054 return OK;
00055 }
00056 else if (line.size() > 6 && line.substr(0,6) == (K_WHITE K_COLON))
00057 {
00058 Record *record = rv.getRecord();
00059 const std::string player_name(line.substr(6));
00060 record->setPlayer(osl::WHITE, player_name);
00061 return OK;
00062 }
00063 else if (line.size() > 6 && line.substr(0,6) == (K_KISEN K_COLON))
00064 {
00065 Record *record = rv.getRecord();
00066 record->setTounamentName(line.substr(6));
00067 return OK;
00068 }
00069 else if (line.size() > 8 && line.substr(0,8) == (K_TEAIWARI K_COLON))
00070 return KOMAOCHI;
00071 else if (line.substr(0,2) != K_BLACK_SIGN && line.substr(0,2) != K_WHITE_SIGN)
00072 return OK;
00073
00074 std::string move_str;
00075 for (size_t i = 0; ; )
00076 {
00077 if (i < line.size() &&
00078 (line.at(i) == ' ' || line.at(i) == '\t'))
00079 {
00080 ++i;
00081 continue;
00082 }
00083
00084 if ( (line.substr(i,2) == K_BLACK_SIGN ||
00085 line.substr(i,2) == K_WHITE_SIGN ||
00086 i+1 >= line.size())
00087 && !move_str.empty())
00088 {
00089
00090 Move last_move;
00091 if (rv.getLastMove())
00092 last_move = rv.getLastMove()->getMove();
00093 const NumEffectState state(*rv.getState());
00094 const Move move = kmove.strToMove(move_str, state, last_move);
00095 if (!move.isValid())
00096 return ILLEGAL;
00097 rv.addMoveAndAdvance(move);
00098 move_str.clear();
00099 }
00100 if (i+1 >= line.size())
00101 return OK;
00102 move_str.append(line.substr(i,2));
00103 i += 2;
00104 }
00105 }
00106
00107 }
00108 }
00109 }
00110
00111
00112 osl::record::ki2::
00113 InputStream::InputStream(std::istream& is, bool verbose)
00114 : is(is), state(SimpleState(HIRATE))
00115 {
00116 if (! is)
00117 {
00118 std::cerr << "InputStream::InputStream cannot read \n";
00119 abort();
00120 }
00121 kmove.setVerbose(verbose);
00122 }
00123
00124 osl::record::ki2::
00125 InputStream::~InputStream(){}
00126
00127 void osl::record::ki2::
00128 InputStream::load(Record* rec)
00129 {
00130 rv.setState(&state);
00131 rv.setRecord(rec);
00132 std::string line;
00133 while (std::getline(is, line))
00134 {
00135 line = misc::sjis2euc(line);
00136 const ParseResult result = ki2ParseLine(rv, line, kmove);
00137 switch (result)
00138 {
00139 case OK:
00140 continue;
00141 case KOMAOCHI:
00142 {
00143 const std::string msg = "ERROR: Komaochi (handicapped game) records are not available: ";
00144 std::cerr << msg << "\n";
00145 throw Ki2IOError(msg);
00146 }
00147 case ILLEGAL:
00148 {
00149 const std::string msg = "ERROR: An illegal move found in a record.";
00150 throw Ki2IOError(msg);
00151 }
00152 default:
00153 assert(false);
00154 }
00155 }
00156 }
00157
00158 osl::record::ki2::
00159 Ki2File::Ki2File(const std::string& fileName, bool verbose)
00160 : verbose(verbose)
00161 {
00162 std::ifstream ifs(fileName.c_str());
00163 if (! ifs)
00164 {
00165 const std::string msg = "Ki2File::Ki2File file cannot read ";
00166 std::cerr << msg << fileName << "\n";
00167 throw Ki2IOError(msg + fileName);
00168 }
00169 InputStream irs(ifs, verbose);
00170 irs.load(&rec);
00171 }
00172
00173 const osl::record::Record& osl::record::ki2::
00174 Ki2File::getRecord() const
00175 {
00176 return rec;
00177 }
00178
00179 const osl::NumEffectState osl::record::ki2::
00180 Ki2File::getInitialState() const
00181 {
00182 return rec.getInitialState();
00183 }
00184
00185 const std::string osl::record::ki2::show(Square position)
00186 {
00187 if (position.isPieceStand())
00188 return "";
00189 const int x = position.x(), y = position.y();
00190 return StandardCharacters::suji[x] + StandardCharacters::dan[y];
00191 }
00192
00193 const std::string osl::record::ki2::show(Ptype ptype)
00194 {
00195 switch (ptype)
00196 {
00197 case PSILVER: case PKNIGHT: case PLANCE:
00198 return K_NARU + StandardCharacters().kanji(unpromote(ptype));
00199 default:
00200 ;
00201 }
00202 return StandardCharacters().kanji(ptype);
00203 }
00204
00205 const std::string osl::record::ki2::showPromote(bool promote)
00206 {
00207 return promote ? K_NARU : K_FUNARI;
00208 }
00209
00210 const std::string osl::record::ki2::show(Square cur, Square prev)
00211 {
00212 if (cur == prev)
00213 return K_ONAZI;
00214 return show(cur);
00215 }
00216
00217 const std::string osl::record::ki2::show(Move m, const NumEffectState& state,
00218 Move prev)
00219 {
00220 std::string ret = (m.player() == BLACK) ? K_BLACK_SIGN : K_WHITE_SIGN;
00221 if (m.isPass()) {
00222 ret += K_PASS;
00223 return ret;
00224 }
00225 const Square from = m.from(), to = m.to();
00226 const Ptype ptype = m.oldPtype();
00227 const Player player = m.player();
00228 mask_t pieces = state.allEffectAt(player, ptype, to);
00229 const mask_t promoted = state.promotedPieces().getMask(Ptype_Table.getIndex(ptype));
00230 if (isPromoted(ptype))
00231 pieces &= promoted;
00232 else
00233 pieces &= ~promoted;
00234 if (from.isPieceStand()) {
00235 ret += show(to) + show(ptype);
00236 int has_effect = 0;
00237 while (pieces.any()) {
00238 const Piece p = state.pieceOf(pieces.takeOneBit());
00239 if (p.ptype() == ptype)
00240 ++has_effect;
00241 }
00242 if (has_effect)
00243 ret += K_UTSU;
00244 return ret;
00245 }
00246 ret += prev.isNormal() && (to == prev.to())
00247 ? K_ONAZI : show(to);
00248 ret += show(m.oldPtype());
00249 const int count = pieces.countBit();
00250 if (count >= 2) {
00251 CArray<int,3> x_count = {{ 0 }}, y_count = {{ 0 }};
00252 int my_x = 0, my_y = 0;
00253 while (pieces.any()) {
00254 const int n = pieces.takeOneBit() + Ptype_Table.getIndex(ptype)*32;
00255 const Piece p = state.pieceOf(n);
00256 if (p.ptype() != ptype)
00257 continue;
00258 int index_x = 1, index_y = 1;
00259 if (p.square().x() != to.x())
00260 index_x = ((p.square().x() - to.x()) * playerToMul(player) > 0)
00261 ? 2 : 0;
00262 if (p.square().y() != to.y())
00263 index_y = ((p.square().y() - to.y()) * playerToMul(player) > 0)
00264 ? 2 : 0;
00265 if (p.square() == from)
00266 my_x = index_x, my_y = index_y;
00267 x_count[index_x]++;
00268 y_count[index_y]++;
00269 }
00270 if (y_count[my_y] == 1) {
00271 if (from.y() == to.y())
00272 ret += K_YORU;
00273 else if ((to.y() - from.y())*playerToMul(player) > 0)
00274 ret += K_HIKU;
00275 else
00276 ret += K_UE;
00277 }
00278 else if (x_count[my_x] == 1) {
00279 if (from.x() == to.x()) {
00280 if (isPromoted(ptype) && isMajor(ptype)) {
00281 const Piece l = state.pieceAt
00282 (Square(from.x() - playerToMul(player), from.y()));
00283 if (l.isOnBoardByOwner(player) && l.ptype() == ptype)
00284 ret += K_HIDARI;
00285 else
00286 ret += K_MIGI;
00287 }
00288 else
00289 ret += K_SUGU;
00290 }
00291 else if ((to.x() - from.x())*playerToMul(player) > 0)
00292 ret += K_MIGI;
00293 else
00294 ret += K_HIDARI;
00295 }
00296 else if (from.x() == to.x()) {
00297 if ((to.y() - from.y())*playerToMul(player) > 0)
00298 ret += K_HIKU;
00299 else
00300 ret += K_SUGU;
00301 }
00302 else {
00303 if ((to.x() - from.x())*playerToMul(player) > 0)
00304 ret += K_MIGI;
00305 else
00306 ret += K_HIDARI;
00307 if ((to.y() - from.y())*playerToMul(player) > 0)
00308 ret += K_HIKU;
00309 else
00310 ret += K_UE;
00311 }
00312 }
00313 if (canPromote(m.oldPtype()))
00314 if (m.isPromotion()
00315 || to.canPromote(player) || from.canPromote(player)) {
00316 ret += showPromote(m.isPromotion());
00317 }
00318 return ret;
00319 }
00320
00321 const std::string osl::record::
00322 ki2::show(const Move *first, const Move *last,
00323 const char *threatmate_first, const char *threatmate_last,
00324 const NumEffectState& initial, Move prev)
00325 {
00326 if (first == last || first->isInvalid())
00327 return "";
00328 NumEffectState state(initial);
00329 std::string ret = show(*first, state, prev);
00330 if (threatmate_first != threatmate_last
00331 && *threatmate_first++)
00332 ret += "(" K_TSUMERO ")";
00333 for (; first+1 != last; ++first) {
00334 if (first->isInvalid())
00335 break;
00336 state.makeMove(*first);
00337 ret += show(*(first+1), state, *first);
00338 if (threatmate_first != threatmate_last
00339 && *threatmate_first++)
00340 ret += "(" K_TSUMERO ")";
00341 }
00342 return ret;
00343 }
00344
00345 const std::string osl::record::
00346 ki2::show(const Move *first, const Move *last, const NumEffectState& initial, Move prev)
00347 {
00348 vector<char> threatmate(last-first, false);
00349 return show(first, last, &*threatmate.begin(), &*threatmate.end(), initial, prev);
00350 }
00351
00352
00353
00354
00355