Communicate clock times in bughouse
authorFabian Fichter <ianfab@users.noreply.github.com>
Wed, 11 Mar 2020 22:44:50 +0000 (23:44 +0100)
committerFabian Fichter <ianfab@users.noreply.github.com>
Wed, 11 Mar 2020 22:44:50 +0000 (23:44 +0100)
Consider clock times of partner board in time management (#64).

src/partner.cpp
src/partner.h
src/search.cpp
src/timeman.cpp

index 77ef9da..5b7c583 100644 (file)
 PartnerHandler Partner; // Global object
 
 void PartnerHandler::reset() {
-    sitRequested = partnerDead = weDead = false;
+    fast = sitRequested = partnerDead = weDead = false;
+    time = opptime = 0;
 }
 
+template <PartnerType p>
 void PartnerHandler::ptell(const std::string& message) {
-    sync_cout << "tellics ptell " << message << sync_endl;
+    if (p == ALL_PARTNERS || (p == FAIRY && isFairy) || (p == HUMAN && !isFairy))
+        sync_cout << "tellics ptell " << message << sync_endl;
 }
 
 void PartnerHandler::parse_partner(std::istringstream& is) {
     std::string token;
     if (is >> token)
+        // handshake to identify Fairy-Stockfish
         ptell("partner Fairy-Stockfish is an engine. Ask it 'help' for supported commands.");
     else
         isFairy = false;
@@ -47,45 +51,54 @@ void PartnerHandler::parse_ptell(std::istringstream& is, const Position& pos) {
     is >> token;
     if (token == "partner")
     {
+        // handshake to identify Fairy-Stockfish
         if (is >> token && token == "Fairy-Stockfish")
             isFairy = true;
     }
     else if (token == "help")
     {
         if (!(is >> token))
-            ptell("I listen to the commands help, sit, go, and move. Ptell 'help sit', etc. for details.");
+        {
+            ptell<HUMAN>("I listen to the commands help, sit, go, move, fast, slow, dead, x, time, and otim.");
+            ptell<HUMAN>("Tell 'help sit', etc. for details.");
+        }
         else if (token == "sit")
-            ptell("After receiving 'sit', I stop moving. Also see 'go'.");
+            ptell<HUMAN>("After receiving 'sit', I stop moving. Also see 'go'.");
         else if (token == "go")
-            ptell("After receiving 'go', I will no longer sit.");
+            ptell<HUMAN>("After receiving 'go', I will no longer sit.");
         else if (token == "move")
         {
-            ptell("After receiving 'move', I will move immediately." );
-            ptell("If you specify a valid move, e.g., 'move e2e4', I will play it.");
+            ptell<HUMAN>("After receiving 'move', I will move immediately." );
+            ptell<HUMAN>("If you specify a valid move, e.g., 'move e2e4', I will play it.");
+        }
+        else if (token == "fast")
+            ptell<HUMAN>("After receiving 'go', I will play fast.");
+        else if (token == "slow")
+            ptell<HUMAN>("After receiving 'slow', I will play at normal speed.");
+        else if (token == "dead")
+            ptell<HUMAN>("After receiving 'dead', I assume you are dead and I play fast.");
+        else if (token == "x")
+            ptell<HUMAN>("After receiving 'x', I assume I can play normally again.");
+        else if (token == "time")
+        {
+            ptell<HUMAN>("'time' together with your time in centiseconds allows me to consider your time.");
+            ptell<HUMAN>("E.g., 'time 1000' for 10 seconds.");
         }
+        else if (token == "otim")
+            ptell<HUMAN>("'otim' together with your opponent's time in centiseconds allows me to consider his time.");
     }
     else if (!pos.two_boards())
         return;
     else if (token == "sit")
     {
         sitRequested = true;
-        ptell("I sit, tell me 'go' to continue");
+        ptell<HUMAN>("I sit, tell me 'go' to continue");
     }
     else if (token == "go")
     {
         sitRequested = false;
         Threads.stop = true;
     }
-    else if (token == "dead")
-    {
-        partnerDead = true;
-        ptell("I will play fast");
-    }
-    else if (token == "x")
-    {
-        partnerDead = false;
-        ptell("I will play normally again");
-    }
     else if (token == "move")
     {
         if (is >> token)
@@ -95,9 +108,43 @@ void PartnerHandler::parse_ptell(std::istringstream& is, const Position& pos) {
             if (move && !Threads.abort.exchange(true))
                 moveRequested = move;
             else
-                ptell("sorry, not possible");
+                ptell<HUMAN>("sorry, not possible");
         }
         else
             Threads.stop = true;
     }
+    else if (token == "fast")
+    {
+        fast = true;
+        ptell<HUMAN>("I play fast, tell me 'slow' to play normally again");
+    }
+    else if (token == "slow")
+    {
+        fast = false;
+        ptell<HUMAN>("I play at normal speed again.");
+    }
+    else if (token == "dead")
+    {
+        partnerDead = true;
+        ptell<HUMAN>("I play fast, tell me 'x' if you are no longer dead.");
+    }
+    else if (token == "x")
+    {
+        partnerDead = false;
+        ptell<HUMAN>("I play normally again");
+    }
+    else if (token == "time")
+    {
+        int value;
+        time = (is >> value) ? value : 0;
+    }
+    else if (token == "otim")
+    {
+        int value;
+        opptime = (is >> value) ? value : 0;
+    }
 }
+
+template void PartnerHandler::ptell<HUMAN>(const std::string&);
+template void PartnerHandler::ptell<FAIRY>(const std::string&);
+template void PartnerHandler::ptell<ALL_PARTNERS>(const std::string&);
index 47fbc7d..c63c06c 100644 (file)
 /// PartnerHandler manages the communication with the partner
 /// in games played on two boards, such as bughouse.
 
+enum PartnerType {
+  HUMAN,
+  FAIRY,
+  ALL_PARTNERS
+};
+
 struct PartnerHandler {
     void reset();
+    template <PartnerType p = ALL_PARTNERS>
     void ptell(const std::string& message);
     void parse_partner(std::istringstream& is);
     void parse_ptell(std::istringstream& is, const Position& pos);
 
     std::atomic<bool> isFairy;
-    std::atomic<bool> sitRequested, partnerDead, weDead;
+    std::atomic<bool> fast, sitRequested, partnerDead, weDead;
+    std::atomic<int> time, opptime;
     Move moveRequested;
 };
 
index 86d9828..013b1ca 100644 (file)
@@ -258,8 +258,12 @@ void MainThread::search() {
       Thread::search(); // Let's start searching!
   }
 
-  if (rootPos.two_boards() && !Threads.abort)
+  if (rootPos.two_boards() && !Threads.abort && Options["Protocol"] == "xboard")
   {
+      if (Limits.time[us])
+          Partner.ptell<FAIRY>("time " + std::to_string(Limits.time[us] / 10));
+      if (Limits.time[~us])
+          Partner.ptell<FAIRY>("otim " + std::to_string(Limits.time[~us] / 10));
       if (!Partner.weDead && this->rootMoves[0].score <= VALUE_MATED_IN_MAX_PLY)
       {
           Partner.ptell("dead");
index b63d000..a434502 100644 (file)
@@ -120,6 +120,15 @@ void TimeManagement::init(const Position& pos, Search::LimitsType& limits, Color
                  + limits.inc[us] * (hypMTG - 1)
                  - moveOverhead * (2 + std::min(hypMTG, 40));
 
+      // Adjust time management for four-player variants
+      if (pos.two_boards())
+      {
+          if (Partner.partnerDead && Partner.opptime)
+              hypMyTime -= Partner.opptime * 10;
+          else if (Partner.fast || Partner.partnerDead)
+              hypMyTime /= 4;
+      }
+
       hypMyTime = std::max(hypMyTime, TimePoint(0));
 
       TimePoint t1 = minThinkingTime + remaining<OptimumTime>(pos, hypMyTime, hypMTG, ply, slowMover);
@@ -129,9 +138,6 @@ void TimeManagement::init(const Position& pos, Search::LimitsType& limits, Color
       maximumTime = std::min(t2, maximumTime);
   }
 
-  if (pos.two_boards() && Partner.partnerDead)
-      optimumTime /= 4;
-
   if (Options["Ponder"])
       optimumTime += optimumTime / 4;
 }