00001 //---------------------------------------------------------------------------- 00002 /** @file SgTimeRecord.h 00003 Time management. */ 00004 //---------------------------------------------------------------------------- 00005 00006 #ifndef SG_TIMERECORD_H 00007 #define SG_TIMERECORD_H 00008 00009 #include <iosfwd> 00010 #include "SgBWArray.h" 00011 00012 class SgNode; 00013 00014 //---------------------------------------------------------------------------- 00015 00016 /** Clock states. */ 00017 enum SgClockState { 00018 /** The clock is turned off; no time is counted for either player. */ 00019 SG_CLOCK_OFF, 00020 00021 /** The time is running for one of the players. */ 00022 SG_CLOCK_RUNNING, 00023 00024 /** The running clock was turned off by the computer; some 00025 actions may automatically cause it to turn back on. */ 00026 SG_CLOCK_SUSPENDED 00027 }; 00028 00029 //---------------------------------------------------------------------------- 00030 00031 /** A time record contains time-related information. 00032 How much time each player has left, how overtime is regulated, and how 00033 many moves there are left in this overtime period. This information is 00034 updated when replaying a game depending on time-related properties stored 00035 in the game tree. 00036 00037 A time contest: dynamic time record of an ongoing game. 00038 The time left at each point in the game is stored as properties in the 00039 tree. The time stored is the time left when entering a new node; the 00040 time left while the clock is running at a node is not stored anywhere 00041 except in the TimeContest object. Thus leaving a node and returning to 00042 it later will restore the time left when first entering the node, not 00043 when leaving the node. 00044 */ 00045 class SgTimeRecord 00046 { 00047 public: 00048 explicit SgTimeRecord(int numMoves = 0, double period = 0, 00049 double overhead = 0, bool loseOnTime = false); 00050 00051 /** Constructor. 00052 'oneMoveOnly' must be true for the second constructor (just to 00053 distinguish the two constructors). The second one creates a time 00054 record that can be used to set a specific time period for one move 00055 only. */ 00056 SgTimeRecord(bool oneMoveOnly, double timeForMove); 00057 00058 ~SgTimeRecord(); 00059 00060 00061 /** @name Time settings for the game */ 00062 // @{ 00063 00064 bool UseOvertime() const; 00065 00066 int OTNumMoves() const; 00067 00068 double OTPeriod() const; 00069 00070 double Overhead() const; 00071 00072 bool LoseOnTime() const; 00073 00074 void SetOTNumMoves(int numMoves); 00075 00076 void SetOTPeriod(double period); 00077 00078 void SetOverhead(double overhead); 00079 00080 void SetLoseOnTime(bool lose); 00081 00082 // @} // name 00083 00084 00085 /** @name Clock state */ 00086 // @{ 00087 00088 /** Return the state of the clock: stopped, running, or suspended. */ 00089 SgClockState GetClockState() const; 00090 00091 bool ClockIsRunning() const; 00092 00093 /** Returns the current time left. 00094 Call UpdateTimeLeft first to get the newest information. */ 00095 double TimeLeft(SgBlackWhite player) const; 00096 00097 /** The number of moves left to play in this overtime period. 00098 This is zero if the game is in main time. */ 00099 int MovesLeft(SgBlackWhite color) const; 00100 00101 void SetTimeLeft(SgBlackWhite color, double timeLeft); 00102 00103 /** Turn the clock on or off. 00104 @todo Set gUserAbort if the time is turned off, so that for example a 00105 search is aborted. */ 00106 void TurnClockOn(bool turnOn); 00107 00108 /** Set number of moves left to play in this overtime period. 00109 This is zero if the game is in main time. */ 00110 void SetMovesLeft(SgBlackWhite color, int moves); 00111 00112 /** Set the clock into suspended state. */ 00113 void SuspendClock(); 00114 00115 /** Update the internal m_timeLeft. 00116 If the time left is negative, m_movesLeft is set if overtime is 00117 starting, or a "lost on time" is shown if m_loseOnTime is true. */ 00118 void UpdateTimeLeft(); 00119 00120 // @} // name 00121 00122 00123 /** @name Functions for using the clock in a game */ 00124 // @{ 00125 00126 /** Called by GoGame to react to user events. 00127 Called when a node is entered after moving in the tree or just to 00128 refresh the current state 00129 If the clock is on and the node is not m_atNode, the clock is 00130 suspended. m_player is set to the given player, and m_timeLeft is set 00131 to reflect the time left at that node. */ 00132 void EnterNode(SgNode& node, SgBlackWhite player); 00133 00134 /** Called by GoGame to react to user events. 00135 Called when a move was played on the board. 00136 If the clock was suspended, the clock is turned back on. 00137 Otherwise, if the clock was running, the time left is stored as 00138 properties in the new node. */ 00139 void PlayedMove(SgNode& node, SgBlackWhite player); 00140 00141 /** Set time left and store it as a property in the tree. 00142 If time is <= 0, puts it into overtime. */ 00143 void SetClock(SgNode& node, SgBlackWhite player, double time); 00144 00145 // @} // name 00146 00147 00148 /** @name Utility functions */ 00149 // @{ 00150 00151 /** Returns the time stored at the given node or its most recent 00152 ancestor. */ 00153 static SgBWArray<double> GetTimeFromTree(SgNode& node); 00154 00155 /** Returns the number of moves left to play in overtime as determined by 00156 the given node or an ancestor with that property. */ 00157 static SgBWArray<int> GetOTMovesFromTree(SgNode& node); 00158 00159 /** Sets the time property at the given node for both players. */ 00160 static void SetTimeInTree(SgNode& node, SgBWArray<double> time); 00161 00162 // @} // name 00163 00164 private: 00165 /** How many moves to play in one overtime period. 00166 zero if there is no overtime. */ 00167 int m_overtimeNumMoves; 00168 00169 /** The length of one overtime period. */ 00170 double m_overtimePeriod; 00171 00172 /** How much time to subtract for each move due to time 00173 used by the operator of the program (move entry, etc.). */ 00174 double m_overhead; 00175 00176 /** Whether to end the game when a player has negative time left. */ 00177 bool m_loseOnTime; 00178 00179 /** The player whose clock is running. 00180 Only relevant if the clock is running. */ 00181 SgBlackWhite m_player; 00182 00183 /** Whether the clock is turned on and running. */ 00184 bool m_clockIsOn; 00185 00186 /** Whether the clock is suspended. 00187 Note: m_clockIsOn and m_suspended cannot both be true. */ 00188 bool m_suspended; 00189 00190 /** The current node at which the time is running. */ 00191 SgNode* m_atNode; 00192 00193 /** The time left for both players. 00194 This is updated frequently, reflecting the time stored in fAtNode 00195 minus the time spent at that node. */ 00196 SgBWArray<double> m_timeLeft; 00197 00198 /**The number of moves left to play in this overtime period. 00199 This is zero if game is in main time. */ 00200 SgBWArray<int> m_movesLeft; 00201 00202 /** The time at which fTimeLeft was last updated. */ 00203 double m_timeOfLastUpdate; 00204 }; 00205 00206 inline SgTimeRecord::~SgTimeRecord() 00207 { 00208 } 00209 00210 inline bool SgTimeRecord::ClockIsRunning() const 00211 { 00212 return m_clockIsOn; 00213 } 00214 00215 inline bool SgTimeRecord::LoseOnTime() const 00216 { 00217 return m_loseOnTime; 00218 } 00219 00220 inline int SgTimeRecord::MovesLeft(SgBlackWhite color) const 00221 { 00222 return m_movesLeft[color]; 00223 } 00224 00225 inline int SgTimeRecord::OTNumMoves() const 00226 { 00227 return m_overtimeNumMoves; 00228 } 00229 00230 inline double SgTimeRecord::OTPeriod() const 00231 { 00232 return m_overtimePeriod; 00233 } 00234 00235 inline double SgTimeRecord::Overhead() const 00236 { 00237 return m_overhead; 00238 } 00239 00240 inline void SgTimeRecord::SetLoseOnTime(bool lose) 00241 { 00242 m_loseOnTime = lose; 00243 } 00244 00245 inline void SgTimeRecord::SetMovesLeft(SgBlackWhite color, int moves) 00246 { 00247 SG_ASSERT(moves >= 0); m_movesLeft[color] = moves; 00248 } 00249 00250 inline void SgTimeRecord::SetOTNumMoves(int numMoves) 00251 { 00252 m_overtimeNumMoves = numMoves; 00253 } 00254 00255 inline void SgTimeRecord::SetOTPeriod(double period) 00256 { 00257 m_overtimePeriod = period; 00258 } 00259 00260 inline void SgTimeRecord::SetOverhead(double overhead) 00261 { 00262 m_overhead = overhead; 00263 } 00264 00265 inline void SgTimeRecord::SetTimeLeft(SgBlackWhite color, double timeLeft) 00266 { 00267 m_timeLeft[color] = timeLeft; 00268 } 00269 00270 inline bool SgTimeRecord::UseOvertime() const 00271 { 00272 return m_overtimeNumMoves > 0; 00273 } 00274 00275 //---------------------------------------------------------------------------- 00276 00277 /** Output SgTimeRecord to stream. 00278 @relatesalso SgTimeRecord */ 00279 std::ostream& operator<<(std::ostream& out, const SgTimeRecord& time); 00280 00281 /** Output SgClockState to stream. */ 00282 std::ostream& operator<<(std::ostream& out, SgClockState clockState); 00283 00284 //---------------------------------------------------------------------------- 00285 00286 #endif // SG_TIMERECORD_H