🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: gnu.chess
Article #6111

Re: playing gnuchess against another program

#6111
From: Eugene Stark
Date: Sat, 17 Nov 1990 16:16
499 lines
13380 bytes
I wrote a program to do what you are asking, except it was to pit
two chinese checkers programs against each other.  I think slight
modifications to the program would enable it to work with GNUCHESS.
I enclose the source below.  I'd appreciate receiving any changes
that you make that end up doing anything interesting.

						- Gene Stark
						  SUNY at Stony Brook

/*
 * Versus:  A program to connect two Chinese checkers programs together
 *          so they can play against each other in automatic mode.
 *          Utility for the Stony Brook Dept. of Computer Science
 *          1989/90 Student Programming Competition
 *
 * Author:  E.W. Stark (stark@sbcs.sunysb.edu)
 * Date:    10/21/89
 *
 * Copyright (c) 1990 Eugene W. Stark
 * Permission is hereby granted for anyone to freely copy and modify this
 * program, as long as it is not for profit, and as long as my name and
 * copyright notice remain intact on all copies and modified versions.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY.  No author or distributor
 * accepts responsibility to anyone for the consequences of using it
 * or for whether it serves any particular purpose or works at all,
 * unless he says so in writing.
 *
 *
 * Synopsis: To pit two Chinese checkers programs against each other,
 *          when they are potentially running on different machines,
 *          the player having the white pieces first executes the
 *          following:
 *
 *              % versus -w <White command line>
 *
 *          Versus will first create a socket for communicating moves
 *          with the Black program and print its port number.
 *          It will then allocate a pty pair and start up the White
 *          program.  Versus will then goes into a communication loop
 *          in which it transfers moves back and forth between the pty
 *          and the socket.
 *
 *          After the port number has been printed out, the player
 *          having the black pieces executes the following:
 *
 *              % versus -b <hostname> <portno> <Black command line>
 *
 *          Versus attempts to connect to its counterpart, and if successful
 *          allocates a pty pair and invokes the Black program.  It then
 *          goes into a communication loop.
 *
 *          Versus identifies the moves to be transferred to the opposing
 *          program by looking for lines of the form:
 *
 *              @@@<color>: <move>
 *
 *          output on the pty.  When it sees such a line, it sends a line
 *          consisting just of <move> to the socket.
 */

/*
 * Define HPUX if compiling for HP-UX System.
 */

#include <sys/param.h>
#include <sys/types.h>
#include <stdio.h>
#ifdef HPUX
#include <bsdtty.h>
#include <termio.h>
#include <sys/ptyio.h>
#else
#include <sgtty.h>
#endif
#include <signal.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/file.h>

#ifdef HPUX
#define bcopy(a,b,s)	memcpy (b,a,s)
#endif

#define PATHLEN 512
#define MSGSIZ 512

int White;                            /* Are we White or Black? */
char MsgBuf[MSGSIZ];                  /* Buffer for reading and writing */
char PtyName[32], TtyName[32];        /* Names of pty devices */
int Pty;                              /* Master side pty file descriptor */
int Sock0, Sock;                      /* Communication socket id's */
int Port;                             /* Server port number */
char System[64];                      /* Name of server host */

#ifdef HPUX
char PtyProto[] = "/dev/ptym/ptyXY";
char TtyProto[] = "/dev/pty//ttyXY";  /* XY positions must correspond */
#else
char PtyProto[] = "/dev/ptyXY";
char TtyProto[] = "/dev/ttyXY";
#endif

struct mode {
#ifdef HPUX
    struct termio m_termio;
#else
    struct sgttyb m_ttyb;
    struct tchars m_tchars;
#endif
    struct ltchars m_ltchars;
    int m_ldisc;
    int m_lmode;
} OldMode, NewMode;

main(argc, argv)
int argc;
char *argv[];
{
  if (argc <= 2) Usage(argv[0]);
  if (*argv[1] != '-') Usage(argv[0]);
  switch(*(argv[1]+1)) {
  case 'b':
    if (argc <= 4) Usage(argv[0]);
    strcpy(System, argv[2]);
    Port = atoi(argv[3]);
    printf("Invoking Black program...\n");
    SetupSignals();
    MakeBlackSocket();
    GetPty();
    StartPlayer(&argv[4]);
    ComLoop(); /* No return */
  case 'w':
    White++;
    printf("Invoking White program...\n");
    SetupSignals();
    MakeWhiteSocket();
    GetPty();
    StartPlayer(&argv[2]);
    printf("White program started.\n");
    printf("Now execute: %s -b %s %d (Black program command line)\n",
	   argv[0], System, Port);
    AcceptConnection();
    ComLoop(); /* No return */
  default:
    Usage(argv[0]);
  }
}

/*
 * Print a usage error message and die.
 */

Usage(n)
char *n;
{
    printf("Usage: %s -w (White program command line)\n", n);
    printf("or: %s -b hostname portnum (Black program command line)\n", n);
    exit(1);
}

/*
 * Print an error message and die.
 */

Error(fmt, p1, p2, p3, p4, p5, p6)
char *fmt;
{
  printf(fmt, p1, p2, p3, p4, p5, p6);
  close(Sock0); close(Sock);
  exit(1);
}

/*
 * Signal Handler.
 */

SigHandler()
{
  Error("Unexpected signal received.\n");
}

/*
 * Arrange to handle signals.
 */

SetupSignals()
{
	signal (SIGHUP, SigHandler);
	signal (SIGINT, SigHandler);
	signal (SIGQUIT, SigHandler);
	signal (SIGTERM, SigHandler);
}

/*
 * Start up the White or Black program
 */

StartPlayer(argv)
char *argv[];
{
  int f, mypid;
  switch (fork()) {
  case -1:
    Error ("Can't fork subprocess.\n");
  case 0:
    signal (SIGHUP, SIG_DFL);
    signal (SIGINT, SIG_DFL);
    signal (SIGQUIT, SIG_DFL);
    signal (SIGTERM, SIG_DFL);
    mypid = getpid ();
    if ((f = open ("/dev/tty", O_RDWR)) != -1) {
#ifdef HPUX
      setpgrp();  /* Disown any controlling terminal */
#else
      ioctl (f, TIOCNOTTY, (char *)0);
#endif
      close (f);
    }
    if ((f = open (TtyName, O_RDWR)) == -1) {
      printf("Can't open Pty %s\n", TtyName);
      exit (1);
    }
    dup2 (f, 0);
    dup2 (f, 1);
    dup2 (f, 2);
    for (f = NOFILE - 1; f > 2; f--)
      close (f);
    ioctl (0, TIOCSPGRP, &mypid);
#ifdef HPUX
    setpgrp ();
#else
    setpgrp (0, mypid);
#endif
    sprintf(MsgBuf, "SYNC\n");
    write(1, MsgBuf, 5);  /* send synchronization message to parent */
    execvp(argv[0], &argv[0]);
    printf("Can't execute %s\n", argv[0]);
    exit(1);
  default:  /* wait for synchronization message from child process */
    while(1) {
#ifdef DEBUG
      printf("Waiting for program to start.\n");
#endif
      if (read(Pty, MsgBuf, 5) <= 0) {
	  sleep(1);
	  continue;
      }
      break;
    }
  }
}

/*
 * Perform communication loop until interrupted or partner dies.
 */
 
ComLoop()
{
  int r, w, x = 0;
  extern int errno;

  while (1) {
    r = (1 << Sock) | (1 << Pty);
    if (select (32, &r, NULL, NULL, 0) == -1)
      Error("Error in select.\n");
#ifdef DEBUG
    printf("Select returns %d\n", r);
#endif
    if (r & 1 << Sock)
      SocketToPTY(Sock, Pty);
    if (r & 1 << Pty)
      PTYToSocket(Sock, Pty);
  }
}

/*
 * Allocate a pty pair for communication with program.
 */

GetPty()
{
    char *p, *l, *d;
    int i, f, tf;

    strcpy (PtyName, PtyProto);
    strcpy (TtyName, TtyProto);
    for (p = PtyName, i = 0; *p != 'X'; ++p, ++i) ;
    for (l = "pqr"; *p = *l; ++l) {
	for (d = "0123456789abcdef"; p[1] = *d; ++d) {
	    if ((f = open (PtyName, O_RDWR)) != -1) {
		TtyName[i] = p[0];
		TtyName[i+1] = p[1];
		if ((tf = open (TtyName, O_RDWR)) != -1) {
		    close (tf);
		    Pty = f;
		    fcntl (f, F_SETFL, O_NDELAY);
		    GetTTY(f, &OldMode);
		    SetMode(&OldMode, &NewMode);
		    SetTTY(f, &NewMode);
		    return;
		}
		close (f);
	    }
	}
    }
    Error("Can't get a Pty.\n");
}

GetTTY (fd, mp)
struct mode *mp;
{
#ifdef HPUX
    ioctl (fd, TCGETA, &mp->m_termio);
#else
    ioctl (fd, TIOCGETP, &mp->m_ttyb);
    ioctl (fd, TIOCGETC, &mp->m_tchars);
    ioctl (fd, TIOCGETD, &mp->m_ldisc);
#endif
    ioctl (fd, TIOCGLTC, &mp->m_ltchars);
    ioctl (fd, TIOCLGET, &mp->m_lmode);
}

SetTTY (fd, mp)
struct mode *mp;
{
  int zero = 0;
#ifdef HPUX
    ioctl (fd, TCSETAW, &mp->m_termio);
    ioctl (fd, TIOCTTY, &zero);
#else
    ioctl (fd, TIOCSETP, &mp->m_ttyb);
    ioctl (fd, TIOCSETC, &mp->m_tchars);
    ioctl (fd, TIOCSETD, &mp->m_ldisc);
#endif
    ioctl (fd, TIOCSLTC, &mp->m_ltchars);
    ioctl (fd, TIOCLSET, &mp->m_lmode);
}

SetMode (op, np)
struct mode *op, *np;
{
    *np = *op;
#ifdef HPUX
     np->m_termio.c_line = 0;
     np->m_termio.c_iflag &= ~INLCR;
     np->m_termio.c_iflag &= ~ICRNL;
     np->m_termio.c_oflag &= ~OCRNL;
     np->m_termio.c_oflag &= ~ONLCR;
     np->m_termio.c_lflag &= ~ECHO;
     np->m_termio.c_iflag &= ~(IXOFF|IXON);
     np->m_termio.c_cc[VINTR] = -1;
     np->m_termio.c_cc[VQUIT] = -1;
#else
    np->m_ttyb.sg_flags &= ~(CRMOD|ECHO);
/*    np->m_ttyb.sg_flags |= CBREAK; */
    np->m_tchars.t_intrc = -1;
    np->m_tchars.t_quitc = -1;
    np->m_tchars.t_startc = -1;
    np->m_tchars.t_stopc = -1;
#endif
    np->m_ltchars.t_suspc = -1;
    np->m_ltchars.t_dsuspc = -1;
    np->m_ltchars.t_flushc = -1;
    np->m_ltchars.t_lnextc = -1;
}

MakeWhiteSocket ()
{
    register s;
    int id, len;
    struct sockaddr_in a;

    gethostname(System, sizeof(System));
    if ((id = socket (AF_INET, SOCK_STREAM, 0)) == -1)
        Error("Can't create new socket.\n");
    a.sin_family = AF_INET;
    a.sin_addr.s_addr = INADDR_ANY;
    a.sin_port = 0;
    if (bind (id, (struct sockaddr *)&a, sizeof(a)) == -1)
      Error("Can't bind socket to address.\n");
    len = sizeof(a);
    if (getsockname(id, (struct sockaddr *)&a, &len) == -1)
      Error("Can't get socket name.\n");
    if (listen (id, 5) == -1)
        Error("Unable to listen on socket.\n");
    Sock0 = Sock = id;
    Port = htons(a.sin_port);
}

MakeBlackSocket ()
{
    int id;
    struct sockaddr_in a;
    struct hostent *h;

    if ((id = socket (AF_INET, SOCK_STREAM, 0)) == -1)
      Error("Can't create new socket.\n");
    a.sin_family = AF_INET;
    a.sin_port = htons(Port);
    if ((h = gethostbyname(System)) == 0)
      Error("Unknown host: %s\n", System);
    bcopy(h->h_addr, &a.sin_addr, h->h_length);
    if (connect (id, (struct sockaddr *)&a, sizeof(a)) == -1)
      Error("Can't connect to White program.\n");
    Sock0 = Sock = id;
}

/*
 * Accept a connection on Sock0
 */

AcceptConnection()
{
  struct sockaddr_in a;
  int len = sizeof (a);
  printf("Waiting for connection to Black program...\n");
  if ((Sock = accept (Sock0, &a, &len)) == -1)
    Error("Error in accepting connection.\n");
  printf("Got connection.\n");
}

/*
 * Transfer data from PTY to socket
 */

PTYToSocket(s, f)
{
  int len;
  char *mbp;
  static char linebuf[MSGSIZ], *lbp = linebuf;
#ifdef DEBUG
  printf("PtoS called.\n");
#endif
  if((len = read(f, MsgBuf, MSGSIZ)) == -1) {
    if (errno == EWOULDBLOCK) {
#ifdef DEBUG
      printf("No data there.\n");
#endif
      return;
    }
    Error("Error reading from Pty.\n");
  }
  if(len == 0)
    Error("End of file on Pty.\n");
  write(1, MsgBuf, len);
  mbp = MsgBuf;
  for ( ; len > 0; len--) {
    if (lbp - linebuf >= MSGSIZ-1) lbp--;   /* Truncate long lines */
    if ((*lbp++ = *mbp++) != '\n') continue;
    *lbp = '\0';
    ProcessLine(s, linebuf, lbp);
    lbp = linebuf;
  }
}

/*
 * Determine if line has format @@@<color>:<move>\n
 * If so, send <move>\n to opponent
 */

ProcessLine(fd, buf, ebuf)
int fd;
char *buf, *ebuf;
{
  if (*buf++ == '@')
    if (*buf++ == '@')
      if (*buf++ == '@') {
	while (*buf != ':') if (*buf++ == '\n') return;
	buf++;
	printf("=> %s", buf);
	fflush(stdout);
	write(fd, buf, ebuf - buf);
      }
}

/*
 * Transfer data from socket to PTY
 */

SocketToPTY (s, f)
{
  struct sockaddr_in a;
  int len;
#ifdef DEBUG
  printf("StoP called.\n");
#endif
  if ((len = read (s, MsgBuf, MSGSIZ)) == -1)
    Error("Error reading from socket.\n");
  if(len == 0)
    Error("End of file on socket.\n");
  if (write(f, MsgBuf, len) < len) Error("Incomplete write\n"); 
#ifdef DEBUG
  write (1, MsgBuf, len);
#endif
}
Technical Details
Message-ID: <1990Nov17.161610.27067@sbcs.sunysb.edu>
Path: arc1-ca.pugleaf.net!gmdzi!unido!mcsun!sunic!uupsi!rpi!zaphod.mps.ohio-state.edu!mips!cs.uoregon.edu!ogicse!emory!gatech!purdue!haven!adm!cmcl2!sbcs!usenet
References: <9011160518.AA22499@ucbvax.Berkeley.EDU>

Show Full Headers
Complete Article Headers
X-Google-Language: ENGLISH,ASCII-7-bit
X-Google-Thread: 10d71d,d6b8ff302278d7a3
X-Google-Attributes: gid10d71d,public
X-Google-ArrivalTime: 1990-11-17 08:16:10 PST
Path: arc1-ca.pugleaf.net!gmdzi!unido!mcsun!sunic!uupsi!rpi!zaphod.mps.ohio-state.edu!mips!cs.uoregon.edu!ogicse!emory!gatech!purdue!haven!adm!cmcl2!sbcs!usenet
From: stark@sbstark (Eugene Stark)
Newsgroups: gnu.chess
Subject: Re: playing gnuchess against another program
Message-ID: <1990Nov17.161610.27067@sbcs.sunysb.edu>
Date: 17 Nov 90 16:16:10 GMT
References: <9011160518.AA22499@ucbvax.Berkeley.EDU>
Sender: usenet@sbcs.sunysb.edu (Usenet poster)
Reply-To: stark@sbstark (Eugene Stark)
Organization: SUNY at Stony Brook Computer Science Dept.
Lines: 499
Posted: Sat Nov 17 17:16:10 1990