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