00001 //---------------------------------------------------------------------------- 00002 /** @file SgTimeRecord.cpp 00003 See SgTimeRecord.h. 00004 */ 00005 //---------------------------------------------------------------------------- 00006 00007 #include "SgSystem.h" 00008 #include "SgTimeRecord.h" 00009 00010 #include <iomanip> 00011 #include <limits> 00012 #include <sstream> 00013 #include "SgDebug.h" 00014 #include "SgNode.h" 00015 #include "SgProp.h" 00016 #include "SgTime.h" 00017 #include "SgWrite.h" 00018 00019 using namespace std; 00020 00021 //---------------------------------------------------------------------------- 00022 00023 SgTimeRecord::SgTimeRecord(int numMoves, double period, double overhead, 00024 bool loseOnTime) 00025 : m_overtimeNumMoves(numMoves), 00026 m_overtimePeriod(period), 00027 m_overhead(overhead), 00028 m_loseOnTime(loseOnTime), 00029 m_player(SG_BLACK), 00030 m_clockIsOn(false), 00031 m_suspended(false), 00032 m_atNode(0), 00033 m_timeLeft(0), 00034 m_movesLeft(0), 00035 m_timeOfLastUpdate(0) 00036 { 00037 } 00038 00039 SgTimeRecord::SgTimeRecord(bool oneMoveOnly, double timeForMove) 00040 : m_overtimeNumMoves(1), 00041 m_overtimePeriod(timeForMove), 00042 m_overhead(0), 00043 m_loseOnTime(false), 00044 m_player(SG_BLACK), 00045 m_clockIsOn(false), 00046 m_suspended(false), 00047 m_atNode(0), 00048 m_timeLeft(timeForMove), 00049 m_movesLeft(1), 00050 m_timeOfLastUpdate(0) 00051 { 00052 SG_DEBUG_ONLY(oneMoveOnly); 00053 SG_ASSERT(oneMoveOnly); 00054 } 00055 00056 SgBWArray<double> SgTimeRecord::GetTimeFromTree(SgNode& node) 00057 { 00058 SgBWArray<double> time; 00059 time[SG_BLACK] = 00060 node.TopProp(SG_PROP_TIME_BLACK)->GetRealProp(SG_PROP_TIME_BLACK); 00061 time[SG_WHITE] = 00062 node.TopProp(SG_PROP_TIME_WHITE)->GetRealProp(SG_PROP_TIME_WHITE); 00063 return time; 00064 } 00065 00066 SgBWArray<int> SgTimeRecord::GetOTMovesFromTree(SgNode& node) 00067 { 00068 SgBWArray<int> numMoves; 00069 numMoves[SG_BLACK] = 00070 node.TopProp(SG_PROP_OT_BLACK)->GetIntProp(SG_PROP_OT_BLACK); 00071 numMoves[SG_WHITE] = 00072 node.TopProp(SG_PROP_OT_WHITE)->GetIntProp(SG_PROP_OT_WHITE); 00073 return numMoves; 00074 } 00075 00076 SgClockState SgTimeRecord::GetClockState() const 00077 { 00078 if (m_clockIsOn) 00079 return SG_CLOCK_RUNNING; 00080 else if (m_suspended) 00081 return SG_CLOCK_SUSPENDED; 00082 else 00083 return SG_CLOCK_OFF; 00084 } 00085 00086 double SgTimeRecord::TimeLeft(SgBlackWhite player) const 00087 { 00088 SG_ASSERT_BW(player); 00089 return m_timeLeft[player]; 00090 } 00091 00092 void SgTimeRecord::SetTimeInTree(SgNode& node, SgBWArray<double> time) 00093 { 00094 node.SetRealProp(SG_PROP_TIME_BLACK, time[SG_BLACK]); 00095 node.SetRealProp(SG_PROP_TIME_WHITE, time[SG_WHITE]); 00096 } 00097 00098 void SgTimeRecord::TurnClockOn(bool turnOn) 00099 { 00100 if (m_suspended || (turnOn != m_clockIsOn)) 00101 { 00102 if (turnOn) 00103 m_timeOfLastUpdate = SgTime::Get(); 00104 else 00105 UpdateTimeLeft(); 00106 m_clockIsOn = turnOn; 00107 m_suspended = false; 00108 } 00109 } 00110 00111 void SgTimeRecord::SuspendClock() 00112 { 00113 if (m_clockIsOn && ! m_suspended) 00114 { 00115 m_clockIsOn = false; 00116 m_suspended = true; 00117 } 00118 } 00119 00120 void SgTimeRecord::SetClock(SgNode& node, SgBlackWhite player, double time) 00121 { 00122 node.SetRealProp(SgProp::PlayerProp(SG_PROP_TIME_BLACK, player), time); 00123 m_timeLeft[player] = time; 00124 if (player == m_player) 00125 m_timeOfLastUpdate = SgTime::Get(); 00126 if (m_timeLeft[player] <= 0.0001) 00127 { 00128 m_timeLeft[player] = OTPeriod(); 00129 m_movesLeft[player] = OTNumMoves(); 00130 } 00131 } 00132 00133 void SgTimeRecord::UpdateTimeLeft() 00134 { 00135 double now = SgTime::Get(); 00136 if (m_clockIsOn && (now > m_timeOfLastUpdate)) 00137 { 00138 bool outOfTime = (m_timeLeft[m_player] < now - m_timeOfLastUpdate); 00139 m_timeLeft[m_player] -= now - m_timeOfLastUpdate; 00140 if (outOfTime) 00141 { 00142 SgDebug() << "SgTimeRecord: outOfTime\n"; 00143 if (UseOvertime() && m_movesLeft[m_player] <= 0) 00144 { 00145 SgDebug() << "SgTimeRecond: reseting overtime\n"; 00146 m_timeLeft[m_player] += OTPeriod(); 00147 if (m_timeLeft[m_player] > OTPeriod()) 00148 m_timeLeft[m_player] = OTPeriod(); 00149 m_movesLeft[m_player] = OTNumMoves(); 00150 } 00151 else if (LoseOnTime()) 00152 { 00153 SgDebug() << "SgTimeRecord: lost on time\n"; 00154 SuspendClock(); 00155 } 00156 } 00157 } 00158 m_timeOfLastUpdate = now; 00159 } 00160 00161 void SgTimeRecord::EnterNode(SgNode& node, SgBlackWhite player) 00162 { 00163 if (m_clockIsOn && &node != m_atNode) 00164 SuspendClock(); 00165 m_player = player; 00166 if (! m_clockIsOn) 00167 { 00168 m_atNode = &node; 00169 m_timeLeft = GetTimeFromTree(node); 00170 m_movesLeft = GetOTMovesFromTree(node); 00171 // AR: commented out in Modula-2: fTimeOfLastUpdate := Ticks(); 00172 } 00173 } 00174 00175 void SgTimeRecord::PlayedMove(SgNode& node, SgBlackWhite player) 00176 { 00177 m_atNode = &node; 00178 if (m_suspended && ! node.HasSon()) 00179 TurnClockOn(true); 00180 else if (m_clockIsOn) 00181 { 00182 UpdateTimeLeft(); 00183 if (UseOvertime()) 00184 { 00185 if (m_movesLeft[player] > 0) 00186 { 00187 m_movesLeft[player]--; 00188 if (m_movesLeft[player] == 0) 00189 { 00190 SgDebug() << "SgTimeRecond: reseting overtime\n"; 00191 m_movesLeft[player] = OTNumMoves(); 00192 m_timeLeft[player] = OTPeriod(); 00193 } 00194 } 00195 node.SetIntProp(SgProp::PlayerProp(SG_PROP_OT_BLACK, player), 00196 m_movesLeft[player]); 00197 } 00198 m_timeLeft[player] -= Overhead(); 00199 node.SetRealProp(SgProp::PlayerProp(SG_PROP_TIME_BLACK, player), 00200 m_timeLeft[player]); 00201 } 00202 } 00203 00204 //---------------------------------------------------------------------------- 00205 00206 ostream& operator<<(ostream& out, const SgTimeRecord& time) 00207 { 00208 out << SgWriteLabel("Overhead") << time.Overhead() << '\n' 00209 << SgWriteLabel("UseOvertime") << time.UseOvertime() << '\n' 00210 << SgWriteLabel("OTPeriod") << time.OTPeriod() << '\n' 00211 << SgWriteLabel("OTNumMoves") << time.OTNumMoves() << '\n' 00212 << SgWriteLabel("LoseOnTime") << time.LoseOnTime() << '\n' 00213 << SgWriteLabel("ClockIsRunning") << time.ClockIsRunning() << '\n' 00214 << SgWriteLabel("ClockState") << time.GetClockState() << '\n' 00215 << SgWriteLabel("TimeLeft/B") << time.TimeLeft(SG_BLACK) << '\n' 00216 << SgWriteLabel("TimeLeft/W") << time.TimeLeft(SG_WHITE) << '\n' 00217 << SgWriteLabel("MovesLeft/B") << time.MovesLeft(SG_BLACK) << '\n' 00218 << SgWriteLabel("MovesLeft/W") << time.MovesLeft(SG_WHITE) << '\n'; 00219 return out; 00220 } 00221 00222 ostream& operator<<(ostream& out, SgClockState clockState) 00223 { 00224 switch (clockState) 00225 { 00226 case SG_CLOCK_OFF: 00227 out << "CLOCK_OFF"; 00228 break; 00229 case SG_CLOCK_RUNNING: 00230 out << "CLOCK_RUNNING"; 00231 break; 00232 case SG_CLOCK_SUSPENDED: 00233 out << "CLOCK_SUSPENDED"; 00234 break; 00235 default: 00236 SG_ASSERT(false); 00237 out << "?"; 00238 } 00239 return out; 00240 } 00241 00242 //---------------------------------------------------------------------------- 00243