ki2.cc
Go to the documentation of this file.
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 // anonymous
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)); // this may or may not include HH:MM
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           // an invalid date_str results in an invalid boost::gregorian::date value
00046           // you can check it date.is_special()
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             // apply move_str
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         } // for
00105       }
00106 
00107     } // anonymous namespace
00108   } //namespace record
00109 } // namespace osl
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 // ;;; Local Variables:
00353 // ;;; mode:c++
00354 // ;;; c-basic-offset:2
00355 // ;;; End:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines