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