[comp.sources.games] v03i077: challenge - a card game of skill, Part01/02

games-request@tekred.TEK.COM (01/26/88)

Submitted by: "Dik T. Winter" <mcvax!cwi.nl!dik@uunet.uu.net>
Comp.sources.games: Volume 3, Issue 77
Archive-name: challenge/Part01

	[This should be portable to SYSV or BSD or Sun; it works fine
	 on out 4.3bsd Vax.  Below is a note from the author.  -br]

[[Challenge is a card games for two players, where the two play against
each other.  Unlike other card games, in challenge you have full
knowledge about the position of all cards, so it is essenntially a
game of skill (like chess).  I do not know whether the game is a
first player win or not; analysis is much too difficult for my skills.]]

#! /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 2)."
# Contents:  README MANIFEST challenge.doc challenge.h human.c main.c
#   strategy.c
# Wrapped by billr@saab on Mon Jan 25 11:17:10 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f README -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"README\"
else
echo shar: Extracting \"README\" \(2679 characters\)
sed "s/^X//" >README <<'END_OF_README'
XThis program has been compiled on Vax and Tahoe with BSD 4.3; Sun with
XBSD 4.2 (SUNOS 3.0); 3b2 with SysVR2.0.1; and even bizarre systems as
XDG with MV/UX 3.0 Sys V emulation (set line discipline to 1) and CDC Cyber
Xwith VX/VE Sys V emulation (set line discipline to 0; why cannot this be
Xstandardised?).  So there should be no major problems.
X
XTo compile it you need curses.  A minimal set will do (e.g. compilation
Xwith -DMINICURSES as it is available on some systems) as the program
Xuses curses mainly as a termcap/terminfo frontend.  So perhaps PCcurses
Xmight do.
X
XNo effort has been made to insure uniqueness within the first N symbols
Xof an identifier; so if your compiler has limits on that something may go
Xwrong.
X
XCompilation options are:
X-DSYSV		If System V lookalike (mainly: curses provides kill and
X		erase character through functions rather than the
X		sgttyb structure; check for killchar() and erasechar()
X		in curses; if present set this option).
X-DSHELL		Allow calling of subshell from the program.  This requires
X		the Unix process spawning interface.  (If somebody wants
X		to implement other interfaces, go ahead, and mail the
X		results to me.  Everything occurs in human.c.)
X-DTIMER=1	Definition of this flag requires the alarm system call.
X		When set the program will update a running clock when
X		the computer is thinking.  The value specifies the number
X		of seconds between updates.
X-DDEBUG		To debug the computers strategy.
X
XThe computer strategy is not yet perfect; it is still possible to win
Xwith larger packs.  A better strategy might be possible.  And it is quite slow.
X
XThe following source files are within this package:
Xchallenge.h	Common header file.  It is bad programming to put
X		everything in a common file, but it is done here.
X		So if you change this file everything will recompile.
Xmain.c		Main program; controls the overall game and the general io.
Xhuman.c		Provides the human interface.
Xstrategy.c	The computers strategy.
Xalarm.c		For timer handling (used only if TIMER is defined).
Xlogging.c	Provides the interface to the transcription of games.
Xdemo.c		Provides demonstration.  There is no delay built into this
X		part, so a demonstration can be quite incomprehensible at
X		higher speeds.  Something ought to be done here.
Xinstructions.c	Provides instructions.
X
XDocumentation files:
Xchallenge.6	A man page.
Xchallenge.doc	A general introduction.  (No formatting has been done;
X		you have to take it as it is.)
X
XIf you make any modifications and/or additions, please mail the result to me.
X
Xdik t. winter, cwi, amsterdam, nederland
XInternet:	dik@cwi.nl
XBITNET:		dik@mcvax
Xold-UUCP:	uunet!"dik@cwi.nl" or uunet!mcvax!dik  (no guarantee)
END_OF_README
if test 2679 -ne `wc -c <README`; then
    echo shar: \"README\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f MANIFEST -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"MANIFEST\"
else
echo shar: Extracting \"MANIFEST\" \(504 characters\)
sed "s/^X//" >MANIFEST <<'END_OF_MANIFEST'
X   File Name		Archive #	Description
X-----------------------------------------------------------
X MANIFEST                  1	This shipping list
X Makefile                  2	
X README                    1	
X alarm.c                   2	
X challenge.6               2	
X challenge.doc             1	
X challenge.h               1	
X demo.c                    2	
X human.c                   1	
X instructions.c            2	
X logging.c                 2	
X main.c                    1	
X strategy.c                1	
END_OF_MANIFEST
if test 504 -ne `wc -c <MANIFEST`; then
    echo shar: \"MANIFEST\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f challenge.doc -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"challenge.doc\"
else
echo shar: Extracting \"challenge.doc\" \(8404 characters\)
sed "s/^X//" >challenge.doc <<'END_OF_challenge.doc'
XChallenge.
X
XThe game played by this program is based on the game challenge described
Xby the bridge journalist Hubert Phillips.
XTo quote from his description:
X"Challenge is a game of pure skill.
XHere two players play alternately, as in chess; and, as in chess, the
Xplayer will win who can calculate accurately for the larger number of
Xmoves ahead.
XThe mental processes required for challenge are, indeed, very similar
Xto the mental processes required for chess.
XThis is not true of any other card game."
XHe further relates how the game was introduced to the university of Cambridge
Xby Professor A.S.Besicovitch, under the russian name "Svoyi Koziri".
XApparently Cambridge is the only place where it has been played.
X
XThe game played by the program differs from the original game in only one
Xsense as will be shown below.
XAlthough this change changes the nature of the game a bit, it is (at least
Xin our opinion) not easier than the original.
XIt requires as much skill, and we think it is even a bit harder.
X
XThe mechanics of the game.
X
XChallenge in its standard form is played with a pack of 32 cards, each suit
Xconsists of eight cards: Aces down to 8's.
XIt is also possible to play it with packs of 28, 24 or even less cards to
Xmake a simpler game.
XOf course also more than 32 cards can be used for a more difficult game.
X
XFirst the dealer nominates one suit - it does not matter which - as his
Xtrumps, next the non-dealer nominates another suit as his trumps (note
Xthat the players have different trumps), and lastly the dealer nominates
Xone of the remaining suits as secondary suit.
XThis last is not important for the game itself, but only for the deal.
XTo make the program simpler, within the program the computer has always
XSpades as his trump suit while the opponent always has Hearts as trumps.
X
XNext the dealer shuffles the cards and takes 16 cards (or half the pack if there
Xare less or more than 32 cards).
XFrom these 16 cards the dealer takes all his trumps and all the cards
Xof his secondary colour.
XThe non-dealer takes all dealers trumps and dealers secondary cards from
Xthe remaining 16 cards.
XNext the non-dealer selects from his trump suit the cards corresponding
Xto the cards the dealer has from the dealers trump suit, and the same
Xhappens with the fourth colour corresponding to the dealers secondary
Xcolour.
XThe dealer now takes the remaining cards.
XAfter this the hands of dealer and non-dealer are symmetric.
XThus if dealers trumps are Spades and his secondary colour are Clubs,
Xand non-dealers trumps are Hearts, dealer might have:
X	Spades  : A Q 10 8
X	Clubs   : Q 10 8
X	Diamonds: A K J 9 7
X	Hearts  : K J 9 7
Xand non-dealer has in this case (exactly corresponding):
X	Hearts  : A Q 10 8
X	Diamonds: Q 10 8
X	Clubs   : A K J 9 7
X	Spades  : K J 9 7
XNote that it might occur that you do not have any trumps, but in that
Xcase the other party will also not have any trumps!
X
XNow play begins, non-dealer lays a card face upwards on the table.
XDealer now must either play a better card, or pick up the card from
Xthe table.
XBy a 'better card' is meant a higher card of the suit of the card
Xon the table, or one of his trumps.
XOf course if the card lead is one of his trumps, he has to play a
Xhigher trump.
XThere is no obligation to play a better card, or to follow suit.
XNow players alternate moves, each either playing a better card
Xor taking the cards on the table, not only the last-played card,
Xbut all the cards on the table.
XThe object of the game is to play your last card.
X
XHere the game played by the program differs a bit from the original.
XIn the original game a player who played a better card immediately
Xlead a new card; in the programs version if a player plays a better
Xcard that is the end of his turn, and he does not lead.
X
XIn normal play amongst humans you see only the cards that you have
Xin your hands and the card on top of the stack on the table, so it
Xis a bit easier for the player with the better memory.  As the
Xcomputers memory is apparently quite good, and this would give the
Xcomputer a very high advantage, the program displays not only your
Xcards during play, but also the cards the computer has and the
Xcards on the table.
X
XThe program.
X
XThe calling sequence for the program is:
X	challenge -ssize -ddepth -afile -ooptions
Xthe parameters have the following meaning:
X	-ssize		size is one of the digits 1 to 8.  This
X			parameter defines the size of the pack of
X			cards to be used.  With -s1 only aces are
X			used, with -s8 a complete pack of 32 cards.
X			The default is 8.
X
X	-ddepth		depth is a number larger than or equal to 0.
X			This parameter specifies the search depth for
X			the computers strategy.  Decreasing depth
X			simplifies the game, while increasing it makes
X			it more difficult (at the expense of time of
X			course).  -d0 is very simple to play agains.
X			The default is 4.
X
X	-ooptions	options is a string of letter, each identifying
X			a program toggle.  Specifying a letter will
X			toggle the associated option.  See below for the
X			toggles that are present, and what they do.
X			-ohh toggles the 'h' toggle twice and is effectively
X			a no-op of course.
X
X	-afile		here file is a filename or empty.  With this option
X			analysing mode is entered; see below for details.
X
XWhen the program is entered you are asked for commands.  When it is your
Xturn you may:
X1.	nominate a card to be played.  You specify a card by giving its
X	suit and its value; order and case are not significant.  You may
X	indicate tens by '10', 't' or 'x' and aces by 'a' or '1'.  So
X	the 10 of spades may be specified as S10, ts or Xs or some other
X	variation.
X2.	tell that you want to pick up the cards on the table.  You do this
X	with the command 'p'.
X3.	use one of the extended commands shown in the window in the upper
X	right corner of your screen; they are all prefixed by a exclamation
X	mark.
X4.	If you enter a question mark the program will show you the cards
X	you can play.
X5.	When in analysing mode there are two more commands available;
X	see below for details.
X
XAnalysing mode.
X
XYou enter analysing mode either with the -a parameter on the command
Xline or at the and of a game by entering the 'a' reply.  There are
Xtwo forms of analysing mode:
Xnormal:	You enter this mode if you reply 'a' at the end of a game of
X	when you give a filename on the command line.  You will be
X	put in control again at the end of the game (if a file is
X	given, the game is read in from that file), and you can play
X	with it using the commands above and the auxiliary commands
X	below.
Xsetup:	You enter this mode if you give the -a option, but no file
X	name on the command line.  The program will put you in control
X	with all the cards in your hand, and no cards on the table or
X	in the computers 'hand'.  By playing cards and letting the computer
X	pick up (he must if you do this correctly), you can achieve
X	every starting position.
XThe following auxiliary commands are available in this mode:
X6.	'b' for back up.  Backs up one move for both you and the computer.
X7.	'z' for pass.  Pass the move to the computer again.  This is useful
X	in setup mode if you have achieved the hand you wanted and the
X	computer should start.
X
XExtra commands.
X
XA number of extra commands are available.  The set depends on the mode
Xyou are playing in.  A list of commands is given in the window in the
Xupper right corner of your screen.  The following commands are possible:
X!a	When in analysing mode: return to game mode, read in next game,
X	or set up next game.
X!c	When in analysing mode: consult the computer for a suggested move.
X!d	When in game mode: propose a draw.  This may only be given if
X	the table is empty.
X!f	Announce you have a forced win.  This may only be announced if the
X	table is empty.  The program is very conservative in deciding whether
X	a given hand is a forced win!
X!h	Toggles the 'h' toggle.  If on, the program will mark the cards
X	you may play on every turn (this is equivalent to entering a question
X	mark on every turn).
X!i	Give instructions.
X!l	Toggles the 'l' toggle.  If on, the game will be logged onto the
X	file 'challenge.log', for subsequent use by the program in
X	analysing mode.  If this toggle is put on during a game, the game
X	will be logged from the start.
X!r	Resign.  Normally this is accepted.
X!s	Go into a sub-shell.
X!w	Toggles the 'w' toggle.  If on, the extra commands window is not
X	displayed (although the commands are still available of course).
X
END_OF_challenge.doc
if test 8404 -ne `wc -c <challenge.doc`; then
    echo shar: \"challenge.doc\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f challenge.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"challenge.h\"
else
echo shar: Extracting \"challenge.h\" \(1972 characters\)
sed "s/^X//" >challenge.h <<'END_OF_challenge.h'
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1988. */
X/* Permission granted to redistribute this program. */
X
X#include <curses.h>
X#include <signal.h>
X#include <ctype.h>
X
X#define COMPUTER	3
X#define TABLE		9
X#define HUMAN		15
X
X#define MARGIN		7
X#define R_MARGIN	57
X#define COMMAND_LINE	22
X#define COMMENT_LINE	20
X#define COMMAND_POS	10
X
X#define MAX_CARD	32
X#define MAX_SUIT	8
X
X#define SPADES		0
X#define CLUBS		1
X#define DIAMONDS	2
X#define HEARTS		3
X
X#define ACE		0
X#define KING		1
X#define QUEEN		2
X#define JACK		3
X#define C_10		4
X#define C_9		5
X#define C_8		6
X#define C_7		7
X#define C_6		8
X#define C_5		9
X#define C_4		10
X#define C_3		11
X#define C_2		12
X
X#define PICK_UP		MAX_CARD
X#define RESIGN		(PICK_UP+1)
X#define DRAWN		(PICK_UP+2)
X#define WIN		(PICK_UP+3)
X#define PASS		(PICK_UP+4)
X#define BACK_UP		(PICK_UP+5)
X#define ANAL_END	(PICK_UP+6)
X
X#define SUIT(x)		((x)%4)
X#define VALUE(x)	((x)/4)
X
X#define ROW(player,suit,value)	((player)+(suit))
X#define COL(player,suit,value)	(MARGIN+18+(value)*4)
X
X#ifdef EXTERN
X#define INIT(x)	=x;
X#else
X#define EXTERN	extern
X#define INIT(x)
X#endif
X
XEXTERN int start_player INIT(HUMAN);
XEXTERN int depth INIT(4);
XEXTERN int size INIT(8);
XEXTERN int size2, max_card;
X
XEXTERN char computer[MAX_CARD], human[MAX_CARD], table[MAX_CARD], top;
XEXTERN int nr_computer, nr_human, nr_table;
X
XEXTERN long seed;
X
XEXTERN int nasty();
X
XEXTERN int computer_score INIT(0);
XEXTERN int human_score INIT(0);
XEXTERN char no_scoring INIT(FALSE);
XEXTERN char analysing INIT(FALSE);
X
XEXTERN char s_computer[MAX_CARD], s_human[MAX_CARD], moves[2048];
XEXTERN unsigned long pick_ups[2048];
X
XEXTERN FILE *logfile INIT(NULL);
XEXTERN FILE *old_logfile INIT(NULL);
XEXTERN FILE *save_logfile;
XEXTERN int nr_moves, move_logged;
X
X#ifdef TIMER
XEXTERN int timer();
XEXTERN int minutes, seconds;
X#endif
X
XEXTERN int demo INIT(0);
X
X#ifdef SYSV
X#define KILL	killchar()
X#define ERASE	erasechar()
X#else
X#define KILL	_tty.sg_kill
X#define ERASE	_tty.sg_erase
X#endif
X
END_OF_challenge.h
if test 1972 -ne `wc -c <challenge.h`; then
    echo shar: \"challenge.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f human.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"human.c\"
else
echo shar: Extracting \"human.c\" \(12558 characters\)
sed "s/^X//" >human.c <<'END_OF_human.c'
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1988. */
X/* Permission granted to redistribute this program. */
X
X#include "challenge.h"
X
Xchar help_always = FALSE;
Xchar helped = FALSE;
Xchar fin_text[] = "game is finished, you can back up only";
X
Xhuman_interface()
X{
X    int valid_input = FALSE;
X    char input[4];
X    int i, suit, value, ptr, r;
X
X    if(help_always) {
X	help('*', FALSE);
X	helped = TRUE;
X    }
X    while(!valid_input) {
X    again:
X	ptr = COMMAND_POS;
X	move(COMMAND_LINE, ptr);
X	clrtoeol();
X	i = -1;
X    again1:
X	refresh();
X	while(TRUE) {
X	    i++;
X	    input[i] = getch();
X	    if((input[i] == '\n') ||
X	       (input[i] == '\r')) {
X		if(i-- == 0) goto again;
X		break;
X	    }
X	    if(input[i] == KILL) {
X		goto again;
X	    }
X	    if((input[i] == ('L' & 037)) ||
X	       (input[i] == ('R' & 037))) {
X		i--;
X		clearok(curscr, TRUE);
X		goto again1;
X	    }
X	    if(input[i] == '?' && i == 0) {
X		if(!helped) {
X		    help('*', TRUE);
X		}
X		helped = TRUE;
X		goto again;
X	    }
X	    if(input[i] == ERASE) {
X		if(ptr > 10) {
X		    ptr--;
X		    i -= 2;
X		    move(COMMAND_LINE, ptr);
X		    addch(' ');
X		}
X		move(COMMAND_LINE, ptr);
X		refresh();
X	    } else if((input[i] == ' ') ||
X		  (input[i] == '\t')) {
X		i--;
X	    } else if((i == 3) ||
X		  (input[i] < ' ') ||
X		  (input[i] > '|')) {
X		i--;
X		putchar(007);
X		fflush(stdout);
X	    } else {
X		move(COMMAND_LINE, ptr);
X		addch(input[i]);
X		refresh();
X		ptr++;
X	    }
X	}
X	input[++i] = 0;
X	for(i = 0; i < 4; i++) {
X	    if(isalpha(input[i]) && isupper(input[i])) {
X		input[i] = tolower(input[i]);
X	    }
X	}
X	if(input[0] == '!') {
X	    if(input[2] == 0) {
X		r = extended_command(input[1]);
X		if(r != 0) {
X		    if(helped) {
X			help(' ', FALSE);
X			helped = FALSE;
X		    }
X		    return(r);
X		}
X		goto again;
X	    }
X	} else {
X	    i = 0;
X	    suit = -1;
X	    value = -1;
X	    switch(input[0]) {
X	    case 's':
X	    case 'c':
X	    case 'd':
X	    case 'h':
X		suit = get_suit(input, &i);
X		value = get_value(input, &i);
X		break;
X	    default:
X		value = get_value(input, &i);
X		suit = get_suit(input, &i);
X	    }
X	    if((input[0] == 'p') && (input[1] == 0)) {
X		if(top == PICK_UP) {
X		    move(COMMAND_LINE - 1, 1);
X		    clrtoeol();
X		    printw("there is nothing to pick up");
X		    goto again;
X		}
X		if(nr_computer == 0 || nr_human == 0) {
X		    move(COMMAND_LINE - 1, 1);
X		    clrtoeol();
X		    printw(fin_text);
X		    goto again;
X		}
X		i = PICK_UP;
X		valid_input = TRUE;
X	    } else if((input[0] == 'z') && (input[1] == 0) && analysing) {
X		if(nr_computer == 0 && top == PICK_UP) {
X		    move(COMMAND_LINE - 1, 1);
X		    clrtoeol();
X		    printw("computer has nothing to do");
X		    goto again;
X		}
X		if(nr_computer == 0 || nr_human == 0) {
X		    move(COMMAND_LINE - 1, 1);
X		    clrtoeol();
X		    printw(fin_text);
X		    goto again;
X		}
X		i = PASS;
X		valid_input = TRUE;
X	    } else if((input[0] == 'b') && (input[1] == 0) && analysing) {
X		if(nr_moves < 2) {
X		    move(COMMAND_LINE - 1, 1);
X		    clrtoeol();
X		    printw("you have not yet done any move");
X		    goto again;
X		}
X		i = BACK_UP;
X		valid_input = TRUE;
X	    } else if((suit >= 0) && (value >= 0)) {
X		if((nr_computer == 0 || nr_human == 0) &&
X			(nr_human != max_card)) {
X		    move(COMMAND_LINE - 1, 1);
X		    clrtoeol();
X		    printw(fin_text);
X		    goto again;
X		}
X		if(input[i] == 0) {
X		    i = have_it(value * 4 + suit);
X		    if(i >= 0) {
X			if(!valid(HUMAN, i)) {
X			    move(COMMAND_LINE - 1, 1);
X			    clrtoeol();
X			    printw("you can not play that card");
X			    goto again;
X			} else {
X			    valid_input = TRUE;
X			}
X		    } else {
X			move(COMMAND_LINE - 1, 1);
X			clrtoeol();
X			printw("you do not have that card");
X			goto again;
X		    }
X		}
X	    }
X	}
X	if(!valid_input) {
X	    move(COMMAND_LINE - 1, 1);
X	    clrtoeol();
X	    printw("i do not understand, please retype");
X	}
X    }
X    if(helped) {
X	help(' ', FALSE);
X	helped = FALSE;
X    }
X    return(i);
X}
X
Xget_suit(input, i)
X    char *input;
X    int *i;
X{
X    if(*i > 3) {
X	return(-1);
X    }
X    switch(*(input + (*i)++)) {
X    case 's':
X	return(SPADES);
X    case 'c':
X	return(CLUBS);
X    case 'd':
X	return(DIAMONDS);
X    case 'h':
X	return(HEARTS);
X    }
X    return(-1);
X}
X
Xget_value(input, i)
X    char *input;
X    int *i;
X{
X    if(*i > 3) {
X	return(-1);
X    }
X    switch(*(input + (*i)++)) {
X    case 'a':
X	return(ACE);
X    case 'k':
X	return(KING);
X    case 'q':
X	return(QUEEN);
X    case 'j':
X	return(JACK);
X    case 't':
X    case 'x':
X	return(C_10);
X    case '9':
X	return(C_9);
X    case '8':
X	return(C_8);
X    case '7':
X	return(C_7);
X    case '6':
X	return(C_6);
X    case '5':
X	return(C_5);
X    case '4':
X	return(C_4);
X    case '3':
X	return(C_3);
X    case '2':
X	return(C_2);
X    case '1':
X	if(*(input + *i) != '0') {
X	    return(ACE);
X	}
X	if((*(input + *i) == '0') && ((*i)++ <= 3)) {
X	    return(C_10);
X	}
X    }
X    return(-1);
X}
X
Xhelp(c, do_print)
X    char c, do_print;
X{
X    int i, count = 0;
X
X    if(c == ' ') {
X	move(COMMAND_LINE - 1,1);
X	clrtoeol();
X    }
X    for(i = 0; i < nr_human; i++) {
X	if(valid(HUMAN, i)) {
X	    move(ROW(HUMAN,SUIT(human[i]),VALUE(human[i])),
X		 COL(HUMAN,SUIT(human[i]),VALUE(human[i]))+2);
X	    addch(c);
X	    count++;
X	}
X    }
X    if(do_print) {
X	move(COMMAND_LINE - 1,1);
X	clrtoeol();
X	if(!count) {
X	    printw("you cannot play any card, but you can pick-up");
X	} else if(count > 1) {
X	    printw("you can play the cards marked by an asterisk");
X	} else {
X	    printw("you can play the card marked by an asterisk");
X	}
X    }
X}
X
Xhave_it(card)
X    int card;
X{
X    int i;
X
X    for(i = 0; i < nr_human; i++) {
X	if(human[i] == card) {
X	    return(i);
X	}
X    }
X    return(-1);
X}
X
Xchar *additional_commands[] = {
X	"| extra commands:",
X/* a */ "| !a stop analysis",
X/* b */ 0,
X/* c */ "| !c consult computer",
X/* d */ "| !d propose a draw",
X/* e */ 0,
X/* f */ "| !f have a forced win",
X/* g */ 0,
X/* h */ 0, /* reserved for help toggling */
X/* i */ "| !i give instructions",
X/* j */ 0,
X/* k */ 0,
X/* l */ 0, /* reserved for log toggling */
X/* m */ 0,
X/* n */ 0,
X/* o */ 0,
X/* p */ 0,
X/* q */ 0,
X/* r */ "| !r resign",
X#ifdef SHELL
X/* s */ "| !s execute subshell",
X#else
X/* s */ 0, /* reserved for subshell execution */
X#endif
X/* t */ 0,
X/* u */ 0,
X/* v */ 0,
X/* w */ "| !w clear this window",
X/* x */ 0,
X/* y */ 0,
X/* z */ 0,
X	"+---------------------",
X0};
X
Xchar *n_additional_commands[sizeof(additional_commands)];
X
Xchar always_help[] = {
X	"| !h always help"};
Xchar never_help[] = {
X	"| !h help on request"};
X
Xchar start_logging[] = {
X	"| !l start logging"};
Xchar stop_logging[] = {
X	"| !l stop logging"};
X
X#ifdef SHELL
Xchar *getenv();
X#endif
X
X#define ADDCOM(c)    n_additional_commands[c-'a'+1]
X
Xchar display_window = TRUE;
X
Xdisplay_extra()
X{
X    char c, i, count = 0;
X
X    for(i = 0; i < sizeof(additional_commands); i++) {
X	n_additional_commands[i] = additional_commands[i];
X    }
X    if(!analysing) {
X	ADDCOM('a') = 0;
X	ADDCOM('c') = 0;
X    }
X    if(help_always) {
X	ADDCOM('h') = never_help;
X    } else {
X	ADDCOM('h') = always_help;
X    }
X    if(analysing) {
X	ADDCOM('l') = 0;
X    } else if(logfile == NULL) {
X	ADDCOM('l') = start_logging;
X    } else {
X	ADDCOM('l') = stop_logging;
X    }
X    if(analysing) {
X	ADDCOM('d') = 0;
X	ADDCOM('f') = 0;
X	ADDCOM('r') = 0;
X    }
X    for(i = 0; i < 'z'-'a'+3; i++) {
X	if(n_additional_commands[i] != 0) {
X	    move(count, R_MARGIN);
X	    if(display_window) {
X		printw(n_additional_commands[i]);
X	    }
X	    clrtoeol();
X	    count++;
X	}
X    }
X    for(;count < COMMENT_LINE - 1; count++) {
X	move(count, R_MARGIN);
X	clrtoeol();
X    }
X}
X
Xextended_command(c)
X    char c;
X{
X    char i, count;
X
X    if(isalpha(c) && isupper(c)) {
X	c = tolower(c);
X    }
X    c = option(c);
X    display_extra();
X    return(c);
X}
X
Xint command_line = FALSE;
X
Xoption(c)
X    char c;
X{
X    char i, res = 0, *str;
X
X    switch(c) {
X    case 'a':
X	if(command_line) {
X	    break;
X	}
X	prw("exiting analysis mode");
X	sleep(1);
X	res = ANAL_END;
X	break;
X    case 'c':
X	if(command_line) {
X	    break;
X	}
X	if(!analysing) {
X	    prw("i do not understand this command");
X	    break;
X	}
X	prw("");
X	move(COMMAND_LINE, COMMAND_POS);
X	clrtoeol();
X	printw("consulting..");
X	refresh();
X	i = strategy(HUMAN);
X	move(COMMAND_LINE - 1, 1);
X	if(i < MAX_CARD) {
X	    printw("computer suggests ");
X	    display_full(human[i]);
X	} else {
X	    printw("computer suggests to pick up");
X	}
X	break;
X    case 'd':
X	if(command_line) {
X	    break;
X	}
X	if(analysing) {
X	    prw("i do not understand this command");
X	    break;
X	}
X	prw("consulting your opponent");
X	refresh();
X	sleep(1);
X	if(!accept_draw()) {
X	    prw("the computer does not accept");
X	} else {
X	    prw("the computer gleefully accepts");
X	    res = DRAWN;
X	}
X	if(res == DRAWN) {
X	    refresh();
X	    sleep(1);
X	}
X	break;
X    case 'f':
X	if(command_line) {
X	    break;
X	}
X	if(analysing) {
X	    prw("i do not understand this command");
X	    break;
X	}
X	prw("do you really have a forced win? (y/n) ");
X	refresh();
X	if(!yesno()) {
X	    prw("");
X	    break;
X	}
X	prw("I have to consult your opponent");
X	refresh();
X	sleep(1);
X	if(winning(HUMAN)) {
X	    prw("the computer agrees");
X	    res = WIN;
X	} else {
X	    prw("the computer does not think so; you have to show it");
X	}
X	if(res == WIN) {
X	    refresh();
X	    sleep(1);
X	}
X	break;
X    case 'h':
X	help_always = !help_always;
X	if(help_always) {
X	    help('*', FALSE);
X	    helped = TRUE;
X	    prw("will always mark possible cards");
X	} else {
X	    help(' ', FALSE);
X	    helped = FALSE;
X	    prw("will mark possible cards on request only");
X	}
X	if(command_line) {
X	    sleep(1);
X	}
X	break;
X    case 'i':
X	if(command_line) {
X	    break;
X	}
X	put_instructions(FALSE);
X	printw("enter space to return\n");
X	refresh();
X	getch();
X	redraw();
X	break;
X    case 'l':
X	if(logfile == NULL) {
X	    open_log();
X	    if(logfile == NULL) {
X		prw("cannot open logfile");
X	    } else {
X		prw("logging started on file \"challenge.log\"");
X	    }
X	} else {
X	    prw("logging stopped");
X	    record_stop();
X	    move_logged = 0;
X	}
X	if(command_line) {
X	    sleep(1);
X	}
X	break;
X    case 'r':
X	if(command_line || analysing) {
X	    break;
X	}
X	prw("do you really want to resign? (y/n) ");
X	refresh();
X	if(!yesno()) {
X	    prw("");
X	    break;
X	}
X	prw("the computer accepts");
X	refresh();
X	sleep(1);
X	res = RESIGN;
X	break;
X#ifdef SHELL
X    case 's':
X	if(command_line) {
X	    break;
X	}
X	if(child()) {
X	    if(str = getenv("SHELL")) {
X		execl(str, str, (char *) 0);
X	    } else {
X		execl("/bin/sh", "sh", (char *) 0);
X	    }
X	    printf("%s: cannot execute", str);
X	    sleep(1);
X	    exit(1);
X	}
X	redraw();
X	res = 0;
X	break;
X#endif
X    case 'w':
X	display_window = !display_window;
X	if(!display_window && !command_line) {
X	    prw("you get the window back when you enter the same command");
X	}
X	break;
X    default:
X	if(!command_line) {
X	    prw("i do not understand this command");
X	}
X    }
X    return(res);
X}
X
Xcheck_options(c)
X    char *c;
X{
X    command_line = TRUE;
X    while(*c != 0) {
X	option(*c++);
X    }
X    command_line = FALSE;
X}
X
Xprw(c)
X    char *c;
X{
X    if(command_line) {
X	printf(c);
X	printf("\n");
X    } else {
X	move(COMMAND_LINE - 1, 1);
X	printw(c);
X	clrtoeol();
X    }
X}
X
X/* should be interfaced with strategy */
Xwinning(player)
X    int player;
X{
X    char hand[4][MAX_SUIT], count[4], tops[4];
X    int suit, value, diff, i, j;
X
X    if(player == COMPUTER) {
X	return(FALSE);
X    }
X    if(top != PICK_UP) {
X	return(FALSE);
X    }
X    for(i = 0; i < 4; i++) {
X	count[i] = 0;
X	tops[i] = 0;
X	for(j = 0; j < size; j++) {
X	    hand[i][j] = FALSE;
X	}
X    }
X    for(i = 0; i < nr_human; i++) {
X	suit = SUIT(human[i]);
X	value = VALUE(human[i]);
X	hand[suit][value] = TRUE;
X	count[suit]++;
X    }
X    for(i = 0; i < 4; i++) {
X	for(j = 0; j < size && hand[i][j]; j++) {
X	    tops[i]++;
X	}
X    }
X    if(tops[SPADES] >= nr_human - 1) {
X	return(TRUE);
X    }
X    if(count[SPADES] == size) {
X	i = count[CLUBS] + count[DIAMONDS] + count[HEARTS];
X	j = tops[CLUBS] + tops[DIAMONDS] + tops[HEARTS];
X	return((i - j) <= 1);
X    }
X    return(tops[HEARTS] >= nr_human + 1);
X}
X
X#ifdef SHELL
X/* free after hack */
Xchild()
X{
X    int f = fork();
X
X    move(COMMAND_LINE + 1, 0);
X    clrtoeol();
X    refresh();
X    if(f == 0) {        /* child */
X	endwin();
X	return(TRUE);
X    }
X    if(f == -1) {    /* cannot fork */
X	printw("fork failed, try again");
X	refresh();
X	sleep(1);
X	return(FALSE);
X    }
X    /* fork succeeded; wait for child to exit */
X    endwin();
X    signal(SIGINT,SIG_IGN);
X    signal(SIGQUIT,SIG_IGN);
X    wait((union wait *) 0);
X    initscr();
X    crmode();
X    noecho();
X    clear();
X    signal(SIGINT, nasty);
X    signal(SIGQUIT, nasty);
X    return(FALSE);
X}
X#endif
X
END_OF_human.c
if test 12558 -ne `wc -c <human.c`; then
    echo shar: \"human.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f main.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"main.c\"
else
echo shar: Extracting \"main.c\" \(14394 characters\)
sed "s/^X//" >main.c <<'END_OF_main.c'
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1988. */
X/* Permission granted to redistribute this program. */
X
X#define EXTERN
X
X#include "challenge.h"
X
Xint quit();
X
X/*
X   main program performs program parameter checking, curses initialization
X   and game set up
X*/
Xmain(argc,argv)
X    int argc;
X    char *argv[];
X{
X    char c;
X
X    /*
X       parameter checking.
X    */
X    while(argc > 1) {
X	if(argv[1][0] == '-') {
X	    switch(argv[1][1]) {
X	    case 'd':
X		depth = atoi(&argv[1][2]);
X		if(depth < 0) {
X		    printf("depth should be 0 or larger\n");
X		    exit(0);
X		}
X		break;
X	    case 's':
X		size = atoi(&argv[1][2]);
X		if(size < 1 || size > 8) {
X		    printf("size should be between 1 and 8\n");
X		    exit(0);
X		}
X		break;
X	    case 'a':
X		no_scoring = TRUE;
X		analysing = TRUE;
X		if(argv[1][2] != 0) {
X		    logfile = fopen(&argv[1][2], "r");
X		    if(logfile == NULL) {
X			printf("cannot open game file\n");
X			exit(0);
X		    }
X		}
X		break;
X	    case 'o':
X		check_options(&argv[1][2]);
X		break;
X	    default:
X		usage();
X	    }
X	}
X	else usage();
X	argv++;
X	argc--;
X    }
X    /* general initializations */
X    seed = time(0);
X#ifdef TIMER
X    signal(SIGALRM,timer);
X#endif
X    signal(SIGQUIT,quit);
X    signal(SIGINT,quit);
X    initscr();
X    crmode();
X    noecho();
X    if(LINES < 24 || COLS < 80) {
X	endwin();
X	printf("challenge needs at least 24 rows and 80 columns.\n");
X	exit(1);
X    }
X    clear();
X    if(!analysing) {
X	move(COMMAND_LINE - 2, 1);
X	printw("do you want instructions? (y/n) ");
X	refresh();
X	if(yesno()) {
X	    put_instructions(TRUE);
X	    clear();
X	}
X	move(COMMAND_LINE - 1, 1);
X	printw("do you want a demonstration game? (y/n) ");
X	refresh();
X	if(yesno()) {
X	    for(;;) {
X		demo = COMPUTER;
X		init();
X		redraw();
X		do_demo();
X		move(COMMAND_LINE + 1,1);
X		clrtoeol();
X		move(COMMAND_LINE,1);
X		clrtoeol();
X		printw("another demo? (y/n) ");
X		refresh();
X		if(!yesno()) {
X		    break;
X		}
X	    }
X	    human_score = 0;
X	    computer_score = 0;
X	    demo = 0;
X	}
X	move(COMMAND_LINE,1);
X	clrtoeol();
X	printw("do you want me to start? (y/n) ");
X	refresh();
X	if(yesno()) {
X	    start_player = COMPUTER;
X	}
X	signal(SIGINT, nasty);
X	signal(SIGQUIT, nasty);
X    }
X    /* loop through games */
X    for(;;) {
X	if(!analysing || no_scoring) {
X	    init();
X	    redraw();
X	} else if(!no_scoring) {
X	    move(COMMENT_LINE, 1);
X	    clrtoeol();
X	    move(COMMAND_LINE - 1, 1);
X	    clrtoeol();
X	    move(COMMAND_LINE, 1);
X	    clrtoeol();
X	    printw("command:");
X	    move(COMMAND_LINE + 1, 1);
X	    clrtoeol();
X	    printw("you have now the additional b command available for back-up");
X	    display_extra();
X	    refresh();
X	}
X	play_challenge(start_player);
X	move(COMMAND_LINE + 1,1);
X	clrtoeol();
X	move(COMMAND_LINE,1);
X	clrtoeol();
X	signal(SIGINT, quit);
X	signal(SIGQUIT, quit);
X	printw("another game? (y/n) ");
X	if(!analysing) {
X	    printw("or analyse game? (a) ");
X	}
X	refresh();
X	while(TRUE) {
X	    c = getch();
X	    if(c == 'N') c = 'n';
X	    if(c == 'Y') c = 'y';
X	    if((c == 'n') || (c == 'y') || ((c == 'a') && !analysing)) {
X		break;
X	    }
X	    (void) putchar(007);
X	    fflush(stdout);
X	}
X	refresh();
X	if(c == 'n') {
X	    break;
X	}
X	if(analysing && !no_scoring) {
X	    analysing = FALSE;
X	    logfile = save_logfile;
X	} else if(c == 'a') {
X	    analysing = TRUE;
X	    save_logfile = logfile;
X	    logfile = NULL;
X	}
X	if(!analysing) {
X	    signal(SIGINT, nasty);
X	    signal(SIGQUIT, nasty);
X	    interchange(&start_player);
X	}
X    }
X    quit();
X}
X
X/*
X   play the game; alternate between computer strategy and human.
X   stop when the game is finished or the result is one of
X   RESIGN, DRAWN, WIN.  the computer strategy should not return
X   WIN, and DRAWN only if the human is consulted!
X   PASS is only permitted to restart a game with the proper player
X   starting.
X*/
Xplay_challenge(player)
X    int player;
X{
X    int finished;
X    int card, card1;
X
Xagain:
X    finished = FALSE;
X    if(analysing) {
X	player = HUMAN;
X    }
X    while(!finished) {
X	move(COMMAND_LINE, COMMAND_POS);
X	if(player == COMPUTER) {
X	    clrtoeol();
X	    printw("thinking....");
X	    move(COMMENT_LINE, 1);
X	    clrtoeol();
X	    refresh();
X	    card = strategy(COMPUTER);
X	    card1 = card;
X	    if(card < MAX_CARD) {
X		card1 = computer[card];
X	    }
X	} else {
X	    clrtoeol();
X	    refresh();
X	    card = human_interface();
X	    if(card == ANAL_END) {
X		return;
X	    }
X	    card1 = card;
X	    if(card < MAX_CARD) {
X		card1 = human[card];
X	    }
X	}
X	if(card1 == PICK_UP) {
X		save_pick_up();
X	}
X	if(card != BACK_UP) {
X		moves[nr_moves++] = card1;
X	}
X	if(logfile != NULL && !analysing) {
X	    record(player, card1);
X	}
X	if(card != PASS) {
X	    move(COMMAND_LINE - 1, 1);
X	    clrtoeol();
X	    if(card <= PICK_UP) {
X		finished = do_move(player, card);
X	    } else if(card != BACK_UP) {
X		finished = TRUE;
X		break;
X	    }
X	    move(COMMAND_LINE - 1, 1);
X	    clrtoeol();
X	    if(card != BACK_UP) {
X		if(player == COMPUTER) {
X		    if(card != PICK_UP) {
X			printw("computer plays ");
X			display_full(top);
X		    } else {
X			printw("computer picks up");
X		    }
X		}
X	    } else {
X		back_up(COMPUTER);
X		back_up(HUMAN);
X		move(COMMAND_LINE - 1, 1);
X		printw("backed_up one move");
X	    }
X	}
X	if(!finished && card != BACK_UP) {
X	    interchange(&player);
X	}
X    }
X    if(player == COMPUTER) {
X	if(card <= PICK_UP) {
X	    printw(", and wins");
X	    if(!analysing) {
X		computer_score += 2;
X	    }
X	} else if(card == RESIGN) {
X	    printw("computer resigns");
X	    if(!analysing) {
X		human_score += 2;
X	    }
X	} else {
X	    printw("game is a draw");
X	    if(!analysing) {
X		computer_score++;
X		human_score++;
X	    }
X	}
X	/* NOTE: no case for WIN! */
X    } else {
X	if(card <= PICK_UP || card == WIN) {
X	    printw("you win");
X	    if(card != WIN) {
X		moves[nr_moves++] = PASS;
X	    } else {
X		nr_moves--;
X	    }
X	    if(!analysing) {
X		human_score += 2;
X	    }
X	} else if(card == RESIGN) {
X	    printw("you resign");
X	    nr_moves--;
X	    if(!analysing) {
X		computer_score += 2;
X	    }
X	} else {
X	    printw("the game is a draw");
X	    nr_moves--;
X	    if(!analysing) {
X		computer_score++;
X		human_score++;
X	    }
X	}
X    }
X    if(analysing) {
X	goto again;
X    }
X    if(logfile != NULL && !analysing) {
X	record_end();
X    }
X}
X
Xsave_pick_up()
X{
X    int i;
X    unsigned long pu = 0l;
X
X    for(i = 0; i < nr_table; i++) {
X	pu += (1 << table[i]);
X    }
X    pick_ups[nr_moves] = pu;
X}
X
Xback_up(player)
X{
X    int i, j, m, *nr_deck;
X    char *deck;
X    unsigned long pu;
X
X    if(player == COMPUTER) {
X	deck = &computer[0];
X	nr_deck = &nr_computer;
X    } else {
X	deck = &human[0];
X	nr_deck = &nr_human;
X    }
X    m = moves[--nr_moves];
X    if(m == PASS) {
X	return;
X    }
X    if(m != PICK_UP) {
X	deck[(*nr_deck)++] = m;
X	print_card(player, m);
X	for(i = 0; i < nr_table; i++) {
X	    if(table[i] == m) {
X		table[i] = table[--nr_table];
X		clear_card(TABLE, m);
X		break;
X	    }
X	}
X    } else {
X	pu = pick_ups[nr_moves];
X	i = 0;
X	while(i < max_card && pu != 0L) {
X	    if(pu & 1) {
X		table[nr_table++] = i;
X		print_card(TABLE, i);
X	    }
X	    i++;
X	    pu >>= 1;
X	}
X	for(i = 0; i < nr_table; i++) {
X	    m = table[i];
X	    for(j = 0; j < *nr_deck; j++) {
X		if(deck[j] == m) {
X		    deck[j] = deck[--(*nr_deck)];
X		    clear_card(player, m);
X		}
X	    }
X	}
X    }
X    if(nr_moves > 0) {
X	top = moves[nr_moves - 1];
X    } else {
X	top = PICK_UP;
X    }
X    print_top(top);
X}
X
X/* check the validity of the card played; card is an index to the hand */
Xvalid(player, card)
X    int player, card;
X{
X    int value, suit, tvalue, tsuit, *nr_deck;
X    char *deck;
X
X    if(player == COMPUTER) {
X	deck = &computer[0];
X	nr_deck = &nr_computer;
X    } else {
X	deck = &human[0];
X	nr_deck = &nr_human;
X    }
X    if(card == PICK_UP) {
X	return(nr_table > 0);
X    }
X    if(card >= *nr_deck) {
X	return(FALSE);
X    }
X    if(nr_table == 0) {
X	return(TRUE);
X    }
X    value = VALUE(deck[card]);
X    suit = SUIT(deck[card]);
X    tvalue = VALUE(top);
X    tsuit = SUIT(top);
X    if(suit == tsuit && value < tvalue) {
X	return(TRUE);
X    }
X    if((player == COMPUTER && suit != SPADES) ||
X       (player == HUMAN && suit != HEARTS)) {
X	return(FALSE);
X    }
X    return(suit != tsuit);
X}
X
X/* executes players move; card is an index to the hand */
Xdo_move(player, card)
X    int player;
X    char card;
X{
X    int i, *nr_deck;
X    char *deck;
X
X    if(player == COMPUTER) {
X	deck = &computer[0];
X	nr_deck = &nr_computer;
X    } else {
X	deck = &human[0];
X	nr_deck = &nr_human;
X    }
X    if(card != PICK_UP) {
X	top = deck[card];
X	table[nr_table++] = top;
X	print_card(TABLE, top);
X	print_top(top);
X	deck[card] = deck[--(*nr_deck)];
X	clear_card(player, top);
X	return(*nr_deck == 0);
X    } else {
X	for(i = 0; i < nr_table; i++) {
X	    deck[(*nr_deck)++] = table[i];
X	    print_card(player, table[i]);
X	    clear_card(TABLE, table[i]);
X	}
X	nr_table = 0;
X	top = PICK_UP;
X	print_top(top);
X	return(FALSE);
X    }
X}
X
X/* set up a new game */
Xinit()
X{
X    char cards[MAX_CARD];
X    int i;
X    char *c, *h;
X    int s = size * 4;
X    int j, value, suit, card;
X
X    size2 = size * 2;
X    max_card = size * 4;
X    if(no_scoring) {
X	if(logfile != NULL) {
X	    read_game();
X	    return;
X	}
X	for(i = 0; i < max_card; i++) {
X	    human[i] = i;
X	}
X	nr_human = max_card;
X	nr_computer = 0;
X	nr_table = 0;
X	top = PICK_UP;
X	nr_moves = 0;
X	move_logged = 0;
X	return;
X    }
X    for(i = 0; i < max_card; i++) {
X	cards[i] = i;
X	table[i] = PICK_UP;
X    }
X    top = PICK_UP;
X    c = &computer[0];
X    h = &human[0];
X    for(i = max_card - 1; i >= size2; i--) {
X	j = rnd(s--);
X	card = cards[j];
X	cards[j] = cards[i];
X	value = VALUE(card);
X	suit = SUIT(card);
X	if(suit <= CLUBS) {
X	    *c++ = card;
X	    *h++ = (3 - suit) + value * 4;
X	}
X    }
X    for(i = 0; i < size2; i++) {
X	card = cards[i];
X	value = VALUE(card);
X	suit = SUIT(card);
X	if(suit <= CLUBS) {
X	    *h++ = card;
X	    *c++ = (3 - suit) + value * 4;
X	}
X    }
X    for(i = size2; i < max_card; i++) {
X	*h++ = PICK_UP;
X	*c++ = PICK_UP;
X    }
X    nr_computer = size2;
X    nr_human = size2;
X    nr_table = 0;
X    for(i = 0; i < max_card; i++) {
X	s_computer[i] = computer[i];
X	s_human[i] = human[i];
X    }
X    nr_moves = 0;
X    move_logged = 0;
X}
X
Xdraw_score()
X{
X    if(no_scoring) {
X	move(0, MARGIN + size2);
X	if(start_player == HUMAN) {
X	    printw("   human vs. computer         ");
X	} else {
X	    printw("   computer vs. human         ");
X	}
X    } else {
X	move(0, MARGIN + size2);
X	if(demo != 0) {
X	    printw("computer %2d vs. robot %2d", computer_score, human_score);
X	} else if(start_player == HUMAN) {
X	    printw("human %2d vs. computer %2d", human_score, computer_score);
X	} else {
X	    printw("computer %2d vs. human %2d", computer_score, human_score);
X	}
X    }
X}
X
X/* draw or redraw the play */
Xredraw()
X{
X    int i;
X
X    clear();
X    draw_score();
X    move(COMPUTER, MARGIN);
X    printw("computer: SPADES:");
X    move(COMPUTER + 1, MARGIN);
X    printw("           clubs:");
X    move(COMPUTER + 2, MARGIN);
X    printw("        diamonds:");
X    move(COMPUTER + 3, MARGIN);
X    printw("          hearts:");
X    move(TABLE, MARGIN);
X    printw("   table: spades:");
X    move(TABLE + 1, MARGIN);
X    printw("           clubs:");
X    move(TABLE + 2, MARGIN);
X    printw("        diamonds:");
X    move(TABLE + 3, MARGIN);
X    printw("          hearts:");
X    move(HUMAN, MARGIN);
X    printw("     you: spades:");
X    move(HUMAN + 1, MARGIN);
X    printw("           clubs:");
X    move(HUMAN + 2, MARGIN);
X    printw("        diamonds:");
X    move(HUMAN + 3, MARGIN);
X    printw("          HEARTS:");
X    move(TABLE + 1, 1);
X    printw("top:");
X    move(COMMAND_LINE, 1);
X    printw("command:");
X    move(COMMAND_LINE + 1, 1);
X    printw("enter: card to play, or p for pick-up, or ? for help, or ! for extra commands");
X    for(i = 0; i < nr_computer; i++) {
X	print_card(COMPUTER, computer[i]);
X    }
X    for(i = 0; i < nr_table; i++) {
X	print_card(TABLE, table[i]);
X    }
X    for(i = 0; i < nr_human; i++) {
X	print_card(HUMAN, human[i]);
X    }
X    print_top(top);
X    display_extra();
X}
X
X/* print a card */
Xprint_card(player, card)
X    int player;
X    char card;
X{
X    int value, suit;
X
X    value = VALUE(card);
X    suit = SUIT(card);
X    move(ROW(player,suit,value),COL(player,suit,value));
X    display_value(value);
X}
X
X/* clear the position of a card */
Xclear_card(player, card)
X    int player;
X    char card;
X{
X    int value, suit;
X
X    value = VALUE(card);
X    suit = SUIT(card);
X    move(ROW(player,suit,value),COL(player,suit,value));
X    printw("  ");
X}
X
X/* print the top card */
Xprint_top(card)
X    char card;
X{
X    move(TABLE + 2, 1);
X    display(card);
X}
X
X/* display card: suit and value */
Xdisplay(card)
X    char card;
X{
X    int value, suit;
X
X    value = VALUE(card);
X    suit = SUIT(card);
X    if(card == PICK_UP) {
X	printw("---");
X	return;
X    }
X    display_value(value);
X    printw("%c", "scdh"[suit]);
X}
X
X/* display value of card */
Xdisplay_value(value)
X    int value;
X{
X    if(value == C_10) {
X	printw("1");
X    } else {
X	printw(" ");
X    }
X    printw("%c", "AKQJ098765432"[value]);
X}
X
X/* display the name of the card in full */
Xchar *values[] = {
X"ace", "king", "queen", "jack", "10", "9", "8", "7", "6", "5", "4", "3", "2"};
X
Xchar *suits[] = {
X"spades", "clubs", "diamonds", "hearts"};
X
Xdisplay_full(card)
X    char card;
X{
X    int value, suit;
X
X    value = VALUE(card);
X    suit = SUIT(card);
X    printw(values[value]);
X    printw(" of ");
X    printw(suits[suit]);
X}
X
X/* interchange players */
Xinterchange(p)
X    int *p;
X{
X    *p = COMPUTER + HUMAN - *p;
X}
X
X/* require y or n answer */
Xyesno()
X{
X    char c = 0;
X
X    while((c != 'n') && (c != 'y')) {
X	c = getch();
X	if(c == 'N') c = 'n';
X	if(c == 'Y') c = 'y';
X	if((c != 'n') && (c != 'y')) {
X	    (void) putchar(007);
X	    fflush(stdout);
X	}
X    }
X    return(c == 'y');
X}
X
Xquit()
X{
X#ifdef TIMER
X    alarm(0);
X#endif
X    move(COMMAND_LINE + 1, 0);
X    clrtoeol();
X    refresh();
X    endwin();
X    if(!no_scoring) {
X	printf("your final score was %d, the computer had %d\n",
X	    human_score, computer_score);
X    }
X    exit(0);
X}
X
Xnasty()
X{
X#ifdef TIMER
X    alarm(0);
X#endif
X    move(COMMENT_LINE, 1);
X    clrtoeol();
X    move(COMMAND_LINE, 1);
X    clrtoeol();
X    printw("just when i had such a good game going!");
X    computer_score += 2;
X    quit();
X}
X
Xrnd(mod)
X    int mod;
X{
X    if(mod <= 0) {
X	return(0);
X    }
X    return((((seed = seed*11109+13849) >> 16) & 0xffff) % mod);
X}
X
Xusage()
X{
X    printf("usage: challenge [-s#] [-d#]\n");
X    exit(0);
X}
X
END_OF_main.c
if test 14394 -ne `wc -c <main.c`; then
    echo shar: \"main.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f strategy.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"strategy.c\"
else
echo shar: Extracting \"strategy.c\" \(10798 characters\)
sed "s/^X//" >strategy.c <<'END_OF_strategy.c'
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1988. */
X/* Permission granted to redistribute this program. */
X
X#include "challenge.h"
X
Xint ncall;
X#ifdef DEBUG
Xint debug=1;
Xstatic FILE *log = NULL;
X#endif
X
X#define N_COMPUTER  0
X#define N_HUMAN     1
X#define N_TABLE     2
X
X#define OPPONENT(s)     (1 - (s))
X
X#define INFINITE 0xffff
X#define UNDEF    9999
X
X#define BIT_SUIT(x)    ((x)>>13)
X#define BIT_VALUE(x)    ((x)&0x1fff)
X
Xtypedef struct {
X    char to_move, ply;
X    int  top;
X    int  n_cards[2];
X    int  cards[3][4];
X} position;
X
Xint stack[500];
Xint score[256][4];
Xint trumps[2];
X
Xint jimmy;
X
Xint last_score = 0;
X
Xstore_moves(c, suit, my_cards, table_cards, mp)
X    int c, suit, my_cards, table_cards, *mp;
X{
X    int n = 0;
X
X    suit <<= 13;
X    while(c) {
X	if(c & my_cards) {
X	    *(mp++) = c | suit;
X	    n++;
X	    do {
X		c >>= 1;
X	    } while(c & (my_cards | table_cards));
X	}
X	c >>= 1;
X    }
X    return n;
X}
X
Xgen_moves(pos, mp)
X    position *pos;
X    int *mp;
X{
X    int my_side, my_trump, his_trump;
X    int nm, h, top_suit, top_card;
X    int *my_cards, *table_cards;
X
X    my_side     = pos->to_move;
X    my_cards    = pos->cards[my_side];
X    table_cards = pos->cards[N_TABLE];
X    top_suit    = BIT_SUIT(pos->top);
X    top_card    = BIT_VALUE(pos->top);
X    my_trump    = trumps[my_side];
X    his_trump   = trumps[OPPONENT(my_side)];
X
X    if(top_card) {
X	*mp = 0;
X	nm = 1 + store_moves(top_card >> 1, top_suit, my_cards[top_suit],
X			     table_cards[top_suit], mp + 1);
X	mp += nm;
X	if(top_suit != my_trump) {
X	    nm += store_moves(jimmy, my_trump, my_cards[my_trump],
X			      table_cards[my_trump], mp);
X	}
X    } else {
X	nm = store_moves(jimmy, DIAMONDS, my_cards[DIAMONDS],
X			 table_cards[DIAMONDS], mp);
X	mp += nm;
X	h = store_moves(jimmy, CLUBS, my_cards[CLUBS], table_cards[CLUBS], mp);
X	mp += h;
X	nm += h;
X	h = store_moves(jimmy, his_trump, my_cards[his_trump],
X			table_cards[his_trump], mp);
X	mp += h;
X	nm += h;
X	h = store_moves(jimmy, my_trump, my_cards[my_trump],
X			table_cards[my_trump], mp);
X	nm += h;
X    }
X    return(nm);
X}
X
X#define gscore(x0,x1,y0,y1,a0,a1,b0,b1) 6*x0+5*y0+3*x1+3*y1-a0-b0-2*a1-2*b1
X
Xstatic_eval(pos)
X    position *pos;
X{
X    int my_side, his_side, my_trump, his_trump;
X    int x, x0, x1, dx,
X	y, y0, y1, dy,
X	a, a0, a1, da,
X	b, b0, b1, db, f1;
X    int tx, tx0, tx1, tdx,
X	ty, ty0, ty1, tdy,
X	ta, ta0, ta1, tda,
X	tb, tb0, tb1, tdb, f2;
X
X    my_side = pos->to_move;
X    his_side = OPPONENT(my_side);
X    my_trump = trumps[my_side];
X    his_trump = trumps[his_side];
X
X    {
X	register int *c_m = pos->cards[my_side];
X	register int *c_h = pos->cards[his_side];
X	register int *p;
X
X	p = score[c_m[my_trump]];
X	x0 = *(p++);
X	x1 = *(p++);
X	x = *(p++);
X	dx = *p;
X	p = score[c_h[his_trump]];
X	tx0 = *(p++);
X	tx1 = *(p++);
X	tx = *(p++);
X	tdx = *p;
X	p = score[c_m[his_trump]];
X	y0 = *(p++);
X	y1 = *(p++);
X	y = *(p++);
X	dy = *p;
X	p = score[c_h[my_trump]];
X	ty0 = *(p++);
X	ty1 = *(p++);
X	ty = *(p++);
X	tdy = *p;
X	p = score[c_m[CLUBS]];
X	a0 = *(p++);
X	a1 = *(p++);
X	a = *(p++);
X	da = *p;
X	p = score[c_h[CLUBS]];
X	tb0 = *(p++);
X	tb1 = *(p++);
X	tb = *(p++);
X	tdb = *p;
X	p = score[c_m[DIAMONDS]];
X	b0 = *(p++);
X	b1 = *(p++);
X	b = *(p++);
X	db = *p;
X	p = score[c_h[DIAMONDS]];
X	ta0 = *(p++);
X	ta1 = *(p++);
X	ta = *(p++);
X	tda = *p;
X    }
X
X    if(x1 + y1 + a + b <= 1) {
X	return(INFINITE);
X    }
X    if(tx0 == pos->n_cards[his_side]) {
X	return(-INFINITE);
X    }
X    if((tx) == 0 && x0 >= x1 - 1) {
X	register int n;
X
X	n = da;
X	n += db;
X	n += dx;
X	if(n <= x0 + 1) {
X	    return(INFINITE);
X	}
X    }
X    if(x == 0 && tx0 >= x1) {
X	register int n;
X
X	n = tda;
X	n += tdb;
X	if(tx1 == tx0) {
X	    n++;
X	}
X	if(n <= tx0) {
X	    return(-INFINITE);
X	}
X    }
X    f1 = gscore(x0, x1, y0, y1, a0, a1, b0, b1);
X    f2 = gscore(tx0, tx1, ty0, ty1, ta0, ta1, tb0, tb1);
X    return(3 + f1 - f2);
X}
X#undef gscore
X
Xupdate(pos, mv)
X    register position *pos;
X    register int mv;
X{
X    register int his_side = pos->to_move;
X
X    pos->to_move = OPPONENT(his_side);
X    pos->top = mv;
X    pos->ply += 1;
X    if(mv == 0) {
X	register int s;
X
X	pos->n_cards[his_side] = max_card - pos->n_cards[OPPONENT(his_side)];
X	for(s = 3; s >= 0; s--) {
X	    pos->cards[his_side][s] |= pos->cards[N_TABLE][s];
X	    pos->cards[N_TABLE][s] = 0;
X	}
X    } else {
X	register int suit;
X
X	pos->n_cards[his_side] -= 1;
X	suit = BIT_SUIT(mv);
X	pos->cards[N_TABLE][suit] |= BIT_VALUE(mv);
X	pos->cards[his_side][suit] ^= BIT_VALUE(mv);
X    }
X}
X
Xeval(pos, mv , mvlist, alfa, beta)
X    position pos;
X    int  mv, *mvlist, alfa, beta;
X{
X    int nmoves, e, emax, i;
X    int nbeta = beta;
X
X    ++ncall;
X    update(&pos, mv);
X    if(mv==0) {
X	if(pos.n_cards[pos.to_move] == 1) {
X	    return(-INFINITE);
X	}
X	emax = static_eval(&pos);
X	if(pos.ply > depth) {
X	    return(-emax);
X	}
X	if(emax == INFINITE) {
X	    return(-INFINITE);
X	} else if(emax == -INFINITE) {
X	    return(INFINITE);
X	}
X    }
X    nmoves = gen_moves(&pos,mvlist);
X    if(nmoves > 1 && (pos.n_cards[pos.to_move] == 1)) {
X	return(-INFINITE);
X    }
X    emax = -INFINITE;
X    for(i=0; i<nmoves; i++) {
X	e = eval(pos, mvlist[i], mvlist + nmoves, -nbeta, -alfa);
X	if(e > emax) {
X	    emax = e;
X	}
X	if(emax >= alfa) {
X	    break;
X	}
X	if(emax > nbeta) {
X	    nbeta = emax;
X	}
X    }
X    return(-emax);
X}
X
Xstrategy(player)
X    int player;
X{
X    static init = FALSE;
X    position pos;
X    int nmoves, emax, e, i;
X    int bestmv = 0;
X
X    if(depth == 0) {
X	return(zero_strategy(player));
X    }
X#ifdef TIMER
X    set_alarm();
X#endif
X    if(!init) {
X	init = TRUE;
X	loc_init();
X    }
X
X    init_pos(&pos, player);
X#ifdef DEBUG
X    if(debug) {
X	print_pos(&pos);
X    }
X#endif
X    nmoves = gen_moves(&pos, stack);
X    if(nmoves == 1) {
X	bestmv = stack[0];
X	emax = UNDEF;
X    } else if(nmoves > 1 && pos.n_cards[pos.to_move] == 1) {
X	bestmv = stack[1];
X	emax = INFINITE;
X    } else {
X	ncall = 0;
X	emax = -INFINITE;
X	bestmv = stack[1];
X	for(i=0; i<nmoves; i++) {
X	    e = eval(pos, stack[i], stack + nmoves, -emax, -INFINITE);
X#ifdef DEBUG
X	    if(debug) {
X		printmve(0,stack[i],e);
X	    }
X#endif
X	    if(e > emax)
X	    {
X		emax = e;
X		bestmv = stack[i];
X	    }
X	}
X#ifdef DEBUG
X	if(debug) {
X	    fprintf(log, "chosen ( %d )===> ", ncall);
X	    printmve(0, bestmv, emax);
X	    fflush(log);
X	}
X#endif
X    }
X#ifdef TIMER
X    end_alarm();
X#endif
X    move(COMMENT_LINE, 1);
X    clrtoeol();
X    if(player == COMPUTER) {
X	if(emax == INFINITE || (last_score == INFINITE && emax == UNDEF)) {
X	    printw("i think i am going to win!");
X	    emax = INFINITE;
X	}
X    }
X    refresh();
X    last_score = emax;
X    if(bestmv == 0) {
X	return(PICK_UP);
X    }
X    if(player == COMPUTER) {
X	return(comp_ind(bestmv, &computer[0]));
X    } else {
X	return(comp_ind(bestmv, &human[0]));
X    }
X}
X
Xloc_init()
X{
X    int mcs, s0, s1;
X    int i;
X#ifdef DEBUG
X    if(debug && log==0) {
X	unlink(DEBUG);
X	log = fopen(DEBUG, "w");
X    }
X#endif
X    for(i=0; i<256; i++) {
X	s0 = 0;
X	s1 = 0;
X	mcs = i;
X	while(mcs & 1) {
X	    mcs >>= 1;
X	    s0++;
X	}
X	while(mcs) {
X	    s1 += mcs&1;
X	    mcs >>= 1;
X	}
X	score[i][0] = s0;
X	score[i][1] = s1;
X	score[i][2] = s0 + s1;
X	if(s1 > s0) {
X	    score[i][3] = s1 - s0;
X	} else {
X	    score[i][3] = 0;
X	}
X    }
X}
X
X#define SUIT1(x) ((x)&3)
X#define VALUE1(x) (((x)>>2) & 15)
X
Xbit_to_int(mv)
X    int mv;
X{
X    int s, c, v;
X
X    if(mv == 0) {
X	return(0);
X    }
X    s = BIT_SUIT(mv);
X    c = BIT_VALUE(mv);
X    for(v = 0; c > 1; c >>= 1) {
X	v++;
X    }
X    return(s + (v << 2));
X}
X
Xcomp_ind(c, deck)
X    char *deck;
X{
X    int i;
X
X    c = bit_to_int(c);
X    for(i = 0; deck[i] != c ; i++);
X    return(i);
X}
X
Xinit_pos(pos, player)
X    position *pos;
X    int player;
X{
X
X    int i, c;
X
X    trumps[N_COMPUTER] = SPADES;
X    trumps[N_HUMAN] = HEARTS;
X    jimmy = 1 << ((max_card >> 2) - 1);
X
X    if(nr_table == 0) {
X	pos->top = 0;
X    } else {
X	pos->top = (1 << VALUE1(top)) | (SUIT1(top) << 13);
X    }
X    if(player == COMPUTER) {
X	pos->to_move = N_COMPUTER;
X    } else {
X	pos->to_move = N_HUMAN;
X    }
X    pos->n_cards[N_COMPUTER] = nr_computer;
X    pos->n_cards[N_HUMAN] = nr_human;
X    pos->ply = 0;
X    for(i=0; i<4 ; i++) {
X	pos->cards[N_COMPUTER][i] = 0;
X	pos->cards[N_HUMAN][i] = 0;
X	pos->cards[N_TABLE][i] = 0;
X    }
X    for(i=0; i<nr_computer; i++) {
X	c = computer[i];
X	pos->cards[N_COMPUTER][SUIT1(c)] |= 1 << VALUE1(c);
X    }
X    for(i=0; i<nr_table; i++) {
X	c = table[i];
X	pos->cards[N_TABLE][SUIT1(c)] |= 1 << VALUE1(c);
X    }
X    for(i=0; i<nr_human; i++) {
X	c = human[i];
X	pos->cards[N_HUMAN][SUIT1(c)] |= 1 << VALUE1(c);
X    }
X}
X
X#ifdef DEBUG
Xprintmv(mv)
X    int mv;
X{
X    int c, sc, vc;
X
X    if(mv == 0) {
X	fprintf(log, " pu ");
X    } else {
X	c = bit_to_int(mv);
X	fprintf(log, " %c%c ", "AKQJX98765432"[VALUE(c)], "scdh"[SUIT(c)]);
X    }
X}
X
Xprintmve(level, mv, e)
X    int level, mv, e;
X{
X    fprintf(log, "level:%d ", level);
X    printmv(mv);
X    fprintf(log, " = %d \n", e);
X}
X
Xprint_pos(pos)
X    position *pos;
X{
X    int s, c, bl;
X    int *cp;
X
X    fprintf(log, "\n******************\n");
X    fprintf(log, "computer : \n");
X    cp = pos->cards[N_COMPUTER];
X    for(s = 0; s < 4; s++) {
X	bl = 0;
X	for(c = 1; c <= jimmy; c = c << 1) {
X	    if(c & cp[s]) {
X		bl = 1;
X		printmv(c + (s << 13));
X	    }
X	}
X	if(bl) {
X	    fprintf(log, " \n");
X	}
X    }
X    fprintf(log, "human : \n");
X    cp = pos->cards[N_HUMAN];
X    for(s = 0; s < 4; s++) {
X	bl = 0;
X	for(c = 1; c <= jimmy; c = c << 1) {
X	    if(c & cp[s]) {
X		bl = 1;
X		printmv(c + (s << 13));
X	    }
X	}
X	if(bl) {
X	    fprintf(log, " \n");
X	}
X    }
X    fprintf(log, "table    : \n");
X    cp = pos->cards[N_TABLE];
X    for(s = 0; s < 4; s++) {
X	bl = 0;
X	for(c = 1; c <= jimmy; c = c << 1) {
X	    if(c & cp[s]) {
X		bl = 1;
X		printmv(c + (s << 13));
X	    }
X	}
X	if(bl) {
X	    fprintf(log, " \n");
X	}
X    }
X    if(pos->top) {
X	fprintf(log, "on top >>>>");
X	printmv(pos->top);
X	fprintf(log, " <<<<\n");
X    }
X}
X#endif
X
Xzero_strategy(player)
X    int player;
X{
X    int i, j = PICK_UP, iresult, jresult, nr_deck;
X    char *deck;
X
X    last_score = 0;
X    if(player == COMPUTER) {
X	deck = &computer[0];
X	nr_deck = nr_computer;
X    } else {
X	deck = &human[0];
X	nr_deck = nr_human;
X    }
X    jresult = evaluate_card(player, PICK_UP);
X    for(i = 0; i < nr_deck; i++) {
X	if(valid(player, i)) {
X	    iresult = evaluate_card(player, deck[i]);
X	    if(iresult > jresult) {
X		j = i;
X		jresult = iresult;
X	    }
X	}
X    }
X    return(j);
X}
X
Xevaluate_card(player, card)
X    int player, card;
X{
X    int value, suit;
X
X    if(card == PICK_UP) {
X	return(-1);
X    }
X    value = VALUE(card);
X    suit = SUIT(card);
X    if(((player == COMPUTER) && (suit == SPADES)) ||
X       ((player == HUMAN) && (suit == HEARTS))) {
X	return(value);
X    }
X    if(((player == COMPUTER) && (suit == HEARTS)) ||
X       ((player == HUMAN) && (suit == SPADES))) {
X	return(value + size);
X    }
X    return(value + size2);
X}
X
Xaccept_draw()
X{
X    return(last_score < -20);
X}
X
END_OF_strategy.c
if test 10798 -ne `wc -c <strategy.c`; then
    echo shar: \"strategy.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 1 \(of 2\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked both archives.
    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