[net.sources.games] Poker Part 1

jjv3345@ritcv.UUCP (Jeff Van Epps) (11/21/85)

: Run this script with sh, not with csh
echo x README
sed -e 's/^X//' << 'PaRtIcUlAtEmAtTeR' > README
X
XInstallation Instructions for Poker:
X
XSave the shar file in "SHAR". Edit out the mail headers.
Xmkdir pokerdir
Xmv SHAR pokerdir
Xcd pokerdir
Xsh SHAR
X
XThis creates a bunch of source files and a Makefile.
XEdit "port.h" and enter the HOST which the daemon will be running on
Xand a free Internet PORT number.
XThis way a game can span several machines. Edit "scores.c" and enter 
Xa pathname where the score file can be placed.
Xmake pokerd ; make poker
Xchmod 711 pokerd ; chmod u+s pokerd
X"pokerd" is the daemon, which must be running in order for anyone
Xto play. Start it with
Xpokerd >log &   or    pokerd >/dev/null &
X"poker" is the user interface, so chmod 711 poker (&tell people
Xthe path to it).
X
XWhat happens when the user types "poker"?
XIf the daemon can't be reached, "Connection refused.", else it 
Xwaits for the hand currently being played (if any) to finish.
XThen, if there are <4 people already playing, the new player
Xwill be dealt in. If the maximum player limit is already 
Xreached, the new player is ignored until someone quits ("TABLE FULL").
XIf someone starts "poker", then kills the process, the daemon
Xwill become confused and crash. "poker" therefore disables BREAK.
X
X
XScore Info:
X
XThe player's NAME from his environment and his userid are combined
Xwhen searching the stored scores. If POKER is defined, it is used
Xinstead of NAME. Scores are kept when a player quits
Xand restored when next he plays. If NAME is not set, USER is used.
X
X
XMisc:
X
XWhen asked for Discard:, enter 134 to throw away the first, third, and
Xfourth cards, (i.e. the index of the card in your hand). You may discard
Xfrom 0 to 5 cards.
X^L will redraw the screen.
XSitting out and quitting both do not take effect until AFTER the current
Xhand is finished.
X
X
X
XBugs:
X
XIt will wait forever for someone to respond; this can irritate other
Xplayers.
XSometimes crashes when a client is killed.
XComputer is too easy to beat.
XA player can get in twice on different terminals; then whichever of him
Xquits last is the score that is saved.
X
X
X
XDisclaimers:
X
XWarranty? What warranty?
XPlease excuse the low quality of this "documentation".
XIt is being written hastily and late at night.
X
X
X
XComplaint Department:
X
Xrochester!ritcv!jjv3345
X
X
X"A blurry-eyed hacker is a happy hacker!"
X
PaRtIcUlAtEmAtTeR
echo -n '	'
ls -l README
echo x Makefile
sed -e 's/^X//' << 'PaRtIcUlAtEmAtTeR' > Makefile
XSRCS=	main.c players.c cards.c util.c showcards.c whowon.c poker.c tellall.c payoff.c betting.c computer.c draw.c scores.c 
XOBJS=	main.o players.o cards.o util.o showcards.o whowon.o tellall.o payoff.o betting.o computer.o draw.o scores.o
XOBJS2=	poker.o util.o
X
X# define the type of system programs are being made on
X# currently this is only important for MASSCOMP machines because some
X# socket routine calls and include files are different than 4.2BSD
X#CFLAGS= -DMASSCOMP
XCFLAGS= -DVAX
X
Xpokerd:		$(OBJS)
X#	cc $(OBJS) -lsocket -o pokerd
X	cc $(OBJS) -o pokerd
X
Xpoker:		$(OBJS2)
X#	cc $(OBJS2) -lcurses -ltermlib -lsocket -o poker 
X	cc $(OBJS2) -lcurses -ltermlib -o poker 
X
Xlistings:
X	lpr $(SRCS)
X
X# This 'target' simply makes a new Makefile (after saving the current one
X# in Makefile.old) with added dependencies for header files included
X# in the listed source files.
Xdepend:
X	mv Makefile Makefile.old
X	sed -n '1,/^# DO NOT REMOVE THIS LINE/p' Makefile.old > Makefile
X	grep '^#[ 	]*include[ 	]*["]' $(SRCS) | \
X		sed -e 's/\.[^:]*:#[ 	]*include[ 	]*/.o:	/' \
X		    -e 's/"\([^"]*\)".*/\1/' \
X		    -e 's@<\([^>]*\)>.*@/usr/include/\1@' >> Makefile
X
X# Lines after this block of comments are replace every time the new dependency
X# information is created using 'make depend'.  The next line is crucial.
X# DO NOT REMOVE THIS LINE
Xmain.o:	cards.h
Xmain.o:	players.h
Xmain.o:	betting.h
Xmain.o:	draw.h
Xmain.o:	whowon.h
Xmain.o:	payoff.h
Xmain.o:	showcards.h
Xmain.o:	util.h
Xmain.o:	tellall.h
Xmain.o:	limits.h
Xplayers.o:	players.h
Xplayers.o:	util.h
Xplayers.o:	port.h
Xplayers.o:	scores.h
Xcards.o:	cards.h
Xutil.o:	util.h
Xshowcards.o:	showcards.h
Xshowcards.o:	players.h
Xshowcards.o:	cards.h
Xshowcards.o:	util.h
Xwhowon.o:	whowon.h
Xwhowon.o:	players.h
Xwhowon.o:	cards.h
Xwhowon.o:	showcards.h
Xwhowon.o:	tellall.h
Xpoker.o:	util.h
Xpoker.o:	port.h
Xpoker.o:	limits.h
Xtellall.o:	tellall.h
Xtellall.o:	util.h
Xtellall.o:	players.h
Xpayoff.o:	players.h
Xpayoff.o:	tellall.h
Xbetting.o:	betting.h
Xbetting.o:	players.h
Xbetting.o:	computer.h
Xcomputer.o:	computer.h
Xcomputer.o:	players.h
Xcomputer.o:	cards.h
Xcomputer.o:	whowon.h
Xcomputer.o:	limits.h
Xdraw.o:	draw.h
Xdraw.o:	players.h
Xdraw.o:	showcards.h
Xdraw.o:	tellall.h
Xscores.o:	scores.h
PaRtIcUlAtEmAtTeR
echo -n '	'
ls -l Makefile
echo x betting.c
sed -e 's/^X//' << 'PaRtIcUlAtEmAtTeR' > betting.c
X/*
X** Handle all the betting being done.
X*/
X
X# include	<stdio.h>
X# include	"betting.h"
X# include	"players.h"
X# include	"computer.h"
X
X# define	TRUE	1
X# define	FALSE	0
X
Xint	betting( player, n_players, pot, first )
X
XPLAYER	player[];		/* all player information */
Xint	n_players;		/* # of players */
Xint	*pot;			/* current pot */
Xint	first;			/* player who gets to bet first */
X
X{
Xint	last_raiser=(-1);	/* player who made last raise */
Xint	n_active=0;		/* # players active in betting (haven't folded) */
Xint	n_raises=0;		/* # of raises this hand so far */
Xint	j=(-1);			/* player currently betting */
Xint	i;
Xint	total_bet;		/* total amount bet each player this hand */
Xchar	temp[80];
Xint	done;			/* has player entered something valid yet? */
Xint	amount;			/* how much more is player donating to pot? */
Xint	cycle=FALSE;		/* has bet been around circle once yet? */
Xint	x;
Xint	rounds=0;
X
Xi = first;
Xwhile ( i != first || !cycle )
X	{
X	if ( player[i].in )
X		{
X		if ( j == -1 )
X			{
X			total_bet = player[i].bet;
X			j = i;
X			}
X		sprintf( temp, "B%d%d", i, player[i].bet );
X		tellall( player, n_players, temp );
X		sprintf( temp, "$%d%d", i, player[i].cash );
X		tellall( player, n_players, temp );
X		n_active++;
X		}
X	if ( ++i == n_players )
X		{
X		cycle = TRUE;
X		i = 0;
X		}
X	}
Xtellall( player, n_players, "U" );
Xwhile( n_active > 1 && j != last_raiser )
X	{
X	sprintf( temp, "T%d", j );
X	tellall( player, n_players, temp );
X	sprintf( temp, "P%d", *pot );
X	tellall( player, n_players, temp );
X	sprintf( temp, "B%d%d", j, player[j].bet );
X	tellall( player, n_players, temp );
X	tellall( player, n_players, "U" );
X	sprintf( temp, "$%d%d", j, player[j].cash );
X	tellall( player, n_players, temp );
X	if ( j > 0 )		/* if not computer */
X		{
X		sprintf( temp, "?%d", total_bet - player[j].bet );
X		writeln( player[j].socket, temp );
X		}
X	tellall( player, n_players, "U" );	/* update displays */
X
X	/* get bet ... */
X
X	done = FALSE;
X	while ( !done )
X		{
X		if ( j > 0 )
X			readln( player[j].socket, temp );
X		else
X			computer_bet( player, n_players, n_active, n_raises, *pot, total_bet, temp );
X		done = TRUE;
X		switch ( temp[0] )  {
X			case 'Q' :
X					player[j].wantsout = TRUE;
X					done = FALSE;
X					break;
X			case 'S' :
X					player[j].sittingout = TRUE;
X					done = FALSE;
X					break;
X			case 'F' :
X					player[j].in = FALSE;
X					sprintf( temp, "H%d--fold--", j );
X					tellall( player, n_players, temp );
X					n_active--;
X					break;
X			case 'C' :
X					amount = total_bet - player[j].bet;
X					*pot += amount;
X					player[j].cash -= amount;
X					player[j].bet = total_bet;
X					sprintf( temp, "B%d%d", j, total_bet );
X					tellall( player, n_players, temp );
X					sprintf( temp, "H%dCall", j );
X					tellall( player, n_players, temp );
X					break;
X			case 'R' :
X					if ( ++n_raises > n_players )
X						{
X						sprintf( temp, "MMax # of raises; Call or fold." );
X						writeln( player[j].socket, temp );
X						--j;
X						break;
X						}
X					last_raiser = j;
X					amount = (total_bet += (x = atoi(temp+1))) - player[j].bet;
X					*pot += amount;
X					player[j].cash -= amount;
X					player[j].bet = total_bet;
X					sprintf( temp, "B%d%d", j, total_bet );
X					tellall( player, n_players, temp );
X					sprintf( temp, "H%dRaise %d", j, x);
X					tellall( player, n_players, temp );
X					break;
X			case 'P' :
X					sprintf( temp, "H%dPass", j );
X					tellall( player, n_players, temp );
X					break;
X			}
X		}
X	sprintf( temp, "$%d%d", j, player[j].cash );
X	tellall( player, n_players, temp );
X
X	sprintf( temp, "P%d", *pot );
X	tellall( player, n_players, temp );
X	tellall( player, n_players, "U" );
X	if ( ++j >= n_players )
X		{
X		++rounds;
X		j = 0;
X		}
X	while( !player[j].in )
X		if ( ++j >= n_players )
X			{
X			++rounds;
X			j = 0;
X			}
X	if ( last_raiser == -1 && ( rounds > 1 || ( rounds == 1 && j >= first ) ) )
X		break;		/* all passed or folded */
X	}
Xif ( n_active <= 1 )
X	return( j );
Xelse
X	return( -1 );
X}
PaRtIcUlAtEmAtTeR
echo -n '	'
ls -l betting.c
echo x betting.h
sed -e 's/^X//' << 'PaRtIcUlAtEmAtTeR' > betting.h
X/*
X** Handle the intricacies of betting. If all but one player fold, the
X** winning player's index is returned.
X*/
X
Xextern	int	betting();
PaRtIcUlAtEmAtTeR
echo -n '	'
ls -l betting.h
echo x cards.c
sed -e 's/^X//' << 'PaRtIcUlAtEmAtTeR' > cards.c
X
X/*
X** Basic card playing routines like shuffling, etc.
X*/
X
X# include	"cards.h"
X# ifdef MASSCOMP
X#	define		MAXRAND		32767
X# else
X# 	define		MAXRAND		2147483648
X# endif
X# define	ERROR	-1
X
Xchar	ranks[]="23456789TJQKA";
Xchar	suits[]="DCHS";
X
Xvoid	shuffle (deck)
X
Xint	deck[];		/* return deck of shuffled cards here */
X
X{
Xint	temp[52];
Xint	i,x;
Xint	crandom();
X
Xfor(i=0; i<52; i++)
X	temp[i] = i;
Xfor(i=0; i<52; i++)
X	{
X	while (temp[x = crandom(52)] == ERROR) ;
X	deck[i] = temp[x];
X	temp[x] = ERROR;
X	}
X}
X
Xint	crandom( limit )
X
Xint	limit;
X
X{
X# ifdef MASSCOMP
X# define	random	rand
X# endif
Xunsigned long	random();
Xunsigned long	scale;
Xint		x;
X
Xscale = (unsigned long) MAXRAND/limit;
Xx = random()/scale;
Xif ( x < 0 ) x = 0;	/* weird things do happen occasionally */
Xreturn(x);
X}
PaRtIcUlAtEmAtTeR
echo -n '	'
ls -l cards.c
echo x cards.h
sed -e 's/^X//' << 'PaRtIcUlAtEmAtTeR' > cards.h
Xextern	char	ranks[];	/* card ranks 2-A */
Xextern	char	suits[];	/* card suits D,C,H,S */
X
X# define	card(x)		((x) % 13)
X# define	suit(x)		((x) / 13)
X# define	rank(x)		(ranks[card(x)])
X# define	color(x)	(suits[suit(x)])
X
Xextern	void	shuffle();	/* shuffle a deck of cards */
Xextern	int	crandom();	/* return random number 0 .. limit-1 */
PaRtIcUlAtEmAtTeR
echo -n '	'
ls -l cards.h
echo x computer.c
sed -e 's/^X//' << 'PaRtIcUlAtEmAtTeR' > computer.c
X/*
X** Handle betting and drawing for the computer's hand.
X*/
X
X# include	"computer.h"
X# include	"players.h"
X# include	"cards.h"
X# include	"whowon.h"
X# include	"limits.h"
X
X# define	min(x,y)	((x) > (y) ? (y) : (x))
X
X# define	TRUE	1
X# define	FALSE	0
X
Xstatic	int	bluffing=FALSE;		/* bluffing this hand? */
Xstatic	int	bluffmore=FALSE;	/* more bluff bets this hand? */
X
Xvoid	computer_bet( player, n_players, n_active, n_raises, pot, total, temp )
X
XPLAYER	player[];		/* player information & hands */
Xint	n_players;		/* number of players */
Xint	n_active;		/* number of players still in current hand */
Xint	n_raises;		/* # raises so far this betting session */
Xint	pot;			/* size of pot */
Xint	total;			/* current total bet */
Xchar	temp[];			/* return betting command here */
X
X{
Xint	raise;			/* amount to raise by */
Xint	chance;			/* rating of hand */
Xint	x;			/* random compared to chance to determine action */
Xint	top=(-1);		/* highest card hand has most of */
Xint	i;
Xstatic	int	lastpot=99999;	/* trick to only get random once per hand */
Xstatic	int	random_factor=0;
X
Xevaluate( player, 0 );
Xfor( i = 12; i > 0 ; i-- )
X	if ( top == -1 || player[0].count[i] > player[0].count[top] )
X		top = i;
Xif ( pot < lastpot )		/* things to be done once per hand */
X	{
X	random_factor = n_players * crandom( 10 );
X	if ( crandom( 20 ) < 1 )	/* bluff sometimes	*/
X		bluffing = TRUE;	/* 1 out of 20 chance 	*/
X	else
X		bluffing = FALSE;
X	bluffmore = bluffing;
X	}
Xlastpot = pot;
Xchance = player[0].score * player[0].score * 10 + top + 1 + random_factor ;
Xif ( bluffmore )
X	chance += n_players * 50;
Xif ( ( ( total < chance && crandom(10) < 6 ) || chance > total + 80 ) && n_raises < n_players )
X	{
X	raise = min( RAISE_LIMIT, (player[0].score + crandom(3) - 1) * 10 );
X	if ( raise <= 5 ) raise = 5;
X	if ( bluffing )
X		{
X		raise = RAISE_LIMIT - crandom( 2 ) * 10;
X		bluffmore = FALSE;
X		}
X	sprintf( temp, "R%d", min( RAISE_LIMIT, raise ) );
X	}
Xelse if ( total <= player[0].bet )
X	sprintf( temp, "P" );
Xelse if ( player[0].score >= THREE	/* 3 of a kind or better never folds */
X	|| ( n_active == 2 && player[0].score > NOTHING )
X	|| total < chance + 80 - 100 / n_players )	/* comparatively good hand */
X		{
X		sprintf( temp, "C" );
X		}
Xelse
X	sprintf( temp, "F" );
X}
X
Xvoid	computer_draw( player, temp )
X
XPLAYER	player[];		/* computer's hand is in here */
Xchar	temp[];			/* return command here */
X
X{
Xint	i,j;
X
X/* hand has already been evaluated by computer_bet() at least once. */
Xstrcpy( temp, "Dkkkkk" );
Xif ( player[0].score < STRAIGHT )	/* higher hands require no discards */
X	for( i=0; i<5; i++ )
X		{
X		for( j=0; j<5; j++ )
X			if ( i != j && card(player[0].cards[i]) == card(player[0].cards[j]) )
X				break;
X		if ( j == 5 )
X			{
X			temp[i+1] = 'd';	/* discard it */
X			}
X		}
Xbluffmore = bluffing;
X}
PaRtIcUlAtEmAtTeR
echo -n '	'
ls -l computer.c
echo x computer.h
sed -e 's/^X//' << 'PaRtIcUlAtEmAtTeR' > computer.h
X/*
X** This handles betting and drawing for the computer's hand.
X*/
X
Xextern	void	computer_bet();
Xextern	void	computer_draw();
PaRtIcUlAtEmAtTeR
echo -n '	'
ls -l computer.h
echo x draw.c
sed -e 's/^X//' << 'PaRtIcUlAtEmAtTeR' > draw.c
X/*
X** Let each player who is still in draw as many as 5 cards to replace
X** those he already has in his hand. This routines expects a command
X** of the form Dxxxxx  from each player program, where x is either
X** 'k'  to keep the card in that position, or
X** 'd'  to discard the card in that position.
X*/
X
X# include	"draw.h"
X# include	"players.h"
X# include	"showcards.h"
X# include	"tellall.h"
X
X# define	TRUE		1
X# define	FALSE		0
X
Xvoid	draw( player, n_players, deck, d, first )
X
XPLAYER	player[];		/* hands are in here */
Xint	n_players;		/* # of players */
Xint	deck[];			/* shuffled deck of cards */
Xint	d;			/* next card to take from deck */
Xint	first;			/* player who gets to draw first */
X
X{
Xint	i,c;
Xchar	temp[80];
Xchar	temp2[20];
Xint	n;
Xint	cycle=FALSE;
X
Xi = first;
Xwhile ( i != first || !cycle )
X	{
X	if ( player[i].in )
X		{
X		sprintf( temp, "T%d", i );
X		tellall( player, n_players, temp );
X		tellall( player, n_players, "U" );
X		if ( i == 0 )
X			computer_draw( player, temp );
X		else
X			{
X			writeln( player[i].socket, "D" );
X			readln( player[i].socket, temp );
X			}
X		if ( temp[0] != 'D' )	/* what else could it be ?? */
X			{
X			--i;		/* do this man again ! */
X			continue;
X			}
X		n = 0;
X		for( c=0; c<5; c++ )
X			if ( temp[c+1] == 'd' )
X				{
X				player[i].cards[c] = deck[d++];
X				n++;
X				}
X		if ( n == 0 )
X			strcpy( temp2, "Draws none" );
X		else
X			sprintf( temp2, "Draws %d", n );
X		sprintf( temp, "H%d%s", i, temp2 );
X		tellall( player, n_players, temp );
X		tellall( player, n_players, "U" );
X		if ( i != 0 )
X			{
X			show( player, temp, i, i );
X			writeln( player[i].socket, "U" );
X			}
X		}
X	if ( ++i == n_players )
X		{
X		cycle = TRUE;
X		i = 0;
X		}
X	}
X}
PaRtIcUlAtEmAtTeR
echo -n '	'
ls -l draw.c
echo x draw.h
sed -e 's/^X//' << 'PaRtIcUlAtEmAtTeR' > draw.h
X/*
X** Let each player who is still in draw cards to replace those he has.
X*/
X
Xextern	void	draw();
PaRtIcUlAtEmAtTeR
echo -n '	'
ls -l draw.h
echo x limits.h
sed -e 's/^X//' << 'PaRtIcUlAtEmAtTeR' > limits.h
X/*
X** Game limits.
X*/
X
X# define	ANTE		2
X# define	RAISE_LIMIT	50
PaRtIcUlAtEmAtTeR
echo -n '	'
ls -l limits.h
echo x main.c
sed -e 's/^X//' << 'PaRtIcUlAtEmAtTeR' > main.c
X/*
X** This is a program to handle a multi-user poker game. It uses sockets in
X** the AF_INET family, so it can handle several players even on different
X** machines. The game is 5-card draw poker.
X*/
X
X# include	<signal.h>
X# include	"cards.h"
X# include	"players.h"
X# include	"betting.h"
X# include	"draw.h"
X# include	"whowon.h"
X# include	"payoff.h"
X# include	"showcards.h"
X# include	"util.h"
X# include	"tellall.h"
X# include	"limits.h"
X
X# define	TRUE		1
X# define	FALSE		0
X# define	ERROR		-1
X
Xmain( argc, argv )
X
Xint	argc;
Xchar	**argv;
X
X{
Xint	i,c,d;
Xint	deck[52];		/* the cards */
Xint	pot;			/* size of current pot	*/
Xint	winner;			/* which player won this hand	*/
Xint	first=0;		/* first player to bet, draw, etc. */
X# ifdef MASSCOMP
Xextern	void	srand();
X# else
Xextern	void	srandom();	/* starts random number generator */
X# endif
Xextern	long	time();		/* unique parameter to above */
Xextern	void	crash();	/* if broken pipe, release port (I hope) */
Xextern	int	strcmp();
Xextern	int	getpid();	/* more random stuff */
X
Xsignal(SIGPIPE,crash);
Xsignal(SIGHUP,crash);
Xsignal(SIGXCPU,SIG_IGN);
X# ifdef MASSCOMP
X	srand((int) time(0) ^ getpid() );
X# else
X	srandom((int) time(0) ^ getpid() );
X# endif
Xplayer[0].name = strsave( "Computer III" );
Xplayer[0].cash = 200;
Xplayer[0].sittingout = FALSE;
Xplayer[0].wantsout = FALSE;
Xfor(;;)
X	{
X	if (n_players < 2)
X		new_players( player, &n_players, TRUE );	/* wait for someone to play with */
X	pot = 0;
X	for( i=0; i<n_players; i++)
X		{
X		if ( player[i].sittingout == FALSE )
X			{
X			player[i].in = TRUE;
X			player[i].bet = ANTE;	/* ante */
X			player[i].cash -= ANTE;
X			pot += ANTE;
X			}
X		else
X			{
X			player[i].in = FALSE;
X			player[i].bet = (-1);	/* keep tellall() quiet */
X			} 
X		if ( n_players == 2 )
X			player[i].lonehands += 1;
X		}
X	tellall( player, n_players, "X" );	/* clear all screens */
X	tellall( player, n_players, "U" );	/* clear all screens */
X	shuffle( deck );
X	d = 0;		/* next card to draw from deck */
X	for( c=0; c<5; c++ )
X		for( i=0; i<n_players; i++ )
X			if ( player[i].in )
X				player[i].cards[c] = deck[d++];
X	/* show cards to each player ... */
X	show_cards( player, n_players, FALSE, FALSE );
X	if ( ++first >= n_players )
X		first = 0;
X	if ((winner = betting( player, n_players, &pot, first )) < 0)
X		{
X		draw( player, n_players, deck, d, first );	
X		if ((winner = betting( player, n_players, &pot, first )) < 0)
X			winner = whowon( player, n_players, argc > 1 && strcmp( argv[1], "-test" ) == 0 );
X		else if ( argc > 1 && strcmp( argv[1], "-test" ) == 0 )
X			whowon( player, n_players, TRUE );
X		}
X	else if ( argc > 1 && strcmp( argv[1], "-test" ) == 0 )
X		whowon( player, n_players, TRUE );
X	payoff( player, n_players, winner, pot );
X	leave( player, &n_players );
X	new_players( player, &n_players, FALSE );
X	}
X}
PaRtIcUlAtEmAtTeR
echo -n '	'
ls -l main.c