home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / games / volume2 / nchess / part03 / chessprocess.c next >
C/C++ Source or Header  |  1987-11-25  |  10KB  |  388 lines

  1. /*
  2.  * Copyright 1987 Tom Anderson; 20831 Frank Waters Road;
  3.  * Stanwood, WA  98282.   All rights reserved.
  4.  */
  5.  
  6. /*
  7.  * manage one or two chess game processes
  8.  */
  9.  
  10. #include <sys/types.h>
  11. #include <sys/socket.h>
  12. #include <sys/wait.h>
  13. #include <sys/stat.h>
  14. #include <sys/time.h>
  15. #include <sys/resource.h>
  16. #include <signal.h>
  17. #include <stdio.h>
  18. #include <strings.h>
  19. #include <ctype.h>
  20.  
  21. #include "nchess.h"
  22.  
  23. extern char * gets();
  24.  
  25. int ChessPid[2],
  26.     ChessProcessFDs[2];
  27. FILE * ReadChessProcess[2], * WriteChessProcess[2];
  28. BOOL SigChildInterceptOn = FALSE;
  29. BOOL MachineDebug = FALSE;
  30. char * colorStrings[] = { "black", "white" };
  31.  
  32. /*
  33.  * intercept SIGCHLD
  34.  *
  35.  * print a message for the first chess process that dies and abort the 
  36.  * game.  (note: any change in child status is interpreted as death).
  37.  */
  38. handleSigChild()
  39. {
  40.     int pid;
  41.     union wait status;
  42.  
  43.     while(1) {
  44.     pid = wait3(&status, WNOHANG, (struct rusage *) 0);
  45.     if (pid <= 0)
  46.         return;
  47.     if ( ! GameOver && (pid == ChessPid[BLACK] || pid == ChessPid[WHITE])) {
  48.         Message (pid == ChessPid[WHITE] ?
  49.         "White's process died" :
  50.         "Black's process died" );
  51.         KillMouseActivity();
  52.         GameOver = TRUE;
  53.         Mouse = LOCKED;
  54.     }
  55.     }
  56. }
  57.  
  58. /*
  59.  * have a chess process make the first move.
  60.  *
  61.  * note: with the wonderful unix chess program, "first" also implies
  62.  * playing the white pieces.  nonetheless, color is an argument to this
  63.  * function in case we ever find out how to get around this problem.
  64.  */
  65. void
  66. MachineFirst(color)
  67.     int color;
  68. {
  69.     fputs("first\n", WriteChessProcess[color]);
  70.     fflush(WriteChessProcess[color]);
  71.     if (MachineDebug)
  72.     fprintf(stderr, "sent to %s: first\n", colorStrings[color]);
  73. }
  74.  
  75. /*
  76.  * open a pipe to a chess game process
  77.  *
  78.  * startIt indicates whether the process should be sent the "first"
  79.  * command.
  80.  */
  81. void
  82. InitChessProcess(cp, color, startIt)
  83.     char ** cp;
  84.     int color;
  85.     BOOL startIt;
  86. {
  87.     int sv[2];
  88.     char c[128];
  89.  
  90.     if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) {
  91.     fputs("socketpair failed\n", stderr);
  92.     exit(1);
  93.     }
  94.     if ((ChessPid[color] = fork()) == 0) {
  95.     dup2(sv[0], 0);
  96.     dup2(sv[0], 1); 
  97.     chdir("/tmp");        /* so that "chess.out" can always be written */
  98.     execvp(cp[0], cp);
  99.     puts("exec");
  100.     fflush(stdout);
  101.     _exit(1);
  102.     }
  103. /*    dup2(sv[1], 0);
  104.     dup2(sv[1], 1); */
  105.     /* want to intercept SIGCHLD */
  106.     if ( ! SigChildInterceptOn) {
  107.     SigChildInterceptOn = TRUE;
  108.     signal(SIGCHLD, handleSigChild);
  109.     }
  110.     ChessProcessFDs[color] = (1 << sv[1]);
  111.     ReadChessProcess[color] = fdopen(sv[1], "r");
  112.     WriteChessProcess[color] = fdopen(sv[1], "w");
  113.     setbuf(ReadChessProcess[color], (char *) 0);
  114.     /* 
  115.      * eat the "Chess" prompt 
  116.      * note: if the child's exec failed,
  117.      * catch the "exec" prompt and give up
  118.      */
  119.     fgets(c, sizeof(c), ReadChessProcess[color]);
  120.     if (strcmp(c, "exec\n") == 0) {
  121.     KillChessProcesses();
  122.     fprintf(stderr, "exec of %s failed\n", cp[0]);
  123.     exit(1);
  124.     }
  125.     /* set algebraic notation mode */
  126.     fputs("alg\n", WriteChessProcess[color]);
  127.     fflush(WriteChessProcess[color]);
  128.     if (MachineDebug)
  129.     fprintf(stderr, "sent to %s: alg\n", colorStrings[color]);
  130.     if (startIt)
  131.     MachineFirst(color);
  132. }
  133.  
  134.  
  135. /*
  136.  * reap one or more chess process
  137.  */
  138. void
  139. ReapChessProcesses()
  140. {
  141.     union wait status;
  142.  
  143.     while (wait3(&status, WNOHANG, (struct rusage *) 0) >= 0)
  144.     ;
  145. }
  146.  
  147. /*
  148.  * kill any and all chess processes
  149.  */
  150. void
  151. KillChessProcesses()
  152. {
  153.     signal(SIGCHLD, SIG_IGN);
  154.     if (ChessPid[BLACK])
  155.     kill(ChessPid[BLACK], SIGKILL);
  156.     if (ChessPid[WHITE])
  157.     kill(ChessPid[WHITE], SIGKILL);
  158.     ReapChessProcesses();
  159. }
  160.  
  161. /*
  162.  * get a move from a chess process 
  163.  * 
  164.  * return 1 if a move was successfully obtained, 0 if not.
  165.  */
  166. int
  167. GetMachineMove(move, color)
  168.     Move * move;
  169.     int color;
  170. {
  171.     char c[256], c2[256];
  172.     char file1, file2;
  173.     int rank1, rank2;
  174.  
  175.     if (fgets(c, sizeof(c), ReadChessProcess[color]) == (char *) 0) 
  176.     return(0);
  177.     if (MachineDebug)
  178.     fprintf(stderr, "rec'd from %s: %s", colorStrings[color], c);
  179.     /* look for special announcements */
  180.     if (strcmp(c, "Forced mate\n") == 0) {
  181.     Message(color == WHITE ? 
  182.         "White announces forced mate" :
  183.         "Black announces forced mate");
  184.     return(0);
  185.     } 
  186.     if (strcmp(c, "Resign\n") == 0) {
  187.     Message(color == WHITE ? "White resigns" : "Black resigns");
  188.     DoResignation(color);
  189.     Mouse = LOCKED;
  190.     return(0);
  191.     } 
  192.     if (strcmp(c, "Illegal move\n") == 0) {
  193.     Message("Internal botch - illegal move detected");
  194.     return(0);
  195.     } 
  196.     if (strncmp(c, "done", 4) == 0) {
  197.     return(0);
  198.     }
  199.     if (strncmp(c, "White wins", 10) == 0
  200.     || strncmp(c, "Black wins", 10) == 0) {
  201.     c[10] = '\0';
  202.     Message(c);
  203.     GameOver = TRUE;
  204.     Mouse = LOCKED;
  205.     return(0);
  206.     }
  207.     /* e.g., 1. d2d4 */
  208.     if (sscanf(c, "%*d. %c%d%c%d", &file1, &rank1, &file2, &rank2) == 4
  209.     /* e.g., 1. ... d2d4 */
  210.     || sscanf(c, "%*d. ... %c%d%c%d", &file1, &rank1, &file2, &rank2) == 4) {
  211.     move->x1 = file1 - (isupper(file1) ? 'A' : 'a');
  212.     move->y1 = 8 - rank1;
  213.     move->x2 = file2 - (isupper(file2) ? 'A' : 'a');
  214.     move->y2 = 8 - rank2;
  215.     /* TBD: possible non-queen pawn promotion 
  216.      * (the existing chess program doesn't implement this) */
  217.     move->newPieceType = (int) QUEEN;
  218.     return(1);
  219.     } else {
  220.     strcpy(c2, color == WHITE ? "White announces: " : "Black announces: ");
  221.     Message(strncat(c2, c, sizeof(c2) - strlen(c2) - 2));
  222.     if (strncmp(c, "Draw", 4) == 0) {
  223.         GameOver = TRUE;
  224.         Mouse = LOCKED;
  225.     }
  226.     return(0);
  227.     }
  228. }
  229.  
  230. /*
  231.  * send a move to a chess process
  232.  *
  233.  * note: if the process responds with a move too quickly, we won't 
  234.  * get another select() trigger to get its move.  thus, we need to
  235.  * check for the availability of a move when the echo is received.
  236.  */
  237. void
  238. SendMachineMove(move, color)
  239.     Move * move;
  240.     int color;
  241. {
  242.     char c[128];
  243.  
  244.     if (move->x1 != move->x2
  245.     && GetSquare(move->x1, move->y1)->type == PAWN
  246.     && GetSquare(move->x2, move->y2)->type == NULLPC) {
  247.     /* re-encode en passant captures as horizontal moves */
  248.     fprintf(WriteChessProcess[color], "%c%d%c%d\n", 
  249.         move->x1 + 'a', 8 - move->y1, 
  250.         move->x2 + 'a', 8 - move->y1);
  251.     if (MachineDebug)
  252.         fprintf(stderr, "sent move to %s: %c%d%c%d\n", 
  253.         colorStrings[color],
  254.         move->x1 + 'a', 8 - move->y1, 
  255.         move->x2 + 'a', 8 - move->y1);
  256.     } else {
  257.     fprintf(WriteChessProcess[color], "%c%d%c%d\n", 
  258.         move->x1 + 'a', 8 - move->y1, 
  259.         move->x2 + 'a', 8 - move->y2);
  260.     if (MachineDebug)
  261.         fprintf(stderr, "sent move to %s: %c%d%c%d\n", 
  262.         colorStrings[color],
  263.         move->x1 + 'a', 8 - move->y1, 
  264.         move->x2 + 'a', 8 - move->y2);
  265.     }
  266.     fflush(WriteChessProcess[color]);
  267.     fgets(c, sizeof(c), ReadChessProcess[color]); /* eat the move echo */
  268.     if (MachineDebug)
  269.     fprintf(stderr, "rec'd from %s: %s", colorStrings[color], c);
  270. }
  271.  
  272. /*
  273.  * undo the last machine move and our move 
  274.  */
  275. void
  276. MachineUndo(color)
  277. {
  278.     fputs("remove\n", WriteChessProcess[color]);
  279.     fflush(WriteChessProcess[color]);
  280.     if (MachineDebug)
  281.     fprintf(stderr, "sent to %s: remove\n", colorStrings[color]);
  282.     UnDoMove();
  283.     UnDoMove();
  284. }
  285.  
  286. /*
  287.  * set up the board 
  288.  * (as noted above: with the existing unix chess program, there is no 
  289.  * apparent way (short of deciphering the chess.out format, which is 
  290.  * totally un-fun) to inform the chess program whose turn it is and 
  291.  * which color it is supposed to play - it assumes that white always 
  292.  * is the first to move.  
  293.  */
  294.  
  295. char whitePieceChars[] = { 'p', 'n', 'b', 'r', 'q', 'k', ' ' };
  296. char blackPieceChars[] = { 'P', 'N', 'B', 'R', 'Q', 'K', ' ' };
  297.  
  298. /*
  299.  * set up a board state against the machine.
  300.  * returns TRUE if successful, FALSE otherwise
  301.  */
  302. BOOL
  303. MachineSetup(color)
  304.     int color;
  305. {
  306.     register int x, y;
  307.     Square * sqp;
  308.     char c[128];
  309.  
  310.     fputs("setup\n", WriteChessProcess[color]);
  311.     if (MachineDebug)
  312.     fprintf(stderr, "sent to %s:\nsetup\n", colorStrings[color]);
  313.     for (y = 0 ; y < 8 ; y++) {
  314.     for (x = 0 ; x < 8 ; x++) {
  315.         sqp = GetSquare(x, y);
  316.         putc(sqp->color == WHITE ? 
  317.         whitePieceChars[(int) sqp->type] :
  318.         blackPieceChars[(int) sqp->type], 
  319.         WriteChessProcess[color]);
  320.         if (MachineDebug)
  321.         fputc(sqp->color == WHITE ? 
  322.             whitePieceChars[(int) sqp->type] :
  323.             blackPieceChars[(int) sqp->type], 
  324.             stderr);
  325.     }
  326.     putc('\n', WriteChessProcess[color]);
  327.     if (MachineDebug)
  328.         fputc('\n', stderr);
  329.     }
  330.     fflush(WriteChessProcess[color]);
  331.     fgets(c, sizeof(c), ReadChessProcess[color]);
  332.     if (MachineDebug)
  333.     fprintf(stderr, "rec'd from %s: %s", colorStrings[color], c);
  334.     return(strcmp(c, "Setup successful\n") == 0);
  335. }
  336.  
  337. /*
  338.  * have a chess process save the game as "/tmp/chess.out".
  339.  * return the size of chess.out.
  340.  */
  341. int
  342. MachineSave(color)
  343.     int color;
  344. {
  345.     FILE * saveFile;
  346.     struct stat saveFileStatus;
  347.     int saveFileSize;
  348.     int retryCount = 0;
  349.  
  350.     fputs("save\n", WriteChessProcess[color]);
  351.     fflush(WriteChessProcess[color]);
  352.     if (MachineDebug)
  353.     fprintf(stderr, "sent to %s: save\n", colorStrings[color]);
  354.     sleep((unsigned) 1);
  355.     /* wait for the chess process to create chess.out */
  356.     do {
  357.     if ((saveFile = fopen("/tmp/chess.out", "r")) == (FILE *) 0) 
  358.         sleep((unsigned) 2); 
  359.     } while(saveFile == (FILE *) 0 && ++retryCount < 10);
  360.     if (saveFile == (FILE *) 0) {
  361.     Message("Can't open chess.out!");
  362.     return(-1);
  363.     }
  364.     saveFileStatus.st_size = -1;
  365.     /* wait until chess.out stops growing */
  366.     do {
  367.     sleep((unsigned) 1);
  368.     saveFileSize = saveFileStatus.st_size;
  369.     fstat(fileno(saveFile), &saveFileStatus);
  370.     } while (saveFileSize != saveFileStatus.st_size);
  371.     fclose(saveFile);
  372.     return(saveFileSize);
  373. }
  374.  
  375. /*
  376.  * restore the game 
  377.  */
  378. void
  379. MachineRestore(color)
  380.     int color;
  381. {
  382.     fputs("restore\n", WriteChessProcess[color]);
  383.     fflush(WriteChessProcess[color]);
  384.     if (MachineDebug)
  385.     fprintf(stderr, "sent to %s: restore\n", colorStrings[color]);
  386. }
  387.  
  388.