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