[comp.sources.games] v12i036: netwhist - multiplayer internet whist game, Part01/01

billr@saab.CNA.TEK.COM (Bill Randle) (02/20/91)

Submitted-by: Bharat Mediratta <bharat@computing-maths.cardiff.ac.uk>
Posting-number: Volume 12, Issue 36
Archive-name: netwhist/Part01
Environment: INET sockets, curses

	[I haven't tried this one yet.  -br]

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 1)."
# Contents:  README MANIFEST INSTALL README_ORIG lib lib/netwhist_info
#   nw src src/Makefile src/interface.c src/interface.h src/netwhist.c
#   src/netwhist.h src/netwhistd.c src/utils.c src/utils.h
# Wrapped by billr@saab on Tue Feb 19 14:35:42 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(411 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
X
X
X			  -- NetWhist 0.9 --
X
X		      By Bharat "Bart" Mediratta
X		       Colgate University, '92
X
X
X			     Introduction
X			     ------------
X
X	NetWhist is an interactive multiplayer game that allows you
Xto play German Whist (a simple whist variant) against another person
Xon a different machine.  It was written while I (the author) was at 
XThe University of Wales, College of Cardiff in Cardiff, South Wales.  
X
END_OF_FILE
if test 411 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MANIFEST'\"
else
echo shar: Extracting \"'MANIFEST'\" \(610 characters\)
sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
X   File Name		Archive #	Description
X-----------------------------------------------------------
X INSTALL                    1	
X MANIFEST                   1	This shipping list
X README                     1	
X README_ORIG                1	
X lib                        1	
X lib/netwhist_info          1	
X nw                         1	
X src                        1	
X src/Makefile               1	
X src/interface.c            1	
X src/interface.h            1	
X src/netwhist.c             1	
X src/netwhist.h             1	
X src/netwhistd.c            1	
X src/utils.c                1	
X src/utils.h                1	
END_OF_FILE
if test 610 -ne `wc -c <'MANIFEST'`; then
    echo shar: \"'MANIFEST'\" unpacked with wrong size!
fi
# end of 'MANIFEST'
fi
if test -f 'INSTALL' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'INSTALL'\"
else
echo shar: Extracting \"'INSTALL'\" \(1757 characters\)
sed "s/^X//" >'INSTALL' <<'END_OF_FILE'
XThere are a few steps to be taken to install the program properly.  
X
X1) Edit the Makefile in the src directory and adjust the HOMEDIR and LIBDIR
X   flags for the game.  The game comes in three parts, a shell script,
X   and two executables.  The shell script will go in the HOMEDIR which
X   could be something like /usr/games; a directory that is accessible
X   by everybody.  The executables will go in the LIBDIR, a directory
X   that is accessible, but is mainly used for support software (ie 
X   /usr/games/lib)
X
X2) Type 'make install' to compile and install the executables in the appropriate
X   directory $(LIBDIR)
X
X3) Copy the file 'netwhist_info' into $(LIBDIR) and adjust the modes
X   on it so that it is readable by everybody (755)
X
X4) Edit the file called 'nw' and adjust the line where it says 'set
X   whistdir' to $(LIBDIR).  Since this game was designed to run over
X   internet with a shared file server, it must know which machine is
X   acting as the server.  This shell script keeps track of the server
X   in a file called 'daemon.'  This file must be on the shared file 
X   server if the program is going to work properly, as that way all
X   the machines know which one is the file server.  If you have a
X   temporary directory (e.g. /tmp) that is shareable by all machines
X   on the network, then adjust the line that reads 'set daemon' to a 
X   given file in that directory.  Otherwise, you can leave the line 
X   the way it is and make this script setuid.  I suggest, if you do
X   this that you make the owner of this script something innocuous,
X   like 'games' so that there is no possible breach of security.  You
X   may need to fiddle with the modes a bit to get it working properly.
X
X5) Install the file 'nw' into $(HOMEDIR) 
X
X
X  
X
X
X	
END_OF_FILE
if test 1757 -ne `wc -c <'INSTALL'`; then
    echo shar: \"'INSTALL'\" unpacked with wrong size!
fi
# end of 'INSTALL'
fi
if test -f 'README_ORIG' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README_ORIG'\"
else
echo shar: Extracting \"'README_ORIG'\" \(234 characters\)
sed "s/^X//" >'README_ORIG' <<'END_OF_FILE'
X
XNetWhist 0.9
X------------
X
X
XThe files should arrive in the following structure:
X
Xnetwhist: 
XREADME
XINSTALL
Xlib/		
Xnw*
Xsrc/
X
Xlib:
Xnetwhist_info
X
Xsrc:
XMakefile
Xinterface.c
Xinterface.h
Xnetwhist.c
Xnetwhist.h
Xnetwhistd.c
Xutils.c
Xutils.h
X
END_OF_FILE
if test 234 -ne `wc -c <'README_ORIG'`; then
    echo shar: \"'README_ORIG'\" unpacked with wrong size!
fi
# end of 'README_ORIG'
fi
if test ! -d 'lib' ; then
    echo shar: Creating directory \"'lib'\"
    mkdir 'lib'
fi
if test -f 'lib/netwhist_info' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'lib/netwhist_info'\"
else
echo shar: Extracting \"'lib/netwhist_info'\" \(4827 characters\)
sed "s/^X//" >'lib/netwhist_info' <<'END_OF_FILE'
X
X
X			  -- NetWhist 0.9 --
X
X		      By Bharat "Bart" Mediratta
X		       Colgate University, '92
X
X
X			     Introduction
X			     ------------
X
X	NetWhist is an interactive multiplayer game that allows you
Xto play German Whist (a simple whist variant) against another person
Xon a different machine.  It was written while I (the author) was at 
XThe University of Wales, College of Cardiff in Cardiff, South Wales.  
X
X
X			Rules of German Whist
X			---------------------
X
X	The rules to German whist are very easy.  There are two
Xplayers, and each starts out with 7 cards, dealt from a shuffled deck.
XThe top card on the deck is displayed at every turn (until cards run
Xout.)  The first top card indicates the trump suit for the rest of the
Xgame.  Then, the non-dealer (in this case, the person who joins the
Xgame last) gets to play a card.  Each player lays down a card, and the
Xhigher card wins the trick.  The one rule in laying down a card is
Xthat if you are not leading a card, you must follow the suit that was
Xlead if it is possible.  Therefore, if a Heart is lead and you have a
XHeart in your hand then you MUST play it.  The order of cards is as
Xfollows: 
X		
X			Ace of the trump suit
X				  |
X				  V
X			 2 of the trump suit
X		     Ace of the suit that is lead
X				  |
X				  V
X		      2 of the suit that is lead
X			   All other cards
X
X
X	Therefore, if the trump suit of the game is Spades, and the
Xcard that is lead is a 5 of Clubs, then the following cards will win
Xthe trick: 
X	Any spade, any club higher than the 5 of Clubs
X
XThe following will lose the trick:
X	Any club lower than the 5 of Clubs, and any card that is
Xnon-Club and non-Spade.
X
X	The winner of the trick takes the top card (which is face up)
Xand the loser takes the next card (which is unknown.)  The goal of the
Xgame is very simple - to win as many tricks as you can by the end of
Xthe game (when cards run out.) 
X
X
X
X			  NetWhist Commands
X			  -----------------
X	Because different players like to see their hands ordered
Xdifferently, I have included four different hand styles.  The first is
Xa relatively normal style and is the default:
X
XExample:
X   Your hand: 2H 7H 4D TD 8C QC KC
X
XThe second style is very similar to the first, the only difference
Xbeing there is a gap between the suits to make recognition a little
Xeasier.  This style is selected with the -s option.
X
XExample:
X   Your hand: 2H 7H     4D TD     8C QC KC
X
XThe third one looks more like a bridge hand, and is selected with the
X-l option.
X
XExample:
X   Your hand: 
X   S:	-
X   H:	2 7
X   D:	4 T
X   C:   8 Q K
X
XThe fourth style is the standard bridge hand style.  It is selected
Xwith the -b option.
X
XExample:
X   Your hand: 
X   S -
X   H 27
X   D 4T
X   C 8QK
X
X	When the game starts, it will prompt you for your name and
Xthen will attempt to find other people to play against you.
XCurrently, the game doesn't let you choose who you wish to play
Xagainst, but perhaps later versions of the game will do so.  Once an
Xopponent has been found, play begins.  NetWhist will display a few
Xstatus lines with information.
X
XExample:
X
X   .--- Round number
X   |
X   |   .----------.------ Tricks one on both sides
X   |   |          |
X   V   V          V
X   1: You 0 - Opponent 0
X   Top Card King of Spades (Deck 38)    <--- Top card and number left in deck.
X   Your hand: 2H 7H 4D TD 8C QC KC
X   Your play:        ^
X		     |
X		     `---- Cards in your hand (in shorthand)
X
X	To play a card, simply type it as it appears in your hand.
XThe game will not allow you to play a card that you do not have.  When
Xthere are no more cards left in your hand the game is over.
X	To send a message to your opponent, simply type a double-quote
X(") followed by a text message and return.  This is only possible at
Xthe 'Your play:' prompt.  To quit at any time simply type 'quit' at
Xthe prompt.
X
X				Thanks
X				------
X
X	My thanks go to all the people who have motivated (and helped)
Xme to write this program.  In particular:
X
X	Nick Merriam (nam@uk.ac.ic.doc) 
X		For teaching me how to play the game and getting me 
X		interested in it (and other whist variants!)
X
X	Vaughan Marks (marksv@uk.ac.man.cs.p4)
X		For teaching me some of the more subtle strategies
X		in the game and staying up till 3 in the morning to
X		make sure I learned them.
X
X	Tom Boutell (boutell@edu.udel.it.freezer)
X		For writing The Broken Throne, which gave me a few
X		insights into writing a good network game.  He also
X		provided me (through his source code) with some PD
X		socket(2) routines that I couldn't have written this
X		without.  Thanks, Dave.
X
X
X				 Bugs
X				 ----
X
X	There are none.  Hah, just kidding.  This is a beta release,
Xso I'm sure it's crawling with the little critters.  Bug reports will
Xbe smiled at, and hopefully acted upon.
X
X
X
X		Cheers!
X
X		Bharat "Bart" Mediratta
X		bharat@uk.ac.cf.cm 		(until June)
X		bmediratta@earn.colgateu 	(after that)
END_OF_FILE
if test 4827 -ne `wc -c <'lib/netwhist_info'`; then
    echo shar: \"'lib/netwhist_info'\" unpacked with wrong size!
fi
# end of 'lib/netwhist_info'
fi
if test -f 'nw' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'nw'\"
else
echo shar: Extracting \"'nw'\" \(556 characters\)
sed "s/^X//" >'nw' <<'END_OF_FILE'
X#!/bin/csh -f 
X#
X# nw: A shell script to make sure that the game is started
X#     up on the right host.  I'll get rid of this when I 
X#     figure out how to query the network properly.
X#
Xset whistdir = ~bharat/bin/src/netwhist/lib
Xset daemon = $whistdir/daemon
Xset game = $whistdir/netwhist
Xset nogame = 1
X
X	if (-r $daemon) then
X		set host = `cat $daemon`
X		if ("`$game -v $host`" != "") set nogame = 0
X	endif
X
X	if ($nogame) then
X		set host = `hostname`
X		echo 'Starting NetWhist Daemon on your machine.'
X		echo $host > $daemon
X	endif
X
X	$game $* -h $host
END_OF_FILE
if test 556 -ne `wc -c <'nw'`; then
    echo shar: \"'nw'\" unpacked with wrong size!
fi
# end of 'nw'
fi
if test ! -d 'src' ; then
    echo shar: Creating directory \"'src'\"
    mkdir 'src'
fi
if test -f 'src/Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/Makefile'\"
else
echo shar: Extracting \"'src/Makefile'\" \(532 characters\)
sed "s/^X//" >'src/Makefile' <<'END_OF_FILE'
XOBJECTS = interface.o utils.o
XINCLUDES = netwhist.h interface.h utils.h
XHOMEDIR= /home/scullion/bharat/bin/src/netwhist
XLIBDIR = $(HOMEDIR)/lib
XCFLAGS = -g
X
Xall: netwhist netwhistd
X
Xnetwhist: netwhist.o $(OBJECTS) $(INCLUDES)
X	cc netwhist.o interface.o utils.o -o netwhist -O
X
Xnetwhistd: netwhistd.o $(OBJECTS) $(INCLUDES)
X	cc netwhistd.o $(OBJECTS) -o netwhistd -O
X
Xclean: netwhist
X	rm -f *.o
X	rm -f netwhist
X	rm -f netwhistd
X
Xinstall: netwhist netwhistd
X	install -s netwhist $(LIBDIR)
X	install -s netwhistd $(LIBDIR)
X	make clean	
END_OF_FILE
if test 532 -ne `wc -c <'src/Makefile'`; then
    echo shar: \"'src/Makefile'\" unpacked with wrong size!
fi
# end of 'src/Makefile'
fi
if test -f 'src/interface.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/interface.c'\"
else
echo shar: Extracting \"'src/interface.c'\" \(8379 characters\)
sed "s/^X//" >'src/interface.c' <<'END_OF_FILE'
X/* interface.c: Socket communications support& medium- level message
X * passing functions. Copyright (C) 1990 Tom Boutell on original portions.
X * All low- level socket code drawn with appreciation from:
X * SOCK.C
X * Copyright (C)1989 Dr Evil Laboratories
X * This code written by Ray Moody, Roy Riggs, Mitch Adler,
X * Bill Burdick, and Steven Grady
X * No one makes any guarantees about anything.  This file maybe 
X * freely distributed and modified as long as this header remains intact.  
X */
X
X/*
X * Only modifications made to Boutell's code (that amount to anything) are that
X * read_player and write_player are writing integers, not chars.
X *    -BM 1/24/91
X */
X 
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/time.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <string.h>
X#include <ctype.h>
X#include <signal.h>
X#include <netdb.h>
X#include <varargs.h>
X#include <errno.h>
X
X#include "netwhist.h"
X#include "interface.h"
X
X/* #define DEBUG */
X
X#ifdef DEBUG
X#define debug printf
X#else
X#define debug 0+
X#define perror 0+
X#endif
X
Xfd_set active;
Xint playerFd;
X
Xstruct sockaddr_in sc_in;
Xint s;
Xchar *curhostname = "";
X
X/* - PD Socket code begins here.
X * init_socket() - intialize our socket, port is the port number to use
X *                 call this once at the beginning of your code
X */
X
Xint init_socket(port)
X     int port;
X{
X	setbuf(stdout, (char *)0);
X	if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
X		perror("socket");
X		return 0;
X	}
X	sc_in.sin_family = AF_INET;
X	sc_in.sin_addr.s_addr = INADDR_ANY;
X	sc_in.sin_port = htons((u_short) port);
X	if (bind(s, (struct sockaddr *) &sc_in, sizeof(sc_in)) < 0) {
X		perror("bind");
X		return 0;
X	}
X	if (listen(s, 5) < 0) {
X		perror("listen");
X		return 0;
X	}
X
X	FD_ZERO(&active);
X
X	return 1;
X}
X
X
X/*
X * disconnect_all() - throws everyone off
X */
X
Xint disconnect_all()
X{
X	register int i;
X	
X	for (i = 0; i < FD_SETSIZE; i++) {
X		if (FD_ISSET(i, &active))
X			(void) disconnect(i);
X	}
X	return 1;
X}
X
X
X/*
X * shut-down -- kills all connections and exits the pgm
X */
X
Xint shut_down()
X{
X	(void) disconnect_all();
X	exit(0);
X}
X
X
X/* hostfrom() - returns a string containing an ascii name for the host
X *              that the passed socket s is connected to.  Note that the
X *              string is in static space.  If you want to munge with it,
X *              make a copy.
X */
X
Xchar *hostfrom(i)
X	int i;
X{
X	struct sockaddr_in from;
X	int fromlen = sizeof(from);
X	struct hostent *host;
X	struct in_addr addr;
X
X	if (getpeername(i, &from, &fromlen) < 0) {
X		perror("getpeername");
X		return NULL;
X	}
X	
X	addr = from.sin_addr;
X	if ((host = gethostbyaddr(&addr, sizeof(addr), AF_INET)) == NULL) {
X		debug("gethostbyaddr failed");
X		return NULL;
X	}
X	    
X	return curhostname = host->h_name;
X}
X
X
X/*
X * hostname() - returns curhostname
X */
X
Xchar *hostname()
X{
X	return curhostname;
X}
X
X
X/*
X * new_player() - call this routine in your main loop to allow new
X *                players to join.  returns a playerId or -1 if no one
X *                wants to join.
X *                if wait == 0, then put your process to sleep until
X *                someone new tries to connect.
X */
X
Xint new_player(wait)
X     int wait;   /* 0 - wait for activity, else don't wait */
X{
X	fd_set readfds;
X	int j;
X	struct timeval *pWaitTime, waitTime;
X
X	pWaitTime = &waitTime;
X	
X	if (0 == wait) {
X		pWaitTime = NEVER;
X	} else {
X		pWaitTime->tv_sec = SECONDSLIMIT;
X		pWaitTime->tv_usec = MICROSECONDSLIMIT;
X	}
X
X	bcopy((char *) &active, (char *) &readfds, sizeof(active));
X
X	FD_SET(s, &readfds);
X
X	if (select(FD_SETSIZE, &readfds, NONE, NONE, pWaitTime) < 0) {
X		perror("select");
X		return -1;
X	}
X	if (FD_ISSET(s, &readfds)) {
X		if ((j = accept(s, IGNORE, (int *) 0)) < 0) {
X			return -1;
X		}
X		FD_SET(j, &active);
X		curhostname = hostfrom(j);
X		debug("Test Host=%s\n", curhostname);
X		return j;
X	} else {
X		return -1;
X	}
X}
X
X
X/*
X * disconnect() - drop the player with the given id
X */
X
Xint disconnect(id)
X     int id;
X{
X	if (FD_ISSET(id, &active)) {
X		debug("** Just dropped %d\n", id);
X		FD_CLR(id, &active);
X		if (close(id) < 0) {
X			perror("close");
X			return 0;
X		}
X	} else {
X		debug("** Just tried to drop someone not connected\n");
X		return 0;
X	}
X	return 1;
X}
X
X
X/*
X * read_player() - This routine returns the next string from the player
X *                 connected to descriptor playerFd. If there is no
X *                 input it returns the empty string. If the connection
X *                 is lost the string LOST_CARRIER_MSG is returned.
X *                 NOTE: control characters are replaced by spaces
X *                       and it is null terminated at the first nl/cr
X */
X
Xint read_player(playerFd, buf)
X     int playerFd;
X     int *buf;
X{
X  fd_set readfds;
X  struct timeval waitTime;
X  
X  waitTime.tv_sec = SECONDSLIMIT;
X  waitTime.tv_usec = MICROSECONDSLIMIT;
X  
X  bcopy((char *) &active, (char *) &readfds, sizeof(active));
X  
X  if (select(FD_SETSIZE, &readfds, NONE, NONE, &waitTime) < 0) {
X    perror("select");
X    return(LOST_CARRIER);
X  }
X  
X  if (FD_ISSET(playerFd, &readfds)) {
X    int nbytes;
X    
X    nbytes = read(playerFd, &buf[0], sizeof(int));
X    debug("Len of message is %d\n", buf[0]);
X    if (nbytes > 0 && buf[0] > 0) {
X      nbytes = read(playerFd, &buf[1], buf[0] * sizeof(int));
X      debug("Read %d of message\n", nbytes); 
X    }
X    if (nbytes < 0) {
X      perror("read");
X      disconnect(playerFd);
X      return(LOST_CARRIER);
X    } else if (nbytes == 0) {
X      disconnect(playerFd);
X      return(LOST_CARRIER);
X    } else
X      return(buf[0]);
X  }
X  return(NULL);
X}
X
X
X/*
X * write_player() - write to id the contents of integer array.
X *                  remember - len is the number of integers, not size...
X */
X
Xint w_p(id, buf, len)
X     int id, len;
X     int buf[];
X{
X
X  if (id > -1) {
X    if (!FD_ISSET(id, &active)) {
X      debug("** Tried to write to closed id #%d.\n", id);
X      return 0;
X    } else if (write(id, &buf[0], len * sizeof(int)) < 0) {
X      perror("Write");
X      return 0;
X    }
X  }
X  return 1;
X}
X
X
X
X
Xint connectstream(host, port)
Xchar *host;
Xint port;
X{
X  int s;
X  struct sockaddr_in saddr;
X  struct in_addr host_address;
X
X
X  debug("Connecting to port %d on host %s\n", port, host);
X  if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
X    perror("socket create");
X    return(0);
X  }
X
X  saddr.sin_family = AF_INET;
X  if (!get_host_address(host,&host_address)) {
X    printf("Bad or missing server address.\n");
X    exit(1);
X  }
X  bcopy(&host_address,&saddr.sin_addr,sizeof(struct in_addr));
X  /* saddr.sin_addr.s_addr = htonl(inet_addr(host)); Old method */
X  saddr.sin_port = htons(port);
X
X  if (connect(s, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)) < 0) {
X    perror("connect");
X    return(0);
X  }
X  FD_SET(s,&active);
X  playerFd=s;
X  return(1);
X}
X
X
X/* get_host_address: borrowed with appreciation from Tinytalk. Does a nice
X   job of getting around the various stupidities of the inetaddr routine,
X   et cetera. */
X
Xint get_host_address(name, addr)        /* Get a host address. */
X  register char *name;
X  register struct in_addr *addr;
X{
X  struct hostent *blob;
X  union {                               /* %#@!%!@%#!@ idiot who designed */
X    long signed_thingy;                 /* the inetaddr routine.... */
X    unsigned long unsigned_thingy;
X  } thingy;
X
X  if (*name == '\0') {
X    fprintf(stderr, "%% No host address specified.\n");
X    return (0);
X  }
X
X  if ((*name >= '0') && (*name <= '9')) {       /* IP address. */
X    addr->s_addr = inet_addr(name);
X    thingy.unsigned_thingy = addr->s_addr;
X    if (thingy.signed_thingy == -1) {
X      fprintf(stderr, "%% Couldn't find host %s .\n", name);
X      return (0);
X    }
X  }
X  else {                                /* Host name. */
X    blob = gethostbyname(name);
X
X    if (blob == NULL) {
X      fprintf(stderr, "%% Couldn't find host %s .\n", name);
X      return (0);
X    }
X
X    bcopy(blob->h_addr, addr, sizeof(struct in_addr));
X  }
X
X  return (1);                           /* Success. */
X}
X
Xint inputwaiting(who)
Xint who;
X{
X  int errrec;
X  fd_set readfds;
X  struct timeval waitTime;
X  waitTime.tv_sec=SECONDSLIMIT;
X  waitTime.tv_usec=MICROSECONDSLIMIT;
X  bcopy((char *) &active, (char *) &readfds,sizeof(active));
X  if (select(FD_SETSIZE,&readfds,NULL,NULL,&waitTime)<0) {
X    if (errno!=EINTR) { 
X      perror("select");
X    }
X    return 0;
X  }
X  if (FD_ISSET(who, &readfds))
X    return 1;
X  else
X    return 0;
X}
X
END_OF_FILE
if test 8379 -ne `wc -c <'src/interface.c'`; then
    echo shar: \"'src/interface.c'\" unpacked with wrong size!
fi
# end of 'src/interface.c'
fi
if test -f 'src/interface.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/interface.h'\"
else
echo shar: Extracting \"'src/interface.h'\" \(491 characters\)
sed "s/^X//" >'src/interface.h' <<'END_OF_FILE'
X#define SECONDSLIMIT 0L
X#define MICROSECONDSLIMIT 1L
X
X#define LINE_LEN 1024
X
X#define NONE (fd_set *) NULL
X#define NEVER (struct timeval *) NULL
X#define IGNORE (struct sockaddr *) NULL
X
X
Xint init_socket(); /* int port, fd_set *fd */
Xint shutdown();
Xchar *hostfrom(); /* int i */
Xchar *hostname();
Xint new_player(); /* int wait, fd_set *fd */
Xint disconnect(); /* int id, fd_set *fd */
Xint read_player(); /* int playerFd, fd_set *fd */
Xint w_p(); /* int id, char* str, int len, fd_set *fd */
X
END_OF_FILE
if test 491 -ne `wc -c <'src/interface.h'`; then
    echo shar: \"'src/interface.h'\" unpacked with wrong size!
fi
# end of 'src/interface.h'
fi
if test -f 'src/netwhist.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/netwhist.c'\"
else
echo shar: Extracting \"'src/netwhist.c'\" \(15351 characters\)
sed "s/^X//" >'src/netwhist.c' <<'END_OF_FILE'
X/* NetWhist: Client program
X *
X * NetWhist does all the calculations to actually play the game.  Upon startup
X * it looks around to see if there is a daemon running, and starts one up
X * if there isn't.  
X *
X * Copyright (C)1991 Bharat Mediratta
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <netdb.h>
X#include <signal.h>
X#include <sys/time.h>
X#include <fcntl.h>
X#include <stropts.h>
X#include <varargs.h>
X#include <string.h>
X
X#include "netwhist.h"
X#include "utils.h"
X
X/* #define DEBUG */
X
X#ifdef DEBUG
X#define debug printf
X#else
X#define debug 0+
X#define perror 0+
X#endif
X
Xvoid readnullterm();
Xchar *host = (char *)NULL;
X
Xextern fd_set gameFd;
Xextern int playerFd;
X
Xint playerNumber;
Xint deck[52], CardsInDeck, TopCard;
Xint hand[7], CardsInHand, handstyle;
X
Xint Msg[MAX_PACKET_SIZE];
Xint MsgLen;
X
Xint port, verify = FALSE;
Xint tricks, round, games, won, draw;
X
Xchar opp_name[20], name[20];
X
Xextern char *optarg;
Xextern int optind, opterr;
X  
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  char c;
X  int errflag = 0;
X
X  handstyle = NORMAL;
X  while ((c = getopt(argc, argv, "vhslb")) != -1)
X    switch(c) {
X    case 'v':
X      verify = TRUE;
X    case 'h':
X      host = argv[optind++];
X      break;
X    case 's':
X      handstyle = SEPARATED;
X      break;
X    case 'l':
X      handstyle = LINE_SEPARATED;
X      break;
X    case 'b':
X      handstyle = BRIDGE;
X      break;
X    case '?':
X      errflag++;
X    }
X
X  if (errflag || host == (char *)NULL) {
X    printf("NetWhist needs a special server process to run properly.  This\n");
X    printf("process must be started on the host that you (or an opponent)\n");
X    printf("are using. If you wish to play a given person, find out\n");
X    printf("the name of your machine (type 'hostname' to do this,) and\n");
X    printf("then type 'netwhist <mach-name>'.  Tell your opponent to type\n");
X    printf("the same thing (that is run it with the SAME hostname)  Then\n");
X    printf("you will both be running on the same machine and you can play\n");
X    printf("against each other.\n");
X    exit(1);
X  }
X  
X  if (!verify) 
X    initialize();
X
X  call_operator();
X
X  play_game();
X}
X
Xcall_operator()
X{
X  int done = FALSE;
X
X  if (connectstream(host, SWITCH_PORT) == 0) {
X    /* If we are only verifying, now we know.  Quit */
X    if (verify)
X      exit(0);
X
X    /* Uh-oh - there's no switchboard process running.  Better
X     * fork off a new job and start one...
X     */
X    if (fork() == 0) {
X      execl(DAEMON, "NetWhist Daemon", 0);
X      exit(0);
X    } else {
X      sleep(2);			/* Wait for the server to start */
X      if (connectstream(host, SWITCH_PORT) == 0) {
X	/* Switchboard is running and STILL it doesn't work? We 
X	 * got problems, Boss.
X	 */
X	printf("Can't connect to the daemon...send feedback to %s\n", WIZARD);
X	exit(1);
X      }
X    }
X  }
X
X  /* If we are verifying...send a verify message so the
X   * daemon is not left hanging and quit.  Otherwise, just
X   * send the message and continue.
X   */
X  create_message(VERIFY, verify + 1, 0);
X  send_message(playerFd);
X  if (verify) {
X    printf("NetWhist Daemon running on %s.\n", host);
X    exit(0);
X  }
X
X  while (!done) {
X    /* Wait for messages */
X    while (recv_message(playerFd) == 0);
X    done = (parse_message() == BEGIN);
X  }
X}
X
X
Xparse_message()
X{
X  char text[MAX_PACKET_SIZE];
X  int foo;
X
X  switch(Msg[1]) {
X  case WAIT:			/* Nobody ready to play against */
X    printf("Please wait for an opponent, %s...\n", name);
X    break;
X  case DECK:			/* Random deck is being sent */
X    debug("Taking the deck\n");
X    memcpy(&deck[0], &Msg[2], 52 * sizeof(int));
X    break;
X  case BEGIN:			/* We can start playing now */
X    playerNumber = !(Msg[2] - 1);
X    break;
X  case FULL:
X    printf("Sorry, too many people are playing right now.\n");
X    exit(0);
X  case PLAY:			/* Opponent moved */
X    break;
X  case NAME:
X    for (foo = 0; foo < Msg[0] - 1; foo++) /* Subtract 1 for TEXT header */
X      opp_name[foo] = Msg[2 + foo];
X    opp_name[Msg[0]] = (char) NULL;
X    break;
X  case WIN:
X    win(Msg[2] == YES, Msg[4], Msg[3]);
X    break;
X  case TEXT:
X    for (foo = 0; foo < Msg[0] - 1; foo++) /* Subtract 1 for TEXT header */
X      text[foo] = Msg[2 + foo];
X    text[Msg[0]] = (char) NULL;
X    printf("%s says \"%s\"\n", opp_name, text);
X    break;
X  case ERROR:
X    printf("Couldn't start a game!\n");
X    exit(0);
X  case LOST_CARRIER:
X    printf("%s seems to have quit!\n", opp_name);
X    exit(0);
X  }
X  return(Msg[1]);
X}
X
X
Xmake_hand(who)
Xint who;
X{
X  int foo;
X 
X  CardsInDeck = 52;
X  CardsInHand = 0;
X  TopCard = 0;
X
X  /* Not the most efficient way to do it, but easy to understand */
X  for (foo = 0; foo < 7; foo++) {
X    if (who) {
X      take_top_card();
X      discard_top_card();
X    } else {
X      discard_top_card();
X      take_top_card();
X    }
X  }
X}
X
X
Xtake_top_card()
X{
X  int foo, bar;
X
X  if (CardsInHand == 7) {
X    printf("Too many cards in hand!\n");
X    exit(0);
X  } else if (CardsInDeck) {
X    printf("You take the %s\n", CardName(deck[TopCard], LONG));
X    hand[CardsInHand++] = deck[TopCard++];
X    CardsInDeck--;
X  }
X} 
X
X
Xdiscard_top_card()
X{
X  if (CardsInDeck) {
X    TopCard++;
X    CardsInDeck--;
X  }
X}
X
X
Xshow_information()
X{
X  FILE *fp;
X  char command[80];
X
X/*  
X  if ((fp = fopen(INFO, "r")) == NULL) {
X    printf("Cannot open information file (%s)\n", INFO);
X    return(0);
X  } else fclose(fp);
X*/
X
X  sprintf(command, "/usr/ucb/more %s\n", INFO);
X  system(command);
X}
X
X
Xinitialize()
X{
X  char answer[80];
X
X  printf("Welcome to NetWhist %s\n", VERSION);
X  printf("Do you need help [y/n]? ");
X  gets(answer);
X
X  switch(answer[0]) {
X  case 'y':
X  case 'Y':
X    printf("\n");
X    show_information();
X    break;
X  default:
X    printf("\n");
X  }
X
X  printf("What is your name? ");
X  gets(name);
X
X  games = 0;
X  won = 0;
X}
X
X
Xshow_hand()
X{
X  int foo, bar, found = FALSE;
X
X  printf("Your hand: ");
X  switch(handstyle) {
X  case NORMAL:
X    for (foo = 0; foo < 4; foo++) {
X      /* Print Aces first */
X      if (HandContains(foo * 13 + 1))
X	printf("%s ", CardName(foo * 13 + 1, SHORT));
X
X      /* Check the rest of the suit in descending order */
X      for (bar = (foo + 1) * 13; bar > (foo * 13 + 1); bar--) 
X	if (HandContains(bar))
X	  printf("%s ", CardName(bar, SHORT));	  
X    }
X    printf("\n");
X    break;
X  case SEPARATED:
X    for (foo = 0; foo < 4; foo++) {
X      found = FALSE;
X
X      /* Print Aces first */
X      if (found |= HandContains(foo * 13 + 1))
X	printf("%s ", CardName(foo * 13 + 1, SHORT));
X
X      /* Check the rest of the suit in descending order */
X      for (bar = (foo + 1) * 13; bar > (foo * 13 + 1); bar--)
X	if (HandContains(bar)) {
X	  found = TRUE;
X	  printf("%s ", CardName(bar, SHORT));
X	}
X      if (!found) 
X	printf("-");
X      printf("     ");
X    }
X    printf("\n");
X    break;
X  case LINE_SEPARATED:
X    printf("\n");
X    for (foo = 0; foo < 4; foo++) {
X      printf("%c:\t", Suit(foo * 13 + 1)[0]);
X      found = FALSE;
X
X      /* Print Aces first */
X      if (found |= HandContains(foo * 13 + 1)) 
X	printf("%c ", Value(foo * 13 + 1)[0]);
X
X      /* Check the rest of the suit in descending order */
X      for (bar = (foo + 1) * 13; bar > (foo * 13 + 1); bar--)
X	if (HandContains(bar)) {
X	  found = TRUE;
X	  printf("%c ", Value(bar)[0]);
X	}
X      if (!found) 
X	printf("-");
X      printf("\n");
X    }
X    break;
X  case BRIDGE:
X    printf("\n");
X    for (foo = 0; foo < 4; foo++) {
X      printf("%c ", Suit(foo * 13 + 1)[0]);
X      found = FALSE;
X
X      /* Print Aces first */
X      if (found |= HandContains(foo * 13 + 1))
X	printf("%c ", Value(foo * 13 + 1)[0]);
X
X      /* Check the rest of the suit in descending order */
X      for (bar = (foo + 1) * 13; bar > (foo * 13 + 1); bar--)
X	if (HandContains(bar)) {
X	  found = TRUE;
X	  printf("%c", Value(bar)[0]);
X	}
X      if (!found) 
X	printf("-");
X      printf("\n");
X    }
X    break;
X  }
X}
X
X
XHandContains(which)
Xint which;
X{
X  int foo;
X
X  for (foo = 0; foo < CardsInHand; foo++)
X    if (hand[foo] == which)
X      return(1);
X  return(0);
X}
X
X
X/* NB: If you don't give a valid card...this will remove
X *     the last card in the hand... 
X */
Xremove_card(card)
Xint card;
X{
X  int foo = 0;
X  int found = FALSE;
X
X  while (foo < CardsInHand - 1) {
X    if (hand[foo] == card)
X      found = TRUE;
X
X    if (found)
X      hand[foo] = hand[foo + 1];
X
X    foo++;
X  }
X
X  CardsInHand--;
X}
X
Xplay_game()
X{
X  int foo;
X  int done = FALSE;
X  int card, lead_card;
X  int turn;
X  int restart = TRUE;
X  char trump[10];
X
X  /* Tell the opponent our name */
X  create_message(NAME, 0);
X  add_text(name);
X  send_message(playerFd);
X
X  /* Get the opponent's name */
X  do 
X    while (recv_message(playerFd) == 0);
X  while (parse_message() != NAME);
X
X  printf("\n\n");
X  printf("Your opponent is %s\n", opp_name);
X
X  while (!done) {
X    if (restart) {
X      tricks = 0;
X      round = 0;
X
X      turn = playerNumber = !playerNumber;
X      if (turn) {
X	debug("Requesting a new deck...\n");
X	create_message(DECK, 0);
X	send_message(playerFd);
X      }
X      debug("Waiting for deck...\n");
X      do
X	while (recv_message(playerFd) == 0);
X      while (parse_message() != DECK);
X
X      make_hand(turn);
X      strcpy(trump, Suit(deck[TopCard]));
X      printf("%s are Trumps\n", trump);
X      restart = FALSE;
X    } 
X
X    round++;
X    printf("\n\n");
X    if (round < 27) {
X      printf("Round %d: %s %d - %s %d\n",
X	     round,
X	     name,
X	     tricks,
X	     opp_name,
X	     (round - 1) - tricks);
X      printf("Top Card >%s<\t(Deck %d, %s are Trumps)\n",
X	     CardsInDeck ? CardName(deck[TopCard], LONG) : "EMPTY",
X	     CardsInDeck,
X	     trump);
X    } else {
X      printf("Game over.\n");
X      games++;
X      if (tricks > 13) {
X	printf("You win!\n");
X	won++;
X      } else if (tricks < 13)
X	printf("You lose :-(\n");
X      else {
X	printf("A draw!\n");
X	draw++;
X      }
X
X      printf("Score: %s %d - %s %d\n", name, tricks, opp_name, 26 - tricks);
X      printf("%-10s:     %3s - %4s - %3s\n", "Name:", "Won", "Lost", "Tied");
X      printf("%-10s:     %3d - %4d - %3d\n", 
X	     name, won, (games - won - draw), draw);
X      printf("%-10s:     %3d - %4d - %3d\n", 
X	     opp_name, (games - won - draw), won, draw);
X
X      restart = TRUE;
X      continue;
X    }
X    
X    show_hand();
X    
X    if (turn) {
X      while (get_play(&card, 0) == STRING);
X      remove_card(card);
X      create_message(PLAY, card, 0);
X      send_message(playerFd);
X      printf("Waiting for %s...\n", opp_name);
X      fflush(stdout);
X      do
X	while (recv_message(playerFd) == 0);
X      while (parse_message() != WIN);
X      turn = (Msg[2] == YES);
X    } else {
X      printf("Waiting for %s...\n", opp_name);
X      fflush(stdout);
X      do
X	while (recv_message(playerFd) == 0);
X      while (parse_message() != PLAY);
X
X      /* Tell what the other guy played... */
X      lead_card = Msg[2];
X      printf("%s plays the %s\n", opp_name, CardName(lead_card, LONG));
X
X      /* Get player's move */
X      while (get_play(&card, lead_card) == STRING);
X      remove_card(card);
X      
X      /* Decide who wins...this is marginally tricky. */
X      /* Rules: 
X       *   If the suits are the same, the higher card wins.
X       *   If the suits are different and neither are the
X       *      trump suit, the lead card wins.
X       *   If the suits are different and one is the trump
X       *      suit, the trump card wins.
X       */
X      
X      if (Suit(card)[0] == Suit(lead_card)[0]) {
X	/* Higher card wins...
X	 * NB: remember aces (1, 14, 27, 40) are highest 
X	 */
X	if (card % 13 == 1)	/* My card is the ace */
X	  win(TRUE, card, lead_card, NO);
X	else if (lead_card % 13 == 1) /* Opp's card is the ace */
X	  win(FALSE, card, lead_card, NO);
X	else 		/* No aces, compare numbers... */
X	  if (card > lead_card)
X	    win(TRUE, card, lead_card, NO); /* Mine's higher */
X	  else
X	    win(FALSE, card, lead_card, NO); /* Mine's lower */
X      } else {
X	/* They're different...unless the second
X	 * card's a trump, the first wins
X	 */
X	if (Suit(card)[0] == trump[0])
X	  win(TRUE, card, lead_card, YES); /* Second card wins */
X	else
X  	  win(FALSE, card, lead_card, NO); /* Lead card wins */
X      }
X      create_message(WIN, turn ? NO : YES, card, lead_card);
X      send_message(playerFd);
X    }
X  }
X}
X
Xwin(did_i_win, my_card, his_card, trump_win)
Xint did_i_win, my_card, his_card, trump_win;
X{
X  /* Grrr.  I have to split up printfs (and fflush()) 'cause I 
X   * designed CardName to use a static char[].  Ah, well.
X   * This is the kind of thing that happens when you don't plan
X   * out the program very well.  
X   */
X  tricks += did_i_win;
X
X  printf("%10s: %s\n", name, CardName(my_card));
X  printf("%10s: %s\n", opp_name, CardName(his_card));
X  printf("%17s\n", CardName(his_card));
X  printf("You %s\n", did_i_win ? "win" : "lose");
X
X  if (did_i_win) {
X    take_top_card();
X    discard_top_card();
X  } else {
X    discard_top_card();
X    take_top_card();
X  }
X  return(1);
X}
X
Xget_play(card, lead_card)
Xint *card, lead_card;
X{
X  char play[80];
X  int legal = FALSE;
X
X  do {
X    /* Get the play */
X    do {
X      printf("Your play: ");
X      fflush(stdout);
X      gets(play);
X    } while (play == NULL);
X    
X    /* See if it is legal */
X    legal = legal_move(play, card, lead_card);
X    if (legal == STRING)
X      return(STRING);
X
X    if (legal != CARD) {
X      if (legal == CHEAT)
X	printf("That's cheating! You must play %s\n", Suit(lead_card));
X      else if (!*card)
X	printf("That's not a card!\n");
X      else 
X	printf("Sorry, you do not have a %s\n", CardName(*card, LONG));
X      printf("Please try again.\n");
X    } else 
X      printf("You play: %s\n", CardName(*card, LONG));
X  } while (legal != CARD);
X  return(CARD);
X}
X
X
X
Xparse_move(play)
Xchar *play;
X{
X  int value = 0;
X  int suit = 0;
X
X  /* Skip spaces */
X  while (isspace(*play))
X    play++;
X
X  if (*play == '"') {     /* It's a string */
X    create_message(TEXT, 0);
X    add_text(++play);
X    send_message(playerFd);
X    return(STRING);
X  }
X
X  if (isdigit(*play))
X    while (isdigit(*play)) 
X      value = 10 * value + (*play++ - '0');
X  else switch(*play++) {
X  case 'a':
X  case 'A': 
X    value = 1;
X    break;
X  case 'j':
X  case 'J': 
X    value = 11;
X    break;
X  case 'q':
X  case 'Q':
X    if (strstr(play, "uit") == play) {
X      printf("Quitting...\n");
X      exit(0);
X    } else {
X      value = 12;
X      break;
X    }
X  case 'k':
X  case 'K':
X    value = 13;
X    break;
X  default:
X    return(0);
X  }
X  
X  /* Skip spaces */
X  while (*play == ' ')
X    play++;
X
X  
X  switch(*play) {
X  case 's':
X  case 'S': 
X    suit = 1;
X    break;
X  case 'h':
X  case 'H':
X    suit = 2;
X    break;
X  case 'd':
X  case 'D':
X    suit = 3;
X    break;
X  case 'c':
X  case 'C':
X    suit = 4;
X    break;
X  default:
X    return(0);
X  }
X
X  return((suit - 1) * 13 + value);
X}
X    
X
Xlegal_move(play, card, lead_card)
X     int lead_card;
X     int *card;
X     char *play;
X{
X  int foo;
X  int found = FALSE;
X
X
X  *card = parse_move(play);
X
X  if (*card == STRING)
X    return(STRING);
X
X  for (foo = 0; foo < CardsInHand; foo++)
X    if (hand[foo] == *card)
X      found = CARD;
X
X  /* Make sure that the card played is the same as
X   * the lead suit (if possible)
X   */
X  if (lead_card && (found == CARD)) 
X    {
X      char lead_suit;
X      lead_suit = Suit(lead_card)[0];
X      if (Suit(*card)[0] != lead_suit)
X	for (foo = 0; foo < CardsInHand; foo++)
X	  if (Suit(hand[foo])[0] == lead_suit)
X	    return(CHEAT);
X    }  
X  return(found);
X}
END_OF_FILE
if test 15351 -ne `wc -c <'src/netwhist.c'`; then
    echo shar: \"'src/netwhist.c'\" unpacked with wrong size!
fi
# end of 'src/netwhist.c'
fi
if test -f 'src/netwhist.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/netwhist.h'\"
else
echo shar: Extracting \"'src/netwhist.h'\" \(1084 characters\)
sed "s/^X//" >'src/netwhist.h' <<'END_OF_FILE'
X#define INFO "/home/scullion/bharat/bin/src/whist/lib/netwhist_info"
X#define DAEMON "/home/scullion/bharat/bin/src/whist/lib/netwhistd" 
X#define VERSION "0.9"
X#define WIZARD "bharat"
X
X#ifndef TRUE
X#define TRUE 1
X#define FALSE 0
X#endif
X
X#define MAX_PACKET_SIZE 100
X#define TIMEOUT_LIMIT 10000
X
X#define SWITCH_PORT 3123
X#define MAX_PLAYERS 10
X
X#define DONT_WAIT 1
X
X/* Link states */
X#define INACTIVE 0
X#define PLAYING 1
X#define WAITING 2
X
X/* Different Messages */
X#define LOST_CARRIER     -1
X#define CHANGE_TO 1
X#define FIND_PORT 3
X#define DECK 3
X#define FULL 4
X#define WAIT 5
X#define BEGIN 6
X#define ERROR 7
X#define PLAY 8
X#define WIN 9
X#define TEXT 10
X#define NAME 11
X#define VERIFY 12
X
X/* How is the hand displayed? */
X#define NORMAL 0
X#define SEPARATED 1
X#define LINE_SEPARATED 2
X#define BRIDGE 3
X
X/* What kind of play was it? */
X#define CHEAT  -3
X#define STRING -2
X#define CARD   -1
X
X/* Did I win? */
X#define NO  1
X#define YES 2
X
X/* Ways to show a card */
X#define LONG 1
X#define SHORT 2
X
X/* Message for when the carrier is dropped. */
X#define LOST_CARRIER_MSG "Carrier Dropped"
X
X
X
END_OF_FILE
if test 1084 -ne `wc -c <'src/netwhist.h'`; then
    echo shar: \"'src/netwhist.h'\" unpacked with wrong size!
fi
# end of 'src/netwhist.h'
fi
if test -f 'src/netwhistd.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/netwhistd.c'\"
else
echo shar: Extracting \"'src/netwhistd.c'\" \(4112 characters\)
sed "s/^X//" >'src/netwhistd.c' <<'END_OF_FILE'
X/* NetWhistD - Daemon for whist
X *
X * This program acts as a router for the whist game - as soon as two
X * people request to play, it pairs them off and acts as a switchboard
X * sending data back and forth between them.  
X *
X * Copyright (C)1991 Bharat Mediratta
X */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <netdb.h>
X
X#include "netwhist.h"
X
X/* #define DEBUG */
X
X#ifdef DEBUG
X#define debug printf
X#else
X#define debug 0+
X#define perror 0+
X#endif
X
Xint Msg[MAX_PACKET_SIZE];
Xint MsgLen;
X
Xint playerCount = 0;
Xint timeOut = 0;
X
Xstruct {
X  int fd[2];
X  int active;
X} link[MAX_PLAYERS];
X
Xextern fd_set gameFd;
X
Xmain() 
X{
X  int id;
X  int foo, bar;
X
X  bzero(link, sizeof(link));
X  randomize();
X
X  /* First things first, initialize the switchboard port */
X  if (init_socket(SWITCH_PORT) == 0) {
X    fprintf(stderr, "Error: Cannot open the switchboard port!\n");
X    exit(0);
X  }
X
X  /* We're here to stay...*/
X  for (;;) {
X    /* Each time through the loop, check for a new player */
X    id = new_player(DONT_WAIT);
X    if (id != -1) {
X      debug("New player (%d)!\n", id);
X      /* First check to see if the new player is merely 
X       * querying the network.  
X       */
X      while (recv_message(id) == 0);
X      if (Msg[1] == VERIFY && (Msg[2] - 1) == TRUE)
X	continue;
X	
X      /* We have a new player, deal with him.
X       * first, check to see if there's room for him
X       */
X      foo = 0;
X      while (foo < MAX_PLAYERS && link[foo].active != INACTIVE) foo++;
X      if (foo < MAX_PLAYERS) {	/* There's room */
X	/* Look for unpaired players */
X	foo = 0;
X	while (foo < MAX_PLAYERS && link[foo].active != WAITING) foo++;
X	if (foo < MAX_PLAYERS) { /* Found one */
X	  debug("Found an unpaired player\n");
X	  link[foo].fd[1] = id;
X	  link[foo].active = PLAYING;
X
X	  /* Tell them to start playing */
X	  create_message(BEGIN, 1, 0);
X	  send_message(link[foo].fd[0]);
X	  create_message(BEGIN, 2, 0);
X	  send_message(link[foo].fd[1]);
X	} else {		/* None available */
X	  debug("No unpaired players\n");
X	  foo = 0; 
X	  while (foo < MAX_PLAYERS && link[foo].active != INACTIVE) foo++;
X	  if (foo == MAX_PLAYERS) {
X	    debug("Uh-oh...couldn't find inactive slot...\n");
X	    create_message(ERROR, 0);
X	    send_message(id);
X	    disconnect(id);
X	  } else {
X	    debug("Creating a new slot...\n");
X	    link[foo].active = WAITING;
X	    link[foo].fd[0] = id;
X	    create_message(WAIT, 0);
X	    send_message(link[foo].fd[0]);
X	  }
X	}
X      } else {			/* No room left */
X	create_message(FULL, 0);
X	send_message(id);
X	disconnect(id);
X      }
X    } else {
X      if (playerCount == 0) 
X	timeOut++;
X      else
X	timeOut = 0;
X      if (timeOut == TIMEOUT_LIMIT)
X	exit(0);
X    }
X
X    /* Now, handle incoming requests from all other players */
X    playerCount = 0;
X    for (foo = 0; foo < MAX_PLAYERS; foo++) {
X      if (link[foo].active == PLAYING) {
X	playerCount++;
X	for (bar = 0; bar < 2; bar++) {
X	  /* Once for each side */
X	  if (recv_message(link[foo].fd[bar])) {
X  	    switch(Msg[1]) {
X	    case 0:			/* Nothing */
X	      break;
X	    case LOST_CARRIER:	/* Drop him */
X	      debug("One player down...telling the other...\n");
X	      link[foo].active = FALSE;
X	      create_message(LOST_CARRIER, 0);
X	      send_message(link[foo].fd[!bar]);
X	      break;
X	    case DECK:
X	      /* Make a deck of cards & send it along */
X	      create_message(DECK, 0);
X	      make_deck();
X	      send_message(link[foo].fd[0]);
X	      send_message(link[foo].fd[1]);
X	      break;
X	    default:		/* It's a message, relay it */
X	      debug("Relaying message on link %d\n", foo);
X	      send_message(link[foo].fd[!bar]);
X	    }
X	  }
X	}
X      }
X    }
X  }
X}
X
X
Xmake_deck()
X{
X  int foo, bar, deck[52];
X  
X  for (foo = 0; foo < 52; foo++) /* Fill the deck */
X    deck[foo] = foo + 1;
X
X  debug("Making the deck...\n");
X
X  for (foo = 0; foo < 52; foo++) {
X    /* Pick a card, any card... */
X    bar = random(52 - foo);
X
X    /* add it to the message */
X    add_to_message(deck[bar]);
X
X    /* remove it from the deck */
X    for (; bar < (51-foo); bar++)
X      deck[bar] = deck[bar+1];
X  }
X
X}
X
X
X
END_OF_FILE
if test 4112 -ne `wc -c <'src/netwhistd.c'`; then
    echo shar: \"'src/netwhistd.c'\" unpacked with wrong size!
fi
# end of 'src/netwhistd.c'
fi
if test -f 'src/utils.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/utils.c'\"
else
echo shar: Extracting \"'src/utils.c'\" \(4116 characters\)
sed "s/^X//" >'src/utils.c' <<'END_OF_FILE'
X/* Utils.c:
X *     Some useful routines that are used by the netwhist daemon and the
X *     client program.
X *
X * Copyright Bharat Mediratta, 1991
X */
X
X
X#include <stdio.h>
X#include <time.h>
X#include <varargs.h>
X#include <sys/types.h>
X#include "netwhist.h"
X
X/* #define DEBUG */
X
X#ifdef DEBUG
X#define debug printf
X#else
X#define debug 0+
X#define perror 0+
X#endif
X
Xextern int playerFd;
Xextern int Msg[MAX_PACKET_SIZE];
Xextern int MsgLen;
X
X/*
X * Random() returns a pseudo-random number in the 0..max range
X * Randomize() must be called once before random() to get decent numbers
X */
X
Xint randomize()
X{
X  srand(time(NULL));
X}
X
Xint random(max)
X{
X  return rand() % max;
X}
X
X
X/*
X * Variable parameter function to create a message packet
X */
Xcreate_message (va_alist)
Xva_dcl
X{
X  int foo;
X  va_list ap;
X
X  Msg[0] = 0;
X
X  va_start(ap);
X
X  /* Build the message, tracking size in Msg[0] */
X  while ((foo = va_arg(ap, int)) != 0)
X    Msg[++Msg[0]] = foo;
X  
X  va_end(ap);
X
X}
X
X/*
X * Allows you to add one integer at a time to the packet
X */
Xadd_to_message(what)
Xint what;
X{
X  int foo;
X
X  Msg[++Msg[0]] = what; 
X  ++MsgLen;
X}
X
X/*
X * Add an entire string to the end of the packet, one integer
X * at a time.
X */
Xadd_text(str)
Xchar *str;
X{
X  while (*str != (char) NULL)
X    add_to_message(*str++);
X}
X
X/*
X * Actually send the packet (using w_p()))
X */
Xsend_message(who) 
X     int who;
X{
X  int err;
X
X#ifdef DEBUG
X  { 
X    int foo;
X    printf("Sending message to id %d\n", who);
X    for (foo = 0; foo < Msg[0] + 1; foo++)
X      printf("%d ", Msg[foo]);
X    printf("\n");
X  }
X#endif
X
X  /* Send the message */
X  if ((err = w_p(who, Msg, Msg[0] + 1)) == 0) {
X    debug("w_p failed.\n");
X    return(LOST_CARRIER);
X  } else return(err);
X
X}
X
X
X/*
X * Receive a message from a given file descriptor
X */
Xrecv_message(who)
X     int who;
X{
X  int foo = 0;
X
X  if (inputwaiting(who)) {
X    debug("Receiving message...\n");
X    MsgLen = read_player(who, &Msg[0]);
X#ifdef DEBUG
X    printf("Returned from read_player (%d)\n", MsgLen);
X#endif
X    if (MsgLen != NULL) {
X
X      /* Carrier was dropped */
X      if (MsgLen == LOST_CARRIER) {
X	Msg[1] = LOST_CARRIER;
X	debug("%s\n", LOST_CARRIER_MSG);
X	return(LOST_CARRIER);
X      }
X
X#ifdef DEBUG	
X      {
X	int foo;
X	printf("MsgLen is %d\n", Msg[0]);
X	
X	printf("-- Message Received --\n");
X	for (foo = 0; foo < Msg[0]; foo++)
X	  printf("%d ", Msg[foo+1]);
X	printf("\n");
X      }
X#endif
X      return(1);
X    } else 
X      return(0);
X  } else 
X    return(0);
X}
X
X/*
X * Takes an integer [1..52] and returns corresponding name for
X * card.  Note, as in Suit() and CardName() this uses a static return
X * space, so be careful with multiple calls on a single line.
X */
Xchar *Value(num)
Xint num;
X{
X  static char returnval[5];
X
X  num %= 13;
X
X  switch(num) {
X  case 1: 
X    sprintf(returnval, "Ace");
X    break;
X  case 10:
X    sprintf(returnval, "Ten");
X    break;
X  case 11:
X    sprintf(returnval, "Jack");
X    break;
X  case 12: 
X    sprintf(returnval, "Queen");
X    break;
X  case 0: 
X    sprintf(returnval, "King");
X    break;
X  default: 	/* Futz, there is no itoa() routine! */
X    sprintf(returnval, "%d", num);
X  }
X  return(returnval);
X}
X
X/*
X * Takes an integer [1..52] and returns the suit of the card
X * N.B.  I guessed at the order, so it may be wrong -BM
X */
Xchar *Suit(num)
Xint num;
X{
X  static char returnval[10];
X
X  num = ((num - 1) / 13);
X
X  switch(num) {
X  case 0: 
X    sprintf(returnval, "Spades");
X    break;
X  case 1: 
X    sprintf(returnval, "Hearts");
X    break;
X  case 2: 
X    sprintf(returnval, "Diamonds");
X    break;
X  case 3: 
X    sprintf(returnval, "Clubs");
X    break;
X  default:
X    sprintf(returnval, "Weirds");
X    break;
X  }
X  return(returnval);
X}
X
X/* 
X * Takes an integer [1..52] and returns the name of the card.
X * 'how' specifies whether the returned string will be in long form
X * (e.g. Ace of Spades) or short form (AS)
X */
X
Xchar *CardName(num, how)
Xint num;
Xint how;
X{
X  static char returnval[30];
X  char *val;
X
X  if (how == LONG) 
X    sprintf(returnval, "%s of %s", Value(num), Suit(num));
X  else 
X    sprintf(returnval, "%c%c", Value(num)[0], (Suit(num))[0]);
X
X  return(returnval);
X}
X
X
X
X
END_OF_FILE
if test 4116 -ne `wc -c <'src/utils.c'`; then
    echo shar: \"'src/utils.c'\" unpacked with wrong size!
fi
# end of 'src/utils.c'
fi
if test -f 'src/utils.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/utils.h'\"
else
echo shar: Extracting \"'src/utils.h'\" \(226 characters\)
sed "s/^X//" >'src/utils.h' <<'END_OF_FILE'
X/* Prototypes for the functions in utils.c */
X
Xint randomize();
Xint random();
Xint create_message ();
Xint add_to_message();
Xint send_message();
Xint recv_message();
Xint add_text();
Xchar *Value();
Xchar *Suit();
Xchar *CardName();
END_OF_FILE
if test 226 -ne `wc -c <'src/utils.h'`; then
    echo shar: \"'src/utils.h'\" unpacked with wrong size!
fi
# end of 'src/utils.h'
fi
echo shar: End of archive 1 \(of 1\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have the archive.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0