Rewrite bughouse partner communication
authorFabian Fichter <ianfab@users.noreply.github.com>
Sun, 12 Jan 2020 00:00:53 +0000 (01:00 +0100)
committerFabian Fichter <ianfab@users.noreply.github.com>
Sun, 12 Jan 2020 00:30:10 +0000 (01:30 +0100)
- Support playing moves requested by partner.
- Extend help.

src/Makefile
src/partner.cpp [new file with mode: 0644]
src/partner.h [new file with mode: 0644]
src/search.cpp
src/xboard.cpp

index 9b93f17..98ee074 100644 (file)
@@ -37,7 +37,7 @@ PGOBENCH = ./$(EXE) bench
 
 ### Object files
 OBJS = benchmark.o bitbase.o bitboard.o endgame.o evaluate.o main.o \
-       material.o misc.o movegen.o movepick.o parser.o pawns.o piece.o position.o psqt.o \
+       material.o misc.o movegen.o movepick.o partner.o parser.o pawns.o piece.o position.o psqt.o \
        search.o thread.o timeman.o tt.o uci.o ucioption.o variant.o xboard.o syzygy/tbprobe.o
 
 ### Establish the operating system name
diff --git a/src/partner.cpp b/src/partner.cpp
new file mode 100644 (file)
index 0000000..c1f533e
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+  Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish
+  Copyright (C) 2018-2019 Fabian Fichter
+
+  Fairy-Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Fairy-Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include "partner.h"
+#include "thread.h"
+#include "uci.h"
+
+PartnerHandler Partner; // Global object
+
+void PartnerHandler::parse_partner(std::istringstream& is) {
+    std::string token;
+    if (is >> token)
+        sync_cout << "tellics ptell partner Fairy-Stockfish is an engine. Ask it 'help' for supported commands." << sync_endl;
+    else
+        isFairy = false;
+}
+
+void PartnerHandler::parse_ptell(std::istringstream& is, const Position& pos) {
+    std::string token;
+    is >> token;
+    if (token == "partner")
+    {
+        if (is >> token && token == "Fairy-Stockfish")
+            isFairy = true;
+    }
+    else if (token == "help")
+    {
+        if (!(is >> token))
+            sync_cout << "tellics ptell I listen to the commands help, sit, go, and move. Ptell 'help sit', etc. for details." << sync_endl;
+        else if (token == "sit")
+            sync_cout << "tellics ptell After receiving 'sit', I stop moving. Also see 'go'." << sync_endl;
+        else if (token == "go")
+            sync_cout << "tellics ptell After receiving 'go', I will no longer sit." << sync_endl;
+        else if (token == "move")
+        {
+            sync_cout << "tellics ptell After receiving 'move', I will move immediately."  << sync_endl;
+            sync_cout << "tellics ptell If you specify a valid move, e.g., 'move e2e4', I will play it." << sync_endl;
+        }
+    }
+    else if (!pos.two_boards())
+        return;
+    else if (token == "sit")
+    {
+        sitRequested = true;
+        sync_cout << "tellics ptell I sit, tell me 'go' to continue" << sync_endl;
+    }
+    else if (token == "go")
+    {
+        sitRequested = false;
+        Threads.stop = true;
+    }
+    else if (token == "move")
+    {
+        if (is >> token)
+        {
+            // if the given move is valid and we can still abort the search, play it
+            Move move = UCI::to_move(pos, token);
+            if (move && !Threads.abort.exchange(true))
+                moveRequested = move;
+            else
+                sync_cout << "tellics ptell sorry, not possible" << sync_endl;
+        }
+        else
+            Threads.stop = true;
+    }
+}
diff --git a/src/partner.h b/src/partner.h
new file mode 100644 (file)
index 0000000..def5797
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+  Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish
+  Copyright (C) 2018-2019 Fabian Fichter
+
+  Fairy-Stockfish is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Fairy-Stockfish is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PARTNER_H_INCLUDED
+#define PARTNER_H_INCLUDED
+
+#include <atomic>
+#include <sstream>
+
+#include "position.h"
+
+/// PartnerHandler manages the communication with the partner
+/// in games played on two boards, such as bughouse.
+
+struct PartnerHandler {
+    void parse_partner(std::istringstream& is);
+    void parse_ptell(std::istringstream& is, const Position& pos);
+
+    std::atomic<bool> isFairy;
+    std::atomic<bool> sitRequested;
+    Move moveRequested;
+};
+
+extern PartnerHandler Partner;
+
+#endif // #ifndef PARTNER_H_INCLUDED
\ No newline at end of file
index 3393e29..2c218ef 100644 (file)
@@ -29,6 +29,7 @@
 #include "misc.h"
 #include "movegen.h"
 #include "movepick.h"
+#include "partner.h"
 #include "position.h"
 #include "search.h"
 #include "thread.h"
@@ -260,7 +261,7 @@ void MainThread::search() {
   // GUI sends a "stop" or "ponderhit" command. We therefore simply wait here
   // until the GUI sends one of those commands.
 
-  while (!Threads.stop && (ponder || Limits.infinite || (rootPos.two_boards() && (Threads.sit || this->rootMoves[0].score <= VALUE_MATED_IN_MAX_PLY) && Time.elapsed() < Limits.time[us] - 1000)))
+  while (!Threads.stop && (ponder || Limits.infinite || (rootPos.two_boards() && (Partner.sitRequested || this->rootMoves[0].score <= VALUE_MATED_IN_MAX_PLY) && Time.elapsed() < Limits.time[us] - 1000)))
   {} // Busy wait for a stop or a ponder reset
 
   // Stop the threads if not already stopped (also raise the stop if
@@ -558,7 +559,7 @@ void Thread::search() {
               // keep pondering until the GUI sends "ponderhit" or "stop".
               if (mainThread->ponder)
                   mainThread->stopOnPonderhit = true;
-              else if (!Threads.sit && !(rootPos.two_boards() && bestValue <= VALUE_MATED_IN_MAX_PLY))
+              else if (!(rootPos.two_boards() && (Partner.sitRequested || bestValue <= VALUE_MATED_IN_MAX_PLY)))
                   Threads.stop = true;
           }
       }
@@ -1746,6 +1747,9 @@ void MainThread::check_time() {
   if (ponder)
       return;
 
+  if (Partner.sitRequested)
+      return;
+
   if (   (Limits.use_time_management() && (elapsed > Time.maximum() - 10 || stopOnPonderhit))
       || (Limits.movetime && elapsed >= Limits.movetime)
       || (Limits.nodes && Threads.nodes_searched() >= (uint64_t)Limits.nodes))
index 9972169..2e2b378 100644 (file)
@@ -20,6 +20,7 @@
 #include <string>
 
 #include "evaluate.h"
+#include "partner.h"
 #include "search.h"
 #include "thread.h"
 #include "types.h"
@@ -234,25 +235,20 @@ void StateMachine::process_command(Position& pos, std::string token, std::istrin
       }
   }
   // Bughouse commands
-  else if (token == "partner") {} // ignore for now
+  else if (token == "partner")
+      Partner.parse_partner(is);
   else if (token == "ptell")
   {
-      // parse requests by partner
-      is >> token;
-      if (token == "help")
-          sync_cout << "tellics ptell I listen to the commands help, sit, and go." << sync_endl;
-      else if (token == "hi" || token == "hello")
-          sync_cout << "tellics ptell hi" << sync_endl;
-      else if (token == "sit")
+      Partner.parse_ptell(is, pos);
+      // play move requested by partner
+      if (moveAfterSearch && Partner.moveRequested)
       {
-          Threads.stop = false;
-          Threads.sit = true;
-          sync_cout << "tellics ptell I sit, tell me 'go' to continue" << sync_endl;
-      }
-      else if (token == "go")
-      {
-          Threads.sit = false;
           Threads.stop = true;
+          Threads.main()->wait_for_search_finished();
+          sync_cout << "move " << UCI::move(pos, Partner.moveRequested) << sync_endl;
+          do_move(pos, moveList, states, Partner.moveRequested);
+          moveAfterSearch = false;
+          Partner.moveRequested = MOVE_NONE;
       }
   }
   else if (token == "holding")