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