Index   Main   Namespaces   Classes   Hierarchy   Annotated   Files   Compound   Global   Pages  

SgProp.cpp

Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 /** @file SgProp.cpp
00003     See SgProp.h.
00004 
00005     Implementation details:
00006 
00007     A property list is simply kept as a list.
00008     Any special characteristics of the
00009     property list are enforced when adding new items to the list.
00010 */
00011 //----------------------------------------------------------------------------
00012 
00013 #include "SgSystem.h"
00014 #include "SgProp.h"
00015 
00016 #include <iomanip>
00017 #include <sstream>
00018 #include "SgRect.h"
00019 #include "SgUtil.h"
00020 #include "SgVector.h"
00021 
00022 using namespace std;
00023 using SgPointUtil::InBoardRange;
00024 using SgPropUtil::PointToSgfString;
00025 using SgPropUtil::SgfStringToPoint;
00026 using SgPropUtil::EscapeSpecialCharacters;
00027 using SgUtil::InRange;
00028 
00029 //----------------------------------------------------------------------------
00030 
00031 SgPropPointFmt SgPropUtil::GetPointFmt(int gameNumber)
00032 {
00033     switch (gameNumber)
00034     {
00035     case 2: // Othello
00036     case 11: // Hex
00037         return SG_PROPPOINTFMT_HEX;
00038     default:
00039         return SG_PROPPOINTFMT_GO;
00040     }
00041 }
00042 
00043 string SgPropUtil::PointToSgfString(SgMove p, int boardSize,
00044                                     SgPropPointFmt fmt, int fileFormat)
00045 {
00046     SG_ASSERT(boardSize >= SG_MIN_SIZE && boardSize <= SG_MAX_SIZE);
00047     SG_ASSERT(p != SG_NULLMOVE);
00048     ostringstream out;
00049     switch (fmt)
00050     {
00051     case SG_PROPPOINTFMT_GO:
00052         {
00053             if (p == SG_PASS)
00054             {
00055                 if (fileFormat < 4)
00056                     out << "tt";
00057                 // Pass is empty string in FF[4]
00058             }
00059             else
00060             {
00061                 int col = SgPointUtil::Col(p);
00062                 int row = boardSize - SgPointUtil::Row(p) + 1;
00063                 SG_ASSERT(row > 0);
00064                 out << static_cast<char>('a' + col - 1)
00065                     << static_cast<char>('a' + row - 1);
00066             }
00067         }
00068         break;
00069     case SG_PROPPOINTFMT_HEX:
00070         {
00071             SG_ASSERT(p != SG_PASS);
00072             int col = SgPointUtil::Col(p);
00073             int row = boardSize - SgPointUtil::Row(p) + 1;
00074             out << static_cast<char>('a' + col - 1) << row;
00075         }
00076         break;
00077     default:
00078         SG_ASSERT(false);
00079     }
00080     return out.str();
00081 }
00082 
00083 string SgPropUtil::EscapeSpecialCharacters(const string& s, bool escapeColon)
00084 {
00085     ostringstream buffer;
00086     for (size_t i = 0; i < s.size(); ++i)
00087     {
00088         char c = s[i];
00089         if (c == ']' || c =='\\' || (c == ':' && escapeColon))
00090             buffer << '\\' << c;
00091         else if (c == '\r' || c == '\t')
00092             buffer << ' ';
00093         else
00094             buffer << c;
00095     }
00096     return buffer.str();
00097 }
00098 
00099 SgMove SgPropUtil::SgfStringToPoint(const string& s, int boardSize,
00100                                     SgPropPointFmt fmt)
00101 {
00102     SG_ASSERT(boardSize >= SG_MIN_SIZE && boardSize <= SG_MAX_SIZE);
00103     SgPoint p = SG_NULLMOVE;
00104     switch (fmt)
00105     {
00106     case SG_PROPPOINTFMT_GO:
00107         {
00108             if (s.size() == 2
00109                 && 'a' <= s[0] && s[0] <= 's'
00110                 && 'a' <= s[1] && s[1] <= 's')
00111             {
00112                 int col = s[0] - 'a' + 1;
00113                 int row = s[1] - 'a' + 1;
00114                 p = SgPointUtil::Pt(col, boardSize - row + 1);
00115             }
00116             else if (s.empty() // new FF[4] definition
00117                      || (s.size() == 2 && s[0] == 't' && s[1] == 't'))
00118                 p = SG_PASS;
00119         }
00120         break;
00121     case SG_PROPPOINTFMT_HEX:
00122         {
00123             if (s.size() >= 2 && s.size() <= 3)
00124             {
00125                 int col = s[0] - 'a' + 1;
00126                 int row = s[1] - '1' + 1;
00127                 if (s.size() == 3)
00128                     row = row * 10 + (s[2] - '1' + 1);
00129                 if (InRange(col, 1, boardSize) && InRange(row, 1, boardSize))
00130                     p = SgPointUtil::Pt(col, boardSize - row + 1);
00131             }
00132         }
00133         break;
00134     default:
00135         SG_ASSERT(false);
00136     }
00137     return p;
00138 }
00139 
00140 //----------------------------------------------------------------------------
00141 
00142 SgPropList::SgPropList()
00143     : m_list()
00144 { }
00145 
00146 SgPropList::~SgPropList()
00147 {
00148     Clear();
00149 }
00150 
00151 void SgPropList::Clear()
00152 {
00153     for (SgVectorIteratorOf<SgProp> iter(m_list); iter; ++iter)
00154         delete *iter;
00155     m_list.Clear();
00156 }
00157 
00158 SgProp* SgPropList::Get(SgPropID id) const
00159 {
00160     for (SgVectorIteratorOf<SgProp> iter(m_list); iter; ++iter)
00161     {
00162         SgProp* prop = *iter;
00163         if (prop->MatchesID(id))
00164             return prop;
00165     }
00166     return 0;
00167 }
00168 
00169 void SgPropList::Add(const SgProp* prop)
00170 {
00171     SG_ASSERT(prop);
00172 
00173     // First remove any property of that type, then add new property.
00174     // Enforce constraint that there can be only one move annotation per node.
00175     // Can have multiple unknown properties per node.
00176     if (prop->ID() != SG_PROP_UNKNOWN)
00177     {
00178         if (prop->Flag(SG_PROPCLASS_ANNO_MOVE))
00179             Remove(SG_PROP_MOVE_ANNO, prop);
00180         else if (prop->Flag(SG_PROPCLASS_ANNO_POS))
00181             Remove(SG_PROP_POS_ANNO, prop);
00182         else if (prop->Flag(SG_PROPCLASS_MOVE))
00183             Remove(SG_PROP_MOVE, prop);
00184         else
00185             Remove(prop->ID(), prop);
00186     }
00187     m_list.Include(prop);
00188 }
00189 
00190 void SgPropList::MoveToFront(SgPropID id)
00191 {
00192     SgProp* prop = Get(id);
00193     if (prop && m_list.Exclude(prop))
00194         m_list.PushFront(prop);
00195 }
00196 
00197 bool SgPropList::Remove(const SgProp* prop)
00198 {
00199     if (prop)
00200         delete prop;
00201     return m_list.Exclude(const_cast<SgProp*>(prop));
00202 }
00203 
00204 void SgPropList::Remove(SgPropID id, const SgProp* protectProp)
00205 {
00206     SgVectorOf<SgProp> toBeDeleted;
00207     for (SgVectorIteratorOf<SgProp> iter(m_list); iter; ++iter)
00208     {
00209         SgProp* prop = *iter;
00210         if (prop != protectProp && prop->MatchesID(id))
00211         {
00212             // Can't exclude while iterating over same list.
00213             toBeDeleted.PushBack(prop);
00214             delete prop;
00215         }
00216     }
00217     m_list.Exclude(toBeDeleted);
00218 }
00219 
00220 bool SgPropList::AppendMoveAnnotation(string* s) const
00221 {
00222     SgProp* moveAnnoProp = Get(SG_PROP_MOVE_ANNO);
00223     if (! moveAnnoProp)
00224         return false;
00225     SgPropInt* intProp = dynamic_cast<SgPropInt*>(moveAnnoProp);
00226     int value = intProp ? intProp->Value() : 1;
00227     SgPropID id = moveAnnoProp->ID();
00228     if (id == SG_PROP_GOOD_MOVE)
00229         *s += (value == 2) ? "!!" : "!";
00230     else if (id == SG_PROP_BAD_MOVE)
00231         *s += (value == 2) ? "??" : "?";
00232     else if (id == SG_PROP_INTERESTING)
00233         *s += "!?";
00234     else if (id == SG_PROP_DOUBTFUL)
00235         *s += "?!";
00236     return true;
00237 }
00238 
00239 SgProp* SgPropList::GetPropContainingText(const string& findText) const
00240 {
00241     for (SgVectorIteratorOf<SgProp> iter(m_list); iter; ++iter)
00242     {
00243         SgProp* prop = *iter;
00244         if (prop->ContainsText(findText))
00245             return prop;
00246     }
00247     return 0;
00248 }
00249 
00250 //----------------------------------------------------------------------------
00251 
00252 //--- general
00253 SgPropID SG_PROP_NONE = 0;
00254 SgPropID SG_PROP_UNKNOWN = 0;
00255 
00256 //--- moves
00257 SgPropID SG_PROP_MOVE = 0;
00258 SgPropID SG_PROP_MOVE_BLACK = 0;
00259 SgPropID SG_PROP_MOVE_WHITE = 0;
00260 
00261 //--- board edits
00262 SgPropID SG_PROP_ADD_BLACK = 0;
00263 SgPropID SG_PROP_ADD_WHITE = 0;
00264 SgPropID SG_PROP_ADD_EMPTY = 0;
00265 SgPropID SG_PROP_PLAYER = 0;
00266 
00267 //--- value and territory
00268 SgPropID SG_PROP_VALUE = 0;
00269 SgPropID SG_PROP_TERR_BLACK = 0;
00270 SgPropID SG_PROP_TERR_WHITE = 0;
00271 
00272 //--- marks drawn on the board
00273 SgPropID SG_PROP_MARKS = 0;
00274 SgPropID SG_PROP_SELECT = 0;
00275 SgPropID SG_PROP_MARKED = 0;
00276 SgPropID SG_PROP_TRIANGLE = 0;
00277 SgPropID SG_PROP_SQUARE = 0;
00278 SgPropID SG_PROP_DIAMOND = 0;
00279 SgPropID SG_PROP_CIRCLE = 0;
00280 SgPropID SG_PROP_DIMMED = 0;
00281 SgPropID SG_PROP_LABEL = 0;
00282 
00283 //--- time control
00284 SgPropID SG_PROP_TIMES = 0;
00285 SgPropID SG_PROP_TIME_BLACK = 0;
00286 SgPropID SG_PROP_TIME_WHITE = 0;
00287 SgPropID SG_PROP_OT_NU_MOVES = 0;
00288 SgPropID SG_PROP_OT_PERIOD = 0;
00289 SgPropID SG_PROP_OT_BLACK = 0;
00290 SgPropID SG_PROP_OT_WHITE = 0;
00291 SgPropID SG_PROP_LOSE_TIME = 0;
00292 SgPropID SG_PROP_OVERHEAD = 0;
00293 
00294 //--- statistics
00295 SgPropID SG_PROP_COUNT = 0;
00296 SgPropID SG_PROP_TIME_USED = 0;
00297 SgPropID SG_PROP_NUM_NODES = 0;
00298 SgPropID SG_PROP_NUM_LEAFS = 0;
00299 SgPropID SG_PROP_MAX_DEPTH = 0;
00300 SgPropID SG_PROP_DEPTH = 0;
00301 SgPropID SG_PROP_PART_DEPTH = 0;
00302 SgPropID SG_PROP_EVAL = 0;
00303 SgPropID SG_PROP_EXPECTED = 0;
00304 
00305 //--- root props
00306 SgPropID SG_PROP_FORMAT = 0;
00307 SgPropID SG_PROP_SIZE = 0;
00308 SgPropID SG_PROP_GAME = 0;
00309 SgPropID SG_PROP_SPEC_BLACK = 0;
00310 SgPropID SG_PROP_SPEC_WHITE = 0;
00311 SgPropID SG_PROP_CHINESE = 0;
00312 SgPropID SG_PROP_APPLIC = 0;
00313 
00314 //--- annotations
00315 SgPropID SG_PROP_ANNOTATE = 0;
00316 SgPropID SG_PROP_COMMENT = 0;
00317 SgPropID SG_PROP_NAME = 0;
00318 SgPropID SG_PROP_CHECK = 0;
00319 SgPropID SG_PROP_SIGMA = 0;
00320 SgPropID SG_PROP_HOTSPOT = 0;
00321 SgPropID SG_PROP_FIGURE = 0;
00322 
00323 //--- position annotations
00324 SgPropID SG_PROP_POS_ANNO = 0;
00325 SgPropID SG_PROP_GOOD_BLACK = 0;
00326 SgPropID SG_PROP_GOOD_WHITE = 0;
00327 SgPropID SG_PROP_EVEN_POS = 0;
00328 SgPropID SG_PROP_UNCLEAR = 0;
00329 
00330 //--- move annotations
00331 SgPropID SG_PROP_MOVE_ANNO = 0;
00332 SgPropID SG_PROP_GOOD_MOVE = 0;
00333 SgPropID SG_PROP_BAD_MOVE = 0;
00334 SgPropID SG_PROP_INTERESTING = 0;
00335 SgPropID SG_PROP_DOUBTFUL = 0;
00336 
00337 //--- game info
00338 SgPropID SG_PROP_INFO = 0;
00339 SgPropID SG_PROP_GAME_NAME = 0;
00340 SgPropID SG_PROP_GAME_COMMENT = 0;
00341 SgPropID SG_PROP_EVENT = 0;
00342 SgPropID SG_PROP_ROUND = 0;
00343 SgPropID SG_PROP_DATE = 0;
00344 SgPropID SG_PROP_PLACE = 0;
00345 SgPropID SG_PROP_PLAYER_BLACK = 0;
00346 SgPropID SG_PROP_PLAYER_WHITE = 0;
00347 SgPropID SG_PROP_RESULT = 0;
00348 SgPropID SG_PROP_USER = 0;
00349 SgPropID SG_PROP_TIME = 0;
00350 SgPropID SG_PROP_SOURCE = 0;
00351 SgPropID SG_PROP_COPYRIGHT = 0;
00352 SgPropID SG_PROP_ANALYSIS = 0;
00353 SgPropID SG_PROP_RANK_BLACK = 0;
00354 SgPropID SG_PROP_RANK_WHITE = 0;
00355 SgPropID SG_PROP_TEAM_BLACK = 0;
00356 SgPropID SG_PROP_TEAM_WHITE = 0;
00357 SgPropID SG_PROP_OPENING = 0;
00358 SgPropID SG_PROP_RULES = 0;
00359 SgPropID SG_PROP_HANDICAP = 0;
00360 SgPropID SG_PROP_KOMI = 0;
00361 
00362 //--- abstract properties
00363 SgPropID SG_PROP_FIND_MOVE = 0;
00364 SgPropID SG_PROP_FIND_TEXT = 0;
00365 SgPropID SG_PROP_BRANCH = 0;
00366 SgPropID SG_PROP_TERMINAL = 0;
00367 
00368 //--- Smart Go specific properties
00369 SgPropID SG_PROP_MOTIVE = 0;
00370 SgPropID SG_PROP_SEQUENCE = 0;
00371 SgPropID SG_PROP_NOT_EMPTY = 0;
00372 SgPropID SG_PROP_NOT_BLACK = 0;
00373 SgPropID SG_PROP_NOT_WHITE = 0;
00374 
00375 //----------------------------------------------------------------------------
00376 
00377 bool SgProp::s_initialized = false;
00378 
00379 int SgProp::s_numPropClasses = 0;
00380 
00381 SgPropFlags SgProp::s_flags[SG_MAX_PROPCLASS];
00382 
00383 string SgProp::s_label[SG_MAX_PROPCLASS];
00384 
00385 SgProp* SgProp::s_prop[SG_MAX_PROPCLASS];
00386 
00387 SgProp::~SgProp()
00388 {
00389 }
00390 
00391 void SgProp::ChangeToOpponent()
00392 {
00393     m_id = OpponentProp(m_id);
00394 }
00395 
00396 bool SgProp::ContainsText(const std::string& findText)
00397 {
00398     SG_UNUSED(findText);
00399     return false;
00400 }
00401 
00402 SgPropFlags SgProp::Flags() const
00403 {
00404     return s_flags[m_id];
00405 }
00406 
00407 bool SgProp::Initialized()
00408 {
00409     return s_initialized;
00410 }
00411 
00412 string SgProp::Label() const
00413 {
00414     return s_label[m_id];
00415 }
00416 
00417 SgPropID SgProp::Register(SgProp* prop, const char* label, SgPropFlags flags)
00418 {
00419     ++s_numPropClasses;
00420     SG_ASSERT(s_numPropClasses < SG_MAX_PROPCLASS);
00421     if (s_numPropClasses < SG_MAX_PROPCLASS)
00422     {
00423         s_flags[s_numPropClasses] = flags;
00424         s_label[s_numPropClasses] = label;
00425         s_prop[s_numPropClasses] = prop;
00426         if (prop)
00427         {
00428             SG_ASSERT(prop->m_id == 0); // can't know the ID yet
00429         }
00430         // Black and white properties must be created in pairs, black first.
00431         if (flags & SG_PROPCLASS_WHITE)
00432             SG_ASSERT(s_flags[s_numPropClasses-1] & SG_PROPCLASS_BLACK);
00433 
00434         return s_numPropClasses;
00435     }
00436     else
00437         return 0;
00438 }
00439 
00440 SgProp* SgProp::CreateProperty(SgPropID id)
00441 {
00442     SG_ASSERT(id <= s_numPropClasses);
00443     SG_ASSERT(s_prop[id]);
00444 
00445     // Create a property of the right class, and set its ID (because
00446     // prototype that's duplicated contains a zero ID).
00447     SgProp* prop = s_prop[id]->Duplicate();
00448     prop->m_id = id;
00449     return prop;
00450 }
00451 
00452 SgPropID SgProp::GetIDOfLabel(const string& label)
00453 {
00454     for (int i = 1; i <= s_numPropClasses; ++i)
00455         if (s_label[i] == label)
00456             return i;
00457     return SG_PROP_NONE;
00458 }
00459 
00460 SgPropID SgProp::OpponentProp(SgPropID id)
00461 {
00462     // Relies on the fact that these properties are always created in pairs,
00463     // with black created before white.
00464     // AR: ---> Flags cannot really be overridden
00465     SgPropFlags flags = s_flags[id];
00466 
00467     if (flags & SG_PROPCLASS_BLACK)
00468     {
00469         ++id;
00470         SG_ASSERT(s_flags[id] & SG_PROPCLASS_WHITE);
00471     }
00472     else if (flags & SG_PROPCLASS_WHITE)
00473     {
00474         --id;
00475         SG_ASSERT(s_flags[id] & SG_PROPCLASS_BLACK);
00476     }
00477     return id;
00478 }
00479 
00480 SgPropID SgProp::PlayerProp(SgPropID id, SgBlackWhite player)
00481 {
00482     // AR: ---> Flags cannot really be overridden
00483     SgPropFlags flags = s_flags[id];
00484     SG_ASSERT(flags & (SG_PROPCLASS_BLACK | SG_PROPCLASS_WHITE));
00485     int mask = (player == SG_WHITE ? SG_PROPCLASS_WHITE : SG_PROPCLASS_BLACK);
00486     if (flags & mask)
00487         return id;
00488     else
00489         return OpponentProp(id);
00490 }
00491 
00492 SgBlackWhite SgProp::Player() const
00493 {
00494     SG_ASSERT(Flag(SG_PROPCLASS_BLACK | SG_PROPCLASS_WHITE));
00495     if (Flags() & SG_PROPCLASS_BLACK)
00496         return SG_BLACK;
00497     else if (Flags() & SG_PROPCLASS_WHITE)
00498         return SG_WHITE;
00499     SG_ASSERT(false);
00500     return -1;
00501 }
00502 
00503 bool SgProp::IsPlayer(SgBlackWhite player) const
00504 {
00505     SG_ASSERT_BW(player);
00506     return (Player() == player);
00507 }
00508 
00509 bool SgProp::MatchesID(SgPropID id) const
00510 {
00511     // Matches if ID matches exactly.
00512     if (id == ID())
00513         return true;
00514 
00515     // Matches if looking for abstract property and matches that category.
00516     if (s_flags[id] & SG_PROPCLASS_ABSTRACT)
00517     {
00518         SgPropFlags fCategories = s_flags[id] & (~SG_PROPCLASS_ABSTRACT);
00519         if ((Flags() & fCategories) == fCategories)
00520             return true;
00521     }
00522 
00523     return false;
00524 }
00525 
00526 SgPropID SgProp::ConvertFindTextToPropID(const string& findText)
00527 {
00528     size_t length = findText.size();
00529     if (  (3 <= length && findText[1] == ' ' && findText[2] == '<')
00530        || (2 <= length && findText[1] == '<')
00531        ||  1 == length
00532        )
00533     {
00534         switch (findText[0])
00535         {
00536         case 'A': return SG_PROP_ANNOTATE;
00537         case 'B': return SG_PROP_MOVE_BLACK;
00538         case 'C': return SG_PROP_COMMENT;
00539         case 'H': return SG_PROP_HOTSPOT;
00540         case 'I': return SG_PROP_INFO;
00541         case 'K': return SG_PROP_CHECK;
00542         case 'M': return SG_PROP_MARKS;
00543         case 'N': return SG_PROP_NAME;
00544         case 'S': return SG_PROP_SIGMA;
00545         case 'T': return SG_PROP_TRIANGLE;
00546         case 'W': return SG_PROP_MOVE_WHITE;
00547         case '!': return SG_PROP_GOOD_MOVE;
00548         case '?': return SG_PROP_BAD_MOVE;
00549         case '.': return SG_PROP_TERMINAL;
00550         case ':': return SG_PROP_BRANCH;
00551         default: break;
00552         }
00553     }
00554     return SG_PROP_NONE;
00555 }
00556 
00557 void SgProp::Init()
00558 {
00559     // Attributes of SG_PROP_NONE.
00560     s_flags[0] = 0;
00561     s_label[0] = "";
00562     s_prop[0] = 0;
00563 
00564     // Create prototype properties, one for each property class.
00565     SgProp* unknownProp = new SgPropUnknown(0);
00566     SgProp* simpleProp = new SgPropSimple(0);
00567     SgProp* intProp = new SgPropInt(0);
00568     SgProp* realProp = new SgPropReal(0);
00569     SgProp* multipleProp = new SgPropMultiple(0);
00570     SgProp* valueProp = new SgPropValue(0);
00571     SgProp* timeProp = new SgPropTime(0);
00572     SgProp* mSecProp = new SgPropMSec(0);
00573     SgProp* moveProp = new SgPropMove(0);
00574     SgProp* listProp = new SgPropPointList(0);
00575     SgProp* textProp = new SgPropText(0);
00576     SgProp* textListProp = new SgPropTextList(0);
00577     SgProp* playerProp = new SgPropPlayer(0);
00578     SgProp* addStoneProp = new SgPropAddStone(0);
00579 
00580     // Register abstract property classes so they get cleaned up on fini.
00581     SG_PROP_NONE = 0;
00582     SG_PROP_UNKNOWN = Register(unknownProp, "");
00583     Register(simpleProp, "");
00584     Register(intProp, "");
00585     Register(realProp, "");
00586     Register(multipleProp, "");
00587     Register(valueProp, "");
00588     Register(timeProp, "");
00589     Register(mSecProp, "");
00590     Register(moveProp, "");
00591     Register(listProp, "");
00592     Register(textProp, "");
00593     Register(textListProp, "");
00594     Register(playerProp, "");
00595     Register(addStoneProp, "");
00596 
00597     // Create the standard properties.
00598 
00599     //--- moves and board edits
00600     SG_PROP_MOVE = Register(0, "", SG_PROPCLASS_MOVE + SG_PROPCLASS_ABSTRACT);
00601     SG_PROP_PLAYER = Register(playerProp, "PL");
00602     SG_PROP_ADD_BLACK = Register(addStoneProp, "AB",
00603                                  SG_PROPCLASS_BLACK + SG_PROPCLASS_NEWLINE);
00604     SG_PROP_ADD_WHITE = Register(addStoneProp, "AW",
00605                                  SG_PROPCLASS_WHITE + SG_PROPCLASS_NEWLINE);
00606     SG_PROP_ADD_EMPTY = Register(addStoneProp, "AE", SG_PROPCLASS_NEWLINE);
00607 
00608     //--- value and territory
00609     SG_PROP_VALUE = Register(valueProp, "V");
00610     SG_PROP_TERR_BLACK = Register(listProp, "TB",
00611                                   SG_PROPCLASS_BLACK + SG_PROPCLASS_NEWLINE);
00612     SG_PROP_TERR_WHITE = Register(listProp, "TW",
00613                                   SG_PROPCLASS_WHITE + SG_PROPCLASS_NEWLINE);
00614 
00615     //--- marks drawn on the board
00616     SG_PROP_MARKS = Register(0, "", SG_PROPCLASS_MARK + SG_PROPCLASS_ABSTRACT);
00617     SG_PROP_SELECT = Register(listProp, "SL", SG_PROPCLASS_MARK);
00618     SG_PROP_MARKED = Register(listProp, "MA", SG_PROPCLASS_MARK);
00619     SG_PROP_TRIANGLE = Register(listProp, "TR", SG_PROPCLASS_MARK);
00620     SG_PROP_SQUARE = Register(listProp, "SQ", SG_PROPCLASS_MARK);
00621     SG_PROP_DIAMOND = Register(listProp, "RG", SG_PROPCLASS_MARK);
00622     SG_PROP_CIRCLE = Register(listProp, "CR", SG_PROPCLASS_MARK);
00623     SG_PROP_DIMMED = Register(listProp, "DD", SG_PROPCLASS_MARK);
00624     SG_PROP_LABEL = Register(textListProp, "LB", SG_PROPCLASS_MARK);
00625 
00626     //--- time control
00627     SG_PROP_TIMES = Register(0, "", SG_PROPCLASS_TIME + SG_PROPCLASS_ABSTRACT);
00628     SG_PROP_TIME_BLACK = Register(timeProp, "BL",
00629                                   SG_PROPCLASS_TIME + SG_PROPCLASS_BLACK);
00630     SG_PROP_TIME_WHITE = Register(timeProp, "WL",
00631                                   SG_PROPCLASS_TIME + SG_PROPCLASS_WHITE);
00632     SG_PROP_OT_BLACK = Register(intProp, "OB",
00633                                 SG_PROPCLASS_TIME + SG_PROPCLASS_BLACK
00634                                 + SG_PROPCLASS_NOTCLEAN);
00635     SG_PROP_OT_WHITE = Register(intProp, "OW",
00636                                 SG_PROPCLASS_TIME + SG_PROPCLASS_WHITE
00637                                 + SG_PROPCLASS_NOTCLEAN);
00638     SG_PROP_OT_NU_MOVES = Register(intProp, "OM",
00639                                    SG_PROPCLASS_TIME + SG_PROPCLASS_ROOT
00640                                    + SG_PROPCLASS_CUSTOM
00641                                    + SG_PROPCLASS_NOTCLEAN);
00642     SG_PROP_OT_PERIOD = Register(timeProp, "OP",
00643                                  SG_PROPCLASS_TIME + SG_PROPCLASS_ROOT
00644                                 + SG_PROPCLASS_CUSTOM + SG_PROPCLASS_NOTCLEAN);
00645     SG_PROP_OVERHEAD = Register(timeProp, "OV",
00646                                 SG_PROPCLASS_TIME + SG_PROPCLASS_ROOT
00647                                 + SG_PROPCLASS_CUSTOM + SG_PROPCLASS_NOTCLEAN);
00648     SG_PROP_LOSE_TIME = Register(simpleProp, "LT",
00649                                  SG_PROPCLASS_TIME + SG_PROPCLASS_ROOT
00650                                 + SG_PROPCLASS_CUSTOM + SG_PROPCLASS_NOTCLEAN);
00651 
00652     //--- statistics
00653     // AR: is official property?
00654     SG_PROP_COUNT = Register(0, "CN",
00655                              SG_PROPCLASS_STAT + SG_PROPCLASS_ABSTRACT);
00656     SG_PROP_TIME_USED = Register(mSecProp, "TU",
00657                                  SG_PROPCLASS_STAT + SG_PROPCLASS_CUSTOM
00658                                  + SG_PROPCLASS_NOTCLEAN);
00659     SG_PROP_NUM_NODES = Register(intProp, "NN",
00660                                  SG_PROPCLASS_STAT + SG_PROPCLASS_CUSTOM
00661                                  + SG_PROPCLASS_NOTCLEAN);
00662     SG_PROP_NUM_LEAFS = Register(intProp, "NL",
00663                                  SG_PROPCLASS_STAT + SG_PROPCLASS_CUSTOM
00664                                  + SG_PROPCLASS_NOTCLEAN);
00665     SG_PROP_MAX_DEPTH = Register(intProp, "MD",
00666                                  SG_PROPCLASS_STAT + SG_PROPCLASS_CUSTOM
00667                                  + SG_PROPCLASS_NOTCLEAN);
00668     SG_PROP_DEPTH = Register(intProp, "DE",
00669                              SG_PROPCLASS_STAT + SG_PROPCLASS_CUSTOM
00670                              + SG_PROPCLASS_NOTCLEAN);
00671     SG_PROP_PART_DEPTH = Register(intProp, "PD",
00672                                   SG_PROPCLASS_STAT + SG_PROPCLASS_CUSTOM
00673                                   + SG_PROPCLASS_NOTCLEAN);
00674     SG_PROP_EVAL = Register(valueProp, "EL",
00675                             SG_PROPCLASS_STAT + SG_PROPCLASS_CUSTOM
00676                             + SG_PROPCLASS_NOTCLEAN);
00677     SG_PROP_EXPECTED = Register(moveProp, "EX",
00678                                 SG_PROPCLASS_STAT + SG_PROPCLASS_CUSTOM
00679                                 + SG_PROPCLASS_NOTCLEAN);
00680 
00681     //--- root props
00682     SG_PROP_FORMAT = Register(intProp, "FF", SG_PROPCLASS_ROOT);
00683     SG_PROP_SIZE = Register(intProp, "SZ", SG_PROPCLASS_ROOT);
00684     SG_PROP_GAME = Register(intProp, "GM", SG_PROPCLASS_ROOT);
00685     // AR: not root props?
00686     SG_PROP_SPEC_BLACK = Register(intProp, "BS", SG_PROPCLASS_CUSTOM);
00687     SG_PROP_SPEC_WHITE = Register(intProp, "WS", SG_PROPCLASS_CUSTOM);
00688     SG_PROP_CHINESE = Register(intProp, "CI",
00689                                SG_PROPCLASS_ROOT + SG_PROPCLASS_CUSTOM);
00690     SG_PROP_APPLIC = Register(textProp, "AP",
00691                               SG_PROPCLASS_ROOT + SG_PROPCLASS_NOT_FF3);
00692 
00693     //--- annotations
00694     SG_PROP_ANNOTATE = Register(0, "",
00695                                 SG_PROPCLASS_ANNO + SG_PROPCLASS_ABSTRACT);
00696     SG_PROP_COMMENT = Register(textProp, "C",
00697                                SG_PROPCLASS_ANNO + SG_PROPCLASS_NEWLINE);
00698     SG_PROP_NAME = Register(textProp, "N",
00699                             SG_PROPCLASS_ANNO + SG_PROPCLASS_NEWLINE);
00700     SG_PROP_CHECK = Register(multipleProp, "CH",
00701                              SG_PROPCLASS_ANNO + SG_PROPCLASS_CUSTOM);
00702     SG_PROP_SIGMA = Register(multipleProp, "SI",
00703                              SG_PROPCLASS_ANNO + SG_PROPCLASS_CUSTOM);
00704     SG_PROP_HOTSPOT = Register(multipleProp, "HO",
00705                                SG_PROPCLASS_ANNO + SG_PROPCLASS_CUSTOM);
00706     SG_PROP_FIGURE = Register(simpleProp, "FG",
00707                               SG_PROPCLASS_ANNO + SG_PROPCLASS_NEWLINE);
00708 
00709     //--- position annotations
00710     SG_PROP_POS_ANNO = Register(0, "",
00711                                 SG_PROPCLASS_ANNO + SG_PROPCLASS_ANNO_POS
00712                                 + SG_PROPCLASS_ABSTRACT);
00713     SG_PROP_GOOD_BLACK = Register(multipleProp, "GB",
00714                                   SG_PROPCLASS_ANNO + SG_PROPCLASS_ANNO_POS
00715                                   + SG_PROPCLASS_BLACK);
00716     SG_PROP_GOOD_WHITE = Register(multipleProp, "GW",
00717                                   SG_PROPCLASS_ANNO + SG_PROPCLASS_ANNO_POS
00718                                   + SG_PROPCLASS_WHITE);
00719     SG_PROP_EVEN_POS = Register(multipleProp, "DM",
00720                                 SG_PROPCLASS_ANNO + SG_PROPCLASS_ANNO_POS);
00721     SG_PROP_UNCLEAR = Register(multipleProp, "UC",
00722                                SG_PROPCLASS_ANNO + SG_PROPCLASS_ANNO_POS);
00723 
00724     //--- move annotations
00725     SG_PROP_MOVE_ANNO = Register(0, "",
00726                                  SG_PROPCLASS_ANNO + SG_PROPCLASS_ANNO_MOVE
00727                                  + SG_PROPCLASS_ABSTRACT);
00728     SG_PROP_GOOD_MOVE = Register(multipleProp, "TE",
00729                                  SG_PROPCLASS_ANNO + SG_PROPCLASS_ANNO_MOVE);
00730     SG_PROP_BAD_MOVE = Register(multipleProp, "BM",
00731                                 SG_PROPCLASS_ANNO + SG_PROPCLASS_ANNO_MOVE);
00732     SG_PROP_INTERESTING = Register(simpleProp, "IT",
00733                                    SG_PROPCLASS_ANNO + SG_PROPCLASS_ANNO_MOVE);
00734     SG_PROP_DOUBTFUL = Register(simpleProp, "DO",
00735                                 SG_PROPCLASS_ANNO + SG_PROPCLASS_ANNO_MOVE);
00736 
00737     //--- game info
00738     SG_PROP_INFO = Register(0, "", SG_PROPCLASS_INFO + SG_PROPCLASS_ABSTRACT);
00739     SG_PROP_GAME_NAME = Register(textProp, "GN",
00740                                  SG_PROPCLASS_INFO + SG_PROPCLASS_NEWLINE);
00741     SG_PROP_GAME_COMMENT = Register(textProp, "GC",
00742                                     SG_PROPCLASS_INFO + SG_PROPCLASS_NEWLINE);
00743     SG_PROP_EVENT = Register(textProp, "EV",
00744                              SG_PROPCLASS_INFO + SG_PROPCLASS_NEWLINE);
00745     SG_PROP_ROUND = Register(textProp, "RO", SG_PROPCLASS_INFO);
00746     SG_PROP_DATE = Register(textProp, "DT",
00747                             SG_PROPCLASS_INFO + SG_PROPCLASS_NEWLINE);
00748     SG_PROP_PLACE = Register(textProp, "PC",
00749                              SG_PROPCLASS_INFO + SG_PROPCLASS_NEWLINE);
00750     SG_PROP_PLAYER_BLACK = Register(textProp, "PB",
00751                                     SG_PROPCLASS_INFO + SG_PROPCLASS_BLACK
00752                                     + SG_PROPCLASS_NEWLINE);
00753     SG_PROP_PLAYER_WHITE = Register(textProp, "PW",
00754                                     SG_PROPCLASS_INFO + SG_PROPCLASS_WHITE
00755                                     + SG_PROPCLASS_NEWLINE);
00756     SG_PROP_RESULT = Register(textProp, "RE",
00757                               SG_PROPCLASS_INFO + SG_PROPCLASS_NEWLINE);
00758     SG_PROP_USER = Register(textProp, "US",
00759                             SG_PROPCLASS_INFO + SG_PROPCLASS_NEWLINE);
00760     SG_PROP_TIME = Register(textProp, "TM", SG_PROPCLASS_INFO);
00761     SG_PROP_SOURCE = Register(textProp, "SO",
00762                               SG_PROPCLASS_INFO + SG_PROPCLASS_NEWLINE);
00763     SG_PROP_COPYRIGHT = Register(textProp, "CP", SG_PROPCLASS_INFO);
00764     SG_PROP_ANALYSIS = Register(textProp, "AN", SG_PROPCLASS_INFO);
00765     SG_PROP_RANK_BLACK = Register(textProp, "BR",
00766                                   SG_PROPCLASS_INFO + SG_PROPCLASS_BLACK);
00767     SG_PROP_RANK_WHITE = Register(textProp, "WR",
00768                                   SG_PROPCLASS_INFO + SG_PROPCLASS_WHITE);
00769     SG_PROP_TEAM_BLACK = Register(textProp, "BT",
00770                                   SG_PROPCLASS_INFO + SG_PROPCLASS_BLACK);
00771     SG_PROP_TEAM_WHITE = Register(textProp, "WT"
00772                                   , SG_PROPCLASS_INFO + SG_PROPCLASS_WHITE);
00773     SG_PROP_OPENING = Register(textProp, "ON",
00774                                SG_PROPCLASS_INFO + SG_PROPCLASS_NEWLINE);
00775     SG_PROP_RULES = Register(textProp, "RU",
00776                              SG_PROPCLASS_INFO + SG_PROPCLASS_NEWLINE);
00777     SG_PROP_HANDICAP = Register(intProp, "HA", SG_PROPCLASS_INFO);
00778     SG_PROP_KOMI = Register(realProp, "KM", SG_PROPCLASS_INFO);
00779 
00780     //--- abstract properties
00781     SG_PROP_FIND_MOVE = Register(0, "", SG_PROPCLASS_ABSTRACT);
00782     SG_PROP_FIND_TEXT = Register(0, "", SG_PROPCLASS_ABSTRACT);
00783     SG_PROP_BRANCH = Register(0, "", SG_PROPCLASS_ABSTRACT);
00784     SG_PROP_TERMINAL = Register(0, "", SG_PROPCLASS_ABSTRACT);
00785 
00786     //--- Smart Go specific properties
00787     SG_PROP_MOTIVE = Register(textListProp, "MM",
00788                               SG_PROPCLASS_STAT + SG_PROPCLASS_CUSTOM
00789                               + SG_PROPCLASS_NOTCLEAN);
00790     SG_PROP_SEQUENCE = Register(listProp, "MS",
00791                                 SG_PROPCLASS_STAT + SG_PROPCLASS_CUSTOM
00792                                 + SG_PROPCLASS_NOTCLEAN);
00793     SG_PROP_NOT_EMPTY = Register(listProp, "NE",
00794                                  SG_PROPCLASS_MARK + SG_PROPCLASS_CUSTOM
00795                                  + SG_PROPCLASS_NOTCLEAN);
00796     SG_PROP_NOT_BLACK = Register(listProp, "NB",
00797                                  SG_PROPCLASS_MARK + SG_PROPCLASS_CUSTOM
00798                                  + SG_PROPCLASS_NOTCLEAN);
00799     SG_PROP_NOT_WHITE = Register(listProp, "NW",
00800                                  SG_PROPCLASS_MARK + SG_PROPCLASS_CUSTOM
00801                                  + SG_PROPCLASS_NOTCLEAN);
00802 
00803     s_initialized = true;
00804 }
00805 
00806 void SgProp::Fini()
00807 {
00808     s_initialized = false;
00809 }
00810 
00811 //----------------------------------------------------------------------------
00812 
00813 SgProp* SgPropUnknown::Duplicate() const
00814 {
00815     return new SgPropUnknown(m_id, m_label, m_values);
00816 }
00817 
00818 bool SgPropUnknown::ToString(std::vector<std::string>& values, int boardSize,
00819                              SgPropPointFmt fmt, int fileFormat) const
00820 {
00821     SG_UNUSED(boardSize);
00822     SG_UNUSED(fmt);
00823     SG_UNUSED(fileFormat);
00824     values.clear();
00825     for (vector<string>::const_iterator it = m_values.begin();
00826          it != m_values.end(); ++it)
00827         values.push_back(EscapeSpecialCharacters(*it, false));
00828     return true;
00829 }
00830 
00831 bool SgPropUnknown::FromString(const std::vector<std::string>& values,
00832                                int boardSize, SgPropPointFmt fmt)
00833 {
00834     SG_UNUSED(boardSize);
00835     SG_UNUSED(fmt);
00836     m_values = values;
00837     return true;
00838 }
00839 
00840 //----------------------------------------------------------------------------
00841 
00842 SgProp* SgPropSimple::Duplicate() const
00843 {
00844     return new SgPropSimple(m_id);
00845 }
00846 
00847 bool SgPropSimple::ToString(std::vector<std::string>& values, int boardSize,
00848                             SgPropPointFmt fmt, int fileFormat) const
00849 {
00850     SG_UNUSED(boardSize);
00851     SG_UNUSED(fmt);
00852     SG_UNUSED(fileFormat);
00853     values.assign(1, "");
00854     return true;
00855 }
00856 
00857 bool SgPropSimple::FromString(const std::vector<std::string>& values,
00858                                 int boardSize, SgPropPointFmt fmt)
00859 {
00860     SG_UNUSED(values);
00861     SG_UNUSED(boardSize);
00862     SG_UNUSED(fmt);
00863     return true;
00864 }
00865 
00866 //----------------------------------------------------------------------------
00867 
00868 SgProp* SgPropMultiple::Duplicate() const
00869 {
00870     return new SgPropMultiple(m_id, m_value);
00871 }
00872 
00873 //----------------------------------------------------------------------------
00874 
00875 SgProp* SgPropInt::Duplicate() const
00876 {
00877     return new SgPropInt(m_id, m_value);
00878 }
00879 
00880 bool SgPropInt::ToString(std::vector<std::string>& values, int boardSize,
00881                          SgPropPointFmt fmt, int fileFormat) const
00882 {
00883     SG_UNUSED(fileFormat);
00884     SG_UNUSED(boardSize);
00885     SG_UNUSED(fmt);
00886     ostringstream buffer;
00887     buffer << m_value;
00888     values.assign(1, buffer.str());
00889     return true;
00890 }
00891 
00892 bool SgPropInt::FromString(const std::vector<std::string>& values,
00893                            int boardSize, SgPropPointFmt fmt)
00894 {
00895     SG_UNUSED(boardSize);
00896     SG_UNUSED(fmt);
00897     if (values.empty())
00898     {
00899         m_value = 0;
00900         return true;
00901     }
00902     istringstream in(values[0]);
00903     in >> m_value;
00904     return (! in.fail());
00905 }
00906 
00907 //----------------------------------------------------------------------------
00908 
00909 SgProp* SgPropReal::Duplicate() const
00910 {
00911     return new SgPropReal(m_id, m_value, m_precision);
00912 }
00913 
00914 bool SgPropReal::ToString(std::vector<std::string>& values, int boardSize,
00915                           SgPropPointFmt fmt, int fileFormat) const
00916 {
00917     SG_UNUSED(boardSize);
00918     SG_UNUSED(fmt);
00919     SG_UNUSED(fileFormat);
00920     ostringstream buffer;
00921     if (m_precision > 0)
00922         buffer.precision(m_precision);
00923     buffer << fixed << m_value;
00924     values.assign(1, buffer.str());
00925     return true;
00926 }
00927 
00928 bool SgPropReal::FromString(const std::vector<std::string>& values,
00929                             int boardSize, SgPropPointFmt fmt)
00930 {
00931     SG_UNUSED(boardSize);
00932     SG_UNUSED(fmt);
00933     if (values.empty())
00934     {
00935         m_value = 0;
00936         return true;
00937     }
00938     istringstream in(values[0]);
00939     in >> m_value;
00940     return (! in.fail());
00941 }
00942 
00943 //----------------------------------------------------------------------------
00944 
00945 void SgPropValue::ChangeToOpponent()
00946 {
00947     m_value = -m_value;
00948 }
00949 
00950 SgProp* SgPropValue::Duplicate() const
00951 {
00952     return new SgPropValue(m_id, m_value);
00953 }
00954 
00955 //----------------------------------------------------------------------------
00956 
00957 SgPropTime::~SgPropTime()
00958 {
00959 }
00960 
00961 SgProp* SgPropTime::Duplicate() const
00962 {
00963     return new SgPropTime(m_id, m_value, m_precision);
00964 }
00965 
00966 //----------------------------------------------------------------------------
00967 
00968 SgPropMSec::~SgPropMSec()
00969 {
00970 }
00971 
00972 SgProp* SgPropMSec::Duplicate() const
00973 {
00974     return new SgPropMSec(m_id, m_value);
00975 }
00976 
00977 //----------------------------------------------------------------------------
00978 
00979 SgPropPointList::SgPropPointList(SgPropID id,
00980                                 const SgVector<SgPoint>& vector)
00981     : SgProp(id),
00982       m_list(vector)
00983 {
00984 }
00985 
00986 SgPropPointList::~SgPropPointList()
00987 {
00988 }
00989 
00990 SgProp* SgPropPointList::Duplicate() const
00991 {
00992     return new SgPropPointList(ID(), Value());
00993 }
00994 
00995 bool SgPropPointList::ToString(std::vector<std::string>& values,
00996                                int boardSize, SgPropPointFmt fmt,
00997                                int fileFormat) const
00998 {
00999     // Don't write out empty list properties.
01000     if (Value().IsEmpty())
01001         return false;
01002     values.clear();
01003     for (SgVectorIterator<SgPoint> it(Value()); it; ++it)
01004     {
01005         if (! SgIsSpecialMove(*it))
01006             values.push_back(PointToSgfString(*it, boardSize, fmt,
01007                                               fileFormat));
01008     }
01009     return true;
01010 }
01011 
01012 bool SgPropPointList::FromString(const std::vector<std::string>& values,
01013                                  int boardSize, SgPropPointFmt fmt)
01014 {
01015     for (vector<string>::const_iterator it = values.begin();
01016          it != values.end(); ++it)
01017     {
01018         string s = *it;
01019         if (s.size() == 5 && s[2] == ':')
01020         {
01021             // Compressed point list.
01022             string s1 = s.substr(0, 2);
01023             string s2 = s.substr(3, 2);
01024             SgPoint p1 = SgfStringToPoint(s1, boardSize, fmt);
01025             SgPoint p2 = SgfStringToPoint(s2, boardSize, fmt);
01026             if (InBoardRange(p1) && InBoardRange(p2))
01027             {
01028                 SgRect rect(p1, p2);
01029                 for (SgRectIterator iter(rect); iter; ++iter)
01030                     Value().PushBack(*iter);
01031             }
01032             else
01033             {
01034                 return false;
01035             }
01036         }
01037         else
01038         {
01039             // Single point.
01040             SgPoint p = SgfStringToPoint(s, boardSize, fmt);
01041             if (InBoardRange(p) || p == SG_PASS)
01042                 // Pass needed for move sequence
01043                 Value().PushBack(p);
01044             else
01045                 return false;
01046         }
01047     }
01048     return true;
01049 }
01050 
01051 //----------------------------------------------------------------------------
01052 
01053 SgProp* SgPropText::Duplicate() const
01054 {
01055     return new SgPropText(m_id, m_text);
01056 }
01057 
01058 bool SgPropText::ToString(std::vector<std::string>& values, int boardSize,
01059                           SgPropPointFmt fmt, int fileFormat) const
01060 {
01061     SG_UNUSED(fileFormat);
01062     SG_UNUSED(boardSize);
01063     SG_UNUSED(fmt);
01064     values.assign(1, EscapeSpecialCharacters(m_text, false));
01065     return true;
01066 }
01067 
01068 bool SgPropText::FromString(const std::vector<std::string>& values,
01069                               int boardSize, SgPropPointFmt fmt)
01070 {
01071     SG_UNUSED(boardSize);
01072     SG_UNUSED(fmt);
01073     if (values.size() == 0)
01074         m_text = "";
01075     else
01076         m_text = values[0];
01077     return true;
01078 }
01079 
01080 bool SgPropText::ContainsText(const string& findText)
01081 {
01082     return (m_text.find(findText) != string::npos);
01083 }
01084 
01085 //----------------------------------------------------------------------------
01086 
01087 SgPropTextList::SgPropTextList(SgPropID id, const SgVector<SgPoint>& points,
01088                                SgVectorOf<std::string> strings)
01089     : SgProp(id),
01090       m_points(points),
01091       m_strings()
01092 {
01093     for (SgVectorIteratorOf<string> it(strings); it; ++it)
01094     {
01095         m_strings.PushBack(new string(*(*it)));
01096     }
01097 }
01098 
01099 SgPropTextList::~SgPropTextList()
01100 {
01101     for (SgVectorIteratorOf<string> it(m_strings); it; ++it)
01102     {
01103         delete *it;
01104     }
01105 }
01106 
01107 SgProp* SgPropTextList::Duplicate() const
01108 {
01109     return new SgPropTextList(m_id, m_points, m_strings);
01110 }
01111 
01112 bool SgPropTextList::GetStringAtPoint(SgPoint p, string* s) const
01113 {
01114     int index = m_points.Index(p);
01115     if (index >= 0)
01116     {
01117         *s = *m_strings[index];
01118         return true;
01119     }
01120     return false;
01121 }
01122 
01123 void SgPropTextList::AddStringAtPoint(SgPoint p, const string& s)
01124 {
01125     ClearStringAtPoint(p);
01126     m_points.PushBack(p);
01127     m_strings.PushBack(new string(s));
01128 }
01129 
01130 void SgPropTextList::AppendToStringAtPoint(SgPoint p, const string& s)
01131 {
01132     string value;
01133     GetStringAtPoint(p, &value); // may be empty.
01134     value += s;
01135     AddStringAtPoint(p, value); // this clears out old string, if any.
01136 }
01137 
01138 void SgPropTextList::ClearStringAtPoint(SgPoint p)
01139 {
01140     int index = m_points.Index(p);
01141     if (index >= 0)
01142     {
01143         m_points.DeleteAt(index);
01144         delete m_strings[index];
01145         m_strings.DeleteAt(index);
01146     }
01147 }
01148 
01149 bool SgPropTextList::ToString(std::vector<std::string>& values,
01150                               int boardSize, SgPropPointFmt fmt,
01151                               int fileFormat) const
01152 {
01153     // Don't write out empty text list properties.
01154     if (m_points.IsEmpty())
01155         return false;
01156     values.clear();
01157     int index = 0;
01158     for (SgVectorIterator<SgPoint> it(m_points); it; ++it)
01159     {
01160         ostringstream buffer;
01161         buffer << PointToSgfString(*it, boardSize, fmt, fileFormat) << ':'
01162                << EscapeSpecialCharacters(*m_strings[index], true)
01163                ;
01164         values.push_back(buffer.str());
01165         ++index;
01166     }
01167     return true;
01168 }
01169 
01170 bool SgPropTextList::FromString(const std::vector<std::string>& values,
01171                                   int boardSize, SgPropPointFmt fmt)
01172 {
01173     for (vector<string>::const_iterator it = values.begin();
01174          it != values.end(); ++it)
01175     {
01176         string s = *it;
01177         if (s.size() >= 2)
01178         {
01179             string pointString = s.substr(0, 2);
01180             SgPoint p = SgfStringToPoint(pointString, boardSize, fmt);
01181             if (InBoardRange(p) && s.size() >= 3 && s[2] == ':')
01182             {
01183                 string text = s.substr(3);
01184                 AddStringAtPoint(p, text);
01185                 return true;
01186             }
01187         }
01188     }
01189     return false;
01190 }
01191 
01192 bool SgPropTextList::ContainsText(const string& findText)
01193 {
01194     for (SgVectorIteratorOf<string> it(m_strings); it; ++it)
01195     {
01196         if ((*it)->find(findText) != string::npos)
01197             return true;
01198     }
01199     return false;
01200 }
01201 
01202 //----------------------------------------------------------------------------
01203 
01204 SgProp* SgPropPlayer::Duplicate() const
01205 {
01206     return new SgPropPlayer(m_id, m_player);
01207 }
01208 
01209 bool SgPropPlayer::ToString(std::vector<std::string>& values, int boardSize,
01210                             SgPropPointFmt fmt, int fileFormat) const
01211 {
01212     SG_UNUSED(fileFormat);
01213     SG_UNUSED(boardSize);
01214     SG_UNUSED(fmt);
01215     values.assign(1, m_player == SG_WHITE ? "W" : "B");
01216     return true;
01217 }
01218 
01219 bool SgPropPlayer::FromString(const std::vector<std::string>& values,
01220                               int boardSize, SgPropPointFmt fmt)
01221 {
01222     SG_UNUSED(boardSize);
01223     SG_UNUSED(fmt);
01224     if (values.size() == 0)
01225         return false;
01226     m_player = (values[0] == "W" || values[0] == "w") ? SG_WHITE : SG_BLACK;
01227     return true;
01228 }
01229 
01230 void SgPropPlayer::ChangeToOpponent()
01231 {
01232     m_player = SgOppBW(m_player);
01233 }
01234 
01235 //----------------------------------------------------------------------------
01236 
01237 SgPropAddStone::~SgPropAddStone()
01238 {
01239 }
01240 
01241 SgProp* SgPropAddStone::Duplicate() const
01242 {
01243     return new SgPropAddStone(m_id, Value());
01244 }
01245 
01246 //----------------------------------------------------------------------------
01247 
01248 SgProp* SgPropMove::Duplicate() const
01249 {
01250     return new SgPropMove(m_id, m_move);
01251 }
01252 
01253 bool SgPropMove::ToString(std::vector<std::string>& values, int boardSize,
01254                           SgPropPointFmt fmt, int fileFormat) const
01255 {
01256     values.assign(1, PointToSgfString(m_move, boardSize, fmt, fileFormat));
01257     return true;
01258 }
01259 
01260 bool SgPropMove::FromString(const std::vector<std::string>& values,
01261                               int boardSize, SgPropPointFmt fmt)
01262 {
01263     if (values.size() == 0)
01264         return false;
01265     m_move = SgfStringToPoint(values[0], boardSize, fmt);
01266     return m_move != SG_NULLMOVE;
01267 }
01268 
01269 //----------------------------------------------------------------------------
01270 


17 Jun 2010 Doxygen 1.4.7