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