00001 //---------------------------------------------------------------------------- 00002 /** @file SgGameWriter.cpp */ 00003 //---------------------------------------------------------------------------- 00004 00005 #include "SgSystem.h" 00006 #include "SgGameWriter.h" 00007 00008 #include <iostream> 00009 #include "SgDebug.h" 00010 #include "SgException.h" 00011 #include "SgNode.h" 00012 00013 using namespace std; 00014 using SgPropUtil::GetPointFmt; 00015 00016 //---------------------------------------------------------------------------- 00017 00018 SgGameWriter::SgGameWriter(ostream& out) 00019 : m_out(out), 00020 m_fileFormat(4), 00021 m_numPropsOnLine(0) 00022 { 00023 } 00024 00025 void SgGameWriter::WriteGame(const SgNode& root, bool allProps, 00026 int fileFormat, int gameNumber, int defaultSize) 00027 { 00028 if (! m_out) 00029 throw SgException("SgGameWriter: write error"); 00030 // Add file format property to root. If file format not specified, 00031 // default to file format read in, or FF[4] for new files. 00032 if (fileFormat != 0) 00033 m_fileFormat = fileFormat; 00034 else if (root.HasProp(SG_PROP_FORMAT)) 00035 m_fileFormat = root.GetIntProp(SG_PROP_FORMAT); 00036 SgPropPointFmt fmt = GetPointFmt(gameNumber); 00037 WriteSubtree(root, allProps, defaultSize, fmt); 00038 m_out.put('\n'); 00039 } 00040 00041 void SgGameWriter::WriteSubtree(const SgNode& nodeRef, bool allProps, 00042 int boardSize, SgPropPointFmt fmt) 00043 { 00044 // Start new sequence on a new line. 00045 StartNewLine(); 00046 00047 // Opening parenthesis. 00048 m_out.put('('); 00049 00050 // Write out main sequence first. 00051 const SgNode* node = &nodeRef; 00052 do 00053 { 00054 HandleProps(node, boardSize); 00055 m_out.put(';'); 00056 WriteNode(*node, allProps, boardSize, fmt); 00057 node = node->LeftMostSon(); 00058 } while (node && ! node->HasRightBrother()); 00059 00060 // Now either reached end of branch, or fork in linear sequence. Write out 00061 // each subtree recursively. 00062 while (node) 00063 { 00064 HandleProps(node, boardSize); 00065 WriteSubtree(*node, allProps, boardSize, fmt); 00066 node = node->RightBrother(); 00067 } 00068 00069 // Closing parenthesis. 00070 m_out.put(')'); 00071 } 00072 00073 void SgGameWriter::HandleProps(const SgNode* node, int& boardSize) const 00074 { 00075 int value; 00076 bool hasSizeProp = node->GetIntProp(SG_PROP_SIZE, &value); 00077 if (hasSizeProp) 00078 { 00079 if (value >= SG_MIN_SIZE && value <= SG_MAX_SIZE) 00080 boardSize = value; 00081 else 00082 SgWarning() << "Invalid size " << value; 00083 } 00084 } 00085 00086 void SgGameWriter::WriteNode(const SgNode& node, bool allProps, int boardSize, 00087 SgPropPointFmt fmt) 00088 { 00089 for (SgPropListIterator it(node.Props()); it; ++it) 00090 { 00091 SgProp* prop = *it; 00092 vector<string> values; 00093 // Check whether property should be written, and get its value. 00094 if ((allProps || ShouldWriteProperty(*prop)) 00095 && prop->ToString(values, boardSize, fmt, m_fileFormat)) 00096 { 00097 // Start specific properties on a new line to make file easier 00098 // to read. 00099 if (prop->Flag(SG_PROPCLASS_NEWLINE)) 00100 StartNewLine(); 00101 m_out << prop->Label(); 00102 for (vector<string>::const_iterator it2 = values.begin(); 00103 it2 != values.end(); ++it2) 00104 m_out << '[' << (*it2) << ']'; 00105 // Limit number of properties per line. 00106 if (++m_numPropsOnLine >= 10) 00107 StartNewLine(); 00108 } } 00109 00110 // Start first move node after root node on a new line. 00111 if (node.HasProp(SG_PROP_GAME)) 00112 StartNewLine(); 00113 } 00114 00115 void SgGameWriter::StartNewLine() 00116 { 00117 // Start a new line unless we're already at the beginning of a line. 00118 if (m_numPropsOnLine > 0) 00119 { 00120 m_numPropsOnLine = 0; 00121 m_out.put('\n'); 00122 } 00123 } 00124 00125 bool SgGameWriter::ShouldWriteProperty(const SgProp& prop) 00126 { 00127 // Only write out clean properties with FF[3]. 00128 // FUTURE: Could make standard adherence a separate option. 00129 if (m_fileFormat == 3 && prop.Flag(SG_PROPCLASS_NOTCLEAN)) 00130 return false; 00131 00132 if (prop.Label() == "") 00133 return false; 00134 00135 // don't write out time left properties (e.g. problem collections). 00136 if (prop.ID() == SG_PROP_TIME_BLACK || prop.ID() == SG_PROP_TIME_WHITE) 00137 return false; 00138 00139 // Default: write out all properties. 00140 return true; 00141 } 00142 00143 //---------------------------------------------------------------------------- 00144