pikafish协议

发布时间 2023-12-10 22:10:41作者: ryueifu
/* 
Pikafish Proxy - a Chinese Chess Engine Wrapper for XQWizard to run Pikafish
Designed by Morning Yellow, Version: 2023-03-05, Last Modified: Jun. 2023
Copyright (C) 2023 www.xqbase.com
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <stdio.h>
#include <string.h>
#include "version.h"
#include "../base/pipe.h"
#include "../base/base.h"
#include "../base/base2.h"
#include "../base/rc4prng.h"
#include "../eleeye/pregen.h"
#include "../eleeye/position.h"
#include "../eleeye/book.h"

int main(void) {
  bool bUseBook;
  int i, nLen, mv, vl;
  uint32_t dwMoveStr;
  char *lp, *lpTime, *lp2;
  char sz[LINE_INPUT_MAX_CHAR], sz2[LINE_INPUT_MAX_CHAR];
  char szTime[LINE_INPUT_MAX_CHAR], szInc[LINE_INPUT_MAX_CHAR], szBookFile[LINE_INPUT_MAX_CHAR];
  BookStruct mvsBook[MAX_GEN_MOVES];
  RC4Struct rc4;
  PipeStruct pipeConsole, pipeEngine;
  PositionStruct pos;

  bUseBook = true;
  LocatePath(sz, "pikafish-modern.exe");
  LocatePath(szBookFile, "BOOK.DAT");
  pipeConsole.Open();
  pipeEngine.Open(sz);
  PreGenInit();
  rc4.InitRand();
  pos.FromFen(cszStartFen);

  while (pipeEngine.nEof == 0) {

    // Read Pikafish's Response
    while (pipeEngine.LineInput(sz)) {
      // printf("info string ENG->GUI: [%s]\n", sz);
      if (false) {

        // "Pikafish ...": Ignore
      } else if (strncmp(sz, "Pikafish ", 9) == 0) {

        // "id ...", "option ...", "uciok": Ignore
      } else if (strncmp(sz, "id ", 3) == 0) {
      } else if (strncmp(sz, "option ", 7) == 0) {
      } else if (strcmp(sz, "uciok") == 0) {

        // "bestmove (none)" -> "nobestmove"
      } else if (strcmp(sz, "bestmove (none)") == 0) {
        printf("nobestmove\n");

        // "info depth ... score cp ..." -> "info depth ... score ..."
      } else if (strncmp(sz, "info depth ", 11) == 0) {
        lp = strstr(sz, " score cp ");
        if (lp != NULL) {
          strcpy(sz2, lp + 10);
          strcpy(lp + 7, sz2);
        }
        printf("%s\n", sz);

        // else: unchanged
      } else {
        printf("%s\n", sz);
      }
      fflush(stdout);
    }

    // Read XQWizard's Request
    while (pipeConsole.LineInput(sz)) {
      if (false) {

        // "ucci" -> "uci", show version and options
      } else if (strcmp(sz, "ucci") == 0) {

        printf("id name Pikafish\n");
        printf("id version " PIKAFISH_VERSION "\n");
        printf("option usemillisec type check default true\n");
        printf("option usebook type check default true\n");
        printf("option bookfiles type string default %s\n", szBookFile);
        printf("option hashsize type spin default 16 min 1 max 33554432\n");
        printf("option threads type spin default 1 min 1 max 1024\n");
        printf("ucciok\n");
        strcpy(sz, "uci");

        // "setoption ...": only accepts "usebook", "bookfiles", "hashsize" and "threads"
      } else if (strncmp(sz, "setoption ", 10) == 0) {

        if (false) {

          // "setoption usebook true/false"
        } else if (strncmp(sz, "setoption usebook ", 18) == 0) {
          lp = sz + 18;
          bUseBook = (strcmp(lp, "true") == 0 || strcmp(lp, "on") == 0);
          continue;

          // "setoption bookfiles ..."
        } else if (strncmp(sz, "setoption bookfiles ", 20) == 0) {
          lp = sz + 20;
          if (AbsolutePath(lp)) {
            strcpy(szBookFile, lp);
          } else {
            LocatePath(szBookFile, lp);
          }
          continue;

          // "setoption hashsize ..." -> "setoption name Hash value ..."
        } else if (strncmp(sz, "setoption hashsize ", 19) == 0) {
          strcpy(sz2, "setoption name Hash value ");
          strcat(sz2, sz + 19);
          strcpy(sz, sz2);

          // "setoption threads ..." -> "setoption name Threads value ..."
        } else if (strncmp(sz, "setoption threads ", 18) == 0) {
          sscanf(sz + 18, "%d", &i);
          sprintf(sz, "setoption name Threads value %d", i < 1 ? 1 : i);
        } else {

          // else: unchanged
          continue;
        }

        // "position ...": parse position for book search
      } else if (strncmp(sz, "position ", 9) == 0) {

        lp = strstr(sz, " fen ");
        if (lp == NULL) {
          pos.FromFen(cszStartFen);
        } else {
          pos.FromFen(lp + 5);
        }
        lp = strstr(sz, " moves ");
        if (lp != NULL) {
          lp += 7;
          nLen = (strlen(lp) + 1) / 5;
          for (i = 0; i < nLen; i ++) {
            mv = COORD_MOVE(*(uint32_t *) lp);
            lp += 5;
            if (mv == 0) {
              break;
            }
            if (pos.ucpcSquares[SRC(mv)] == 0) {
              break;
            }
            pos.MakeMove(mv);
            if (pos.LastMove().CptDrw > 0) {
              pos.SetIrrev();
            }
          }
        }

        // "go ...": search book first, then call engine
      } else if (strncmp(sz, "go ", 3) == 0) {

        // search book
        if (bUseBook) {
          // a. get all moves for this position
          nLen = GetBookMoves(pos, szBookFile, mvsBook);

          if (nLen > 0) {
            vl = 0;
            for (i = 0; i < nLen; i ++) {
              vl += mvsBook[i].wvl;
              dwMoveStr = MOVE_COORD(mvsBook[i].wmv);
              printf("info depth 0 score %d pv %.4s\n", mvsBook[i].wvl, (const char *) &dwMoveStr);
              fflush(stdout);
            }

            // b. pick a random move by move weight
            vl = rc4.NextLong() % (uint32_t) vl;
            for (i = 0; i < nLen; i ++) {
              vl -= mvsBook[i].wvl;
              if (vl < 0) {
                break;
              }
            }

            // c. skip the move that causes repetition
            pos.MakeMove(mvsBook[i].wmv);
            if (pos.RepStatus(3) == 0) {
              dwMoveStr = MOVE_COORD(mvsBook[i].wmv);
              printf("bestmove %.4s", (const char *) &dwMoveStr);
              // d. get ponder move (next move with max weight)
              nLen = GetBookMoves(pos, szBookFile, mvsBook);
              pos.UndoMakeMove();
              if (nLen > 0) {
                dwMoveStr = MOVE_COORD(mvsBook[0].wmv);
                printf(" ponder %.4s", (const char *) &dwMoveStr);
              }
              printf("\n");
              fflush(stdout);
              continue;
            }
            pos.UndoMakeMove();
          }
        }

        // "go time ..." -> "go wtime ... btime ..."
        lp = strstr(sz, " time ");
        if (lp != NULL) {
          lpTime = lp + 6;
          // copy text after "time"
          lp2 = strchr(lpTime, ' ');
          if (lp2 == NULL) {
            strcpy(szTime, lpTime + 6);
          } else {
            nLen = lp2 - lpTime;
            strncpy(szTime, lpTime, nLen);
            szTime[nLen] = '\0';
          }
          // copy text after "increment"
          lp2 = strstr(sz, " increment ");
          if (lp2 == NULL) {
            // copy text after "movestogo"
            lp2 = strstr(sz, " movestogo ");
            if (lp2 == NULL) {
              sprintf(lp, " wtime %s btime %s", szTime, szTime);
            } else {
              lpTime = lp2 + 11;
              lp2 = strchr(lpTime, ' ');
              if (lp2 == NULL) {
                strcpy(szInc, lpTime);
              } else {
                nLen = lp2 - lpTime;
                strncpy(szInc, lpTime, nLen);
                szInc[nLen] = '\0';
              }
              sprintf(lp, " wtime %s btime %s movestogo %s", szTime, szTime, szInc);
            }
          } else {
            lpTime = lp2 + 11;
            lp2 = strchr(lpTime, ' ');
            if (lp2 == NULL) {
              strcpy(szInc, lpTime);
            } else {
              nLen = lp2 - lpTime;
              strncpy(szInc, lpTime, nLen);
              szInc[nLen] = '\0';
            }
            sprintf(lp, " wtime %s btime %s winc %s binc %s", szTime, szTime, szInc, szInc);
          }
        }
        // other options such as "go depth ...": unchanged
      }
      pipeEngine.LineOutput(sz);
      // printf("info string GUI->ENG: [%s]\n", sz);
      fflush(stdout);
    }
    Idle();
  }
  pipeConsole.Close();
  pipeEngine.Close();
  return 0;
}