Article View: gnu.chess
Article #6111Re: playing gnuchess against another program
From: Eugene Stark
Date: Sat, 17 Nov 1990 16:16
Date: Sat, 17 Nov 1990 16:16
499 lines
13380 bytes
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!usenetReferences:
<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