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


Sun Mar 13 2011 Doxygen 1.7.1