Index   Main   Namespaces   Classes   Hierarchy   Annotated   Files   Compound   Global   Pages  

SgGameWriter.cpp

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


17 Jun 2010 Doxygen 1.4.7