[comp.sources.games] v07i013: bidding3 - Bridge Bidder, Version 3.0, Part01/02

billr@saab.CNA.TEK.COM (Bill Randle) (07/12/89)

Submitted-by: Nathan Glasser <nathan@brokaw.lcs.mit.edu>
Posting-number: Volume 7, Issue 13
Archive-name: bidding3/Part01
Supersedes: bidding2: Volume 6, Issue 6

	[[This is version 3.0 of my bridge bidding program. This version
	includes a whole lot of new stuff by John Oswalt for picking specific
	types of hands to deal and subsequently bid.]]

#! /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:  MANIFEST bidding.c bidding.doc eval.c example.exp exper.c
#   makefile.dos
# Wrapped by billr@saab on Thu Jul  6 07:50:14 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MANIFEST'\"
else
echo shar: Extracting \"'MANIFEST'\" \(517 characters\)
sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
X   File Name		Archive #	Description
X-----------------------------------------------------------
X MANIFEST                   1	This shipping list
X bidding.c                  1	
X bidding.doc                1	
X bidding.h                  2	
X deal.c                     2	
X eval.c                     1	
X example.exp                1	
X exper.c                    1	
X exper.doc                  2	
X history.doc                2	
X makefile.dos               1	
X makefile.unx               2	
X readme.doc                 2	
END_OF_FILE
if test 517 -ne `wc -c <'MANIFEST'`; then
    echo shar: \"'MANIFEST'\" unpacked with wrong size!
fi
# end of 'MANIFEST'
fi
if test -f 'bidding.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'bidding.c'\"
else
echo shar: Extracting \"'bidding.c'\" \(17979 characters\)
sed "s/^X//" >'bidding.c' <<'END_OF_FILE'
X/* bidding.c */
X/*
X			Bridge Bidder	Version 3.0
X			by John Oswalt and Nathan Glasser
X			..!sun!megatest!jao (usenet)
X			nathan@brokaw.lcs.mit.edu (internet)
X			nathan@mit-eddie.uucp (usenet)
X
X			June, 1989
X------------------------------------------------------------------------------
XCopyright 1988, 1989 by Nathan Glasser and John Oswalt.
XYou may feel free to distribute this program in its current form.
XPlease do not remove this copyright information.
X*/
X
X#include "bidding.h"
X
Xchar *vuln_relative[] = {"Your side","Other side"};
Xchar *vuln_absolute[] = {"1st side","2nd side","Neither side","Both sides"};
Xchar *suit_strings[4] = {"Spades","Hearts","Diamonds","Clubs"};
Xchar *vuln_format[2][2] = {
X  {"Declarer side","Defender side"},
X  {"North/South","East/West"}};
Xchar seperator[] =
X"\n---------------------------------------------------------------------\n\n";
X
X#define PASSED_OUT(pdeal) \
X    ((pdeal)->num_bids == 4 && (pdeal)->bids->bid.suit == PASS)
X
X/* Functions used for deal qualification */
Xextern int twoclubq(), twoclub1stq(), threentq(), twontq(), flanneryq(),
X    longsuitq(), losersq(), flannery1stq(), voidhandsq(),
X    totalvoidsq(), fitq(), doublefitq(), misfitq(), badmisfitq();
X    wildq(), goulash(), experimentq(), onentq();
Xextern int default_predeal(), experiment_predeal();
X
Xstruct deal_type deal_types[] = {
X    {"2clubs",default_predeal,twoclubq,-1,
X      ": Someone has at least game - 1 trick (but not a 2NT hand)."},
X    {"2clubs1st",default_predeal,twoclub1stq,-1,
X      ": Dealer has at least game - 1 trick (but not a 2NT hand)."},
X    {"goulash",default_predeal,goulash,-1,
X      ": Hands delt normally, sorted, cut, and redelt 5-5-3."},
X    {"3nt",default_predeal,threentq,-1,
X      ": Someone has a 7 or 8 card minor to AKQ with no outside A or K."},
X    {"2nt",default_predeal,twontq,-1,
X      ": Someone has a 20-21 HCP hand with no 5 card major,\n\
X\tno 6 card minor, no singleton, and no void."},
X    {"1nt",default_predeal,onentq,-1,
X      ": Someone has a 15-17 HCP hand with no 5 card major,\n\
X\tno 6 card minor, no singleton, and no void."},
X    {"misfit",default_predeal,misfitq,-1,
X      ": All fits are 6 or 7 cards."},
X    {"flannery",default_predeal,flanneryq,-1,
X      ": Someone has 5 hearts, 4 spades, and 11-15 HCP."},
X    {"flannery1st",default_predeal,flannery1stq,-1,
X      ": Dealer has 5 hearts, 4 spades, and 11-15 HCP."},
X    {"longsuit",default_predeal,longsuitq,13,
X      " N: Someone's longest suit is N cards long."},
X    {"losers",default_predeal,losersq,12,
X      " N: Someone has exactly N losers."},
X    {"voidhands",default_predeal,voidhandsq,4,
X      " N: N hands contain at least 1 void."},
X    {"totalvoids",default_predeal,totalvoidsq,12,
X      " N: There are N voids in the deal."},
X    {"fit",default_predeal,fitq,13,
X      " N: At least 1 partnership has exactly N cards in some suit."},
X    {"doublefit",default_predeal,doublefitq,26,
X      " N: At least 1 partnership has exactly N cards in two suits."},
X    {"badmisfit",default_predeal,badmisfitq,26,
X      "N: For at least 1 hand the following is true:\n\
X\tLet A and B be two suits, and misfit(x) be the total cards\n\
X\tof suit x contained in the hand and in some opponent's\n\
X\thand.  Misfit(A) + Misfit(B) >= N for some A and B."},
X    {"wild",default_predeal,wildq,0,
X      ": Equal parts of 2clubs, 2nt, flannery1st, longsuit 8, losers 3,\n\
X\ttotalvoids 2, doublefit 19, badmisfit 20, 3nt, and goulash."},
X    {"experiment",experiment_predeal,experimentq,-1,
X      ": Uses custom code in exper.c to generate and qualify\n\
X\tdeals.  See exper.doc and exper.c."},
X};
X
X#define NUM_DEAL_TYPES (sizeof(deal_types) / sizeof(struct deal_type))
X
XPFI predeal = default_predeal;
Xdeal *deals;
Xint totaltried = 0;
Xint totalfound = 0;
XPFI handqfunc = (PFI)NULL;
Xint handqparm;
Xint cardsused[52];
Xint hand_setup[4];
Xint cardsleft;
Xint num_deals;
Xint dobidding = 1;
X
X
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X{
X    int i,j;
X    int num_deals_left;
X    int deal_num;
X    int origargc = argc;
X    char **origargv = argv;
X    
X    if (argc < 2)
X    {
X	usage(argv[0]);
X	exit(0);
X    }
X    
X    while (argc--, (++argv)[0][0] == '-')
X	switch (argv[0][1])
X	{
X	    case 'l':
X	    case 'L':
X	        list_dealtypes();
X		exit(0);
X	    case 'd':
X	    case 'D':
X	        dobidding = 0;
X		break;
X	    default:
X		printf("Unknown option: %s.\n",argv[0]);
X		exit(1);
X	}
X    
X    num_deals = atoi((argv++)[0]);
X    argc--;
X    
X    /* Handle a deal_type. Look up the name in the table.
X       If we find it there, then we may have to process a parameter.
X       A param_max value of < 0 means it takes no parameter. A
X       parameter of 0 means that it takes no parameter, but the function
X       is automatically given num_deals as its parameter. A positive
X       value means that it takes a parameter, which must be positive and
X       is not allowed to exceed that value. */
X    if (argc)
X    {
X	for (i = NUM_DEAL_TYPES - 1; i >= 0; i--)
X	    if (!strcmp(argv[0],deal_types[i].deal_name))
X	    {
X		predeal = deal_types[i].predeal_func;
X		handqfunc = deal_types[i].hand_func;
X		if (deal_types[i].param_max == 0)
X		    handqparm = num_deals;
X		else if (deal_types[i].param_max > 0)
X		{
X		    if (argc < 2)
X		    {
X			printf("Missing required parameter.\n");
X			exit(1);
X		    }
X		    if ((handqparm = atoi(argv[1])) < 1 ||
X		      handqparm > deal_types[i].param_max)
X		    {
X			printf("Parameter %d not in the range 1-%d.\n",
X			  handqparm,deal_types[i].param_max);
X			exit(1);
X		    }
X		}
X		break;
X	    }
X	if (i < 0)
X    	{
X	    printf("Unknown deal_type %s.\n",argv[0]);
X	    exit(1);
X    	}
X    }
X
X    printf("Dealing %d hand%s...\n",num_deals_left = num_deals,
X	num_deals == 1 ? "" : "s");
X    
X    deals = (deal *)malloc(num_deals * sizeof(deal));
X    
X    srandom((unsigned)time(NULL));
X    
X    for (i = 0; i < num_deals; i++)
X	deal_qualified(i);
X    
X    write_log_header(origargc,origargv);
X    
X    if (!dobidding)
X    {
X	bid tmp;
X	tmp.bid.suit = PASS;
X
X	/* Make it look like all hands were passed out so that
X	   print_complete_deal will work right. Kludge. */
X	for (i = 0; i < num_deals; i++)
X	{
X	    deals[i].num_bids = 4;
X	    deals[i].bids = &tmp;
X	}
X	write_deals();
X	printf("All dealing complete.\n");
X	exit(0);
X    }
X    
X    /* Accept bids */
X    while (num_deals_left)
X    {
X	deal_num = random() % num_deals;
X	
X	if (deals[deal_num].bidding_done)
X	    continue;
X	clear_screen();
X	for (;;)
X	{
X	    print_bidding(stdout,&deals[deal_num],deals[deal_num].num_bids,
X	      BIDDING);
X	    printf("Your hand (%s vulnerable):\n",
X	      (deals[deal_num].vulnerability <= RELATIVE) ?
X	      vuln_relative[(deals[deal_num].num_bids & 1) ^ 
X	      deals[deal_num].vulnerability] :
X	      vuln_absolute[deals[deal_num].vulnerability]);
X	    print_hand(stdout,
X	      deals[deal_num].hands[deals[deal_num].num_bids % 4]);
X	    if (!accept_bid(&deals[deal_num]))
X	    	break;
X	    printf("Bad bid.\n\n");
X	}
X	
X	if (deals[deal_num].bidding_done)
X	{
X	    num_deals_left--;
X	    /* If hand was passed out */
X	    if (PASSED_OUT(&deals[deal_num]))
X		display_complete_deal(&deals[deal_num],1);
X	}
X    }
X    
X    /* Accept opening leads */
X    for (deal_num = 0; deal_num < num_deals; deal_num++)
X    {
X    	/* Make sure hand wasn't passed out */
X	if (PASSED_OUT(&deals[deal_num]))
X	    continue;
X	clear_screen();
X	j = figure_out_leader(&deals[deal_num]);
X
X	for (;;)
X	{
X	    print_bidding(stdout,&deals[deal_num],j,LEADING);
X	    printf("Your hand (%s vulnerable):\n",
X	      (deals[deal_num].vulnerability <= RELATIVE) ?
X	      vuln_relative[(j & 1) ^ 
X	      deals[deal_num].vulnerability] :
X	      vuln_absolute[deals[deal_num].vulnerability]);
X	    print_hand(stdout,deals[deal_num].hands[j]);
X	    if (!get_lead(&deals[deal_num],j))
X	    	break;
X	    printf("Bad lead.\n\n");
X	}
X
X	display_complete_deal(&deals[deal_num],((j + 1) % 4));
X    }
X    
X    printf("All bidding complete.\n");
X}
X
Xdisplay_complete_deal(pdeal,top_hand)
Xdeal *pdeal;
Xint top_hand;
X{
X    print_complete_deal(stdout,pdeal,top_hand);
X    more();
X    log_deal(pdeal,top_hand);
X}
X
Xprint_complete_deal(fp,pdeal,top_hand)
XFILE *fp;
Xdeal *pdeal;
Xint top_hand;
X{
X    int i;
X    char top_h[4][80],left_h[4][80],right_h[4][80],bottom_h[4][80];
X    
X    format_hand(top_h,pdeal->hands[top_hand]);
X    format_hand(right_h,pdeal->hands[(top_hand + 1) % 4]);
X    format_hand(bottom_h,pdeal->hands[(top_hand + 2) % 4]);
X    format_hand(left_h,pdeal->hands[(top_hand + 3) % 4]);
X    fprintf(fp,"\t\tComplete deal (%s vulnerable):\n",
X      ((pdeal->vulnerability <= RELATIVE) ?
X      vuln_format[PASSED_OUT(pdeal)][(top_hand & 1) ^ pdeal->vulnerability] :
X      vuln_absolute[pdeal->vulnerability]));
X    
X    for (i = 0; i < 4; i++)
X	fprintf(fp,"\t\t\t%s\n",top_h[i]);
X    for (i = 0; i < 4; i++)
X	fprintf(fp,"%-43s%s\n",left_h[i],right_h[i]);
X    for (i = 0; i < 4; i++)
X	fprintf(fp,"\t\t\t%s\n",bottom_h[i]);
X}
X
Xprint_bidding(fp,pdeal,your_position,status)
XFILE *fp;
Xdeal *pdeal;
Xint your_position;
Xint status;
X{
X    bid *bids;
X    static char *bid_suits[] = {"S","H","D","C","NT","DB","RD","P"};
X    static char *bid_labels[] = {"*You*","LHO","Partner","RHO"};
X#ifdef LISTING_FIRST_COL
X    static char *lead_labels[] = {"*You*","Dummy","Partner","Declarer"};
X#endif
X#ifdef LISTING_ANY_COL
X    static char *lead_labels[] = {"*You*","Dummy","Partner","Decl."};
X#endif
X    static char *passed_labels[] = {"West","North","East","South"};
X    char **labels;
X    int bid_num;
X    int i;
X    int lastnum;
X
X    if (status == BIDDING)
X    	labels = bid_labels;
X    else if (status == PASSING)
X	labels = passed_labels;
X    else if (status == LEADING)
X	labels = lead_labels;
X
X    your_position = your_position % 4;
X
X    putc('\t',fp);
X    for (i = 0; i < 4; i++)
X#ifdef LISTING_FIRST_COL
X	fprintf(fp,"\t%s",labels[i]);
X#endif
X#ifdef LISTING_ANY_COL
X	fprintf(fp,"\t%s",labels[(i + 4 - your_position) % 4]);
X#endif
X    fprintf(fp,"\nBidding:\t--------------------------------\n");
X
X#ifdef LISTING_FIRST_COL
X    bid_num = (4 - your_position) % 4;
X    if (bid_num)
X	putc('\t',fp);
X    for (i = 0; i < bid_num; i++)
X	fprintf(fp,"\t-");
X    lastnum = bid_num + pdeal->num_bids;
X#endif
X#ifdef LISTING_ANY_COL
X    bid_num = 0;
X    lastnum = pdeal->num_bids;
X#endif
X
X    for (bids = pdeal->bids; bid_num < lastnum; bids = bids->next)
X    {
X	if ((bid_num % 4) == 0)
X	    putc('\t',fp);
X	if (bids->bid.suit <= RANK_USED)
X	    fprintf(fp,"\t%d%s",bids->bid.rank,bid_suits[bids->bid.suit]);
X	else
X	    fprintf(fp,"\t%s",bid_suits[bids->bid.suit]);
X	if ((++bid_num % 4) == 0)
X	    putc('\n',fp);
X    }
X
X#ifdef LISTING_FIRST_COL
X    if (status == BIDDING)
X	fprintf(fp,"\t\t?\n\n");
X    else
X    {
X#endif
X    putc('\n',fp);
X    if (bid_num % 4)
X	putc('\n',fp);
X#ifdef LISTING_FIRST_COL
X    }
X#endif
X}
X
Xaccept_bid(pdeal)
Xdeal *pdeal;
X{
X    int ch;
X    int rank = -1,suit;
X    bid *newbid;
X    static int suit_cvt[] = {3,2,1,0,4};
X    bid *tmp;
X    int i;
X    
X    printf("\nEnter your bid: ");
X    
X    /* Get optional rank */
X    while (isspace(ch = getchar()));
X    
X    if (isdigit(ch))
X    {
X	rank = ch - '0';
X	while (isspace(ch = getchar()));
X    }
X    
X    /* Get suit, notrump, pass, double, or redouble */
X    if (islower(ch))
X	ch = toupper(ch);
X    
X    switch (ch)
X    {
X	case 'S':
X    	    suit = SPADES;
X    	    break;
X	case 'H':
X    	    suit = HEARTS;
X    	    break;
X	case 'D':
X    	    suit = (rank >= 0) ? DIAMONDS : DOUBLE;
X    	    break;
X	case 'C':
X    	    suit = CLUBS;
X    	    break;
X	case 'N':
X    	    suit = NOTRUMP;
X    	    break;
X	case 'P':
X    	    suit = PASS;
X    	    break;
X	case 'R':
X    	    suit = REDOUBLE;
X    	    break;
X	default:
X    	    suit = -1;
X    	    break;
X    }
X    
X    while (getchar() != '\n');
X    if (suit < 0)
X	return(1);
X    
X    /* Make sure numerical bid is ok */
X    if (suit <= RANK_USED)
X    {
X	if (rank < 1 || rank > 7)
X	{
X	    char tmp[10];
X
X	    printf("Do you wish to restart the bidding for this hand? ");
X	    fgets(tmp,10,stdin);
X	    if (tmp[0] != 'y' && tmp[0] != 'Y')
X		return(1);
X	    pdeal->num_bids = 0;
X	    pdeal->bids = NULL;
X	    return(0);
X	}
X	if (pdeal->num_bids > 0)
X	    for (tmp = pdeal->bids->prev, i = pdeal->num_bids; i;
X	      tmp = tmp->prev, i--)
X		if (tmp->bid.suit <= RANK_USED)
X		{
X		    if (rank < tmp->bid.rank || rank == tmp->bid.rank &&
X		      suit_cvt[suit] <= suit_cvt[tmp->bid.suit])
X			return(1);
X		    break;
X		}
X    }
X    /* Make sure double or redouble is valid */
X    else if (suit == DOUBLE || suit == REDOUBLE)
X    {
X	if (pdeal->num_bids <= 0)
X	    return(1);
X	for (tmp = pdeal->bids->prev, i = pdeal->num_bids; i;
X	     tmp = tmp->prev, i--)
X	    if (tmp->bid.suit != PASS)
X	    {
X		/* Double or redouble by wrong side */
X		/* The person bidding in the num_bids position was
X		   an opponent. The last valid bidder must have had
X		   this parity. */
X		if (((i ^ pdeal->num_bids) & 1) == 1)
X		    return(1);
X		/* Double of a double or redouble */
X		if (suit == DOUBLE && tmp->bid.suit > RANK_USED)
X		    return(1);
X		/* Redouble of a bid other than double */
X		if (suit == REDOUBLE && tmp->bid.suit != DOUBLE)
X		    return(1);
X		break;
X	    }
X	/* Double or redouble as first non-pass bid */
X	if (!i)
X	    return(1);
X    }
X    
X    newbid = (bid *)malloc(sizeof(bid));
X    newbid->bid.rank = rank;
X    newbid->bid.suit = suit;
X    
X    if (++(pdeal->num_bids) == 1)
X	newbid->next = newbid->prev = pdeal->bids = newbid;
X    else
X    {
X	(newbid->next = pdeal->bids)->prev =
X	  (newbid->prev = pdeal->bids->prev)->next = newbid;
X	if (newbid->bid.suit == PASS && newbid->prev->bid.suit == PASS &&
X	  newbid->prev->prev->bid.suit == PASS && pdeal->num_bids >= 4)
X	    pdeal->bidding_done = 1;
X    }
X    return(0);
X}
X
Xmore()
X{
X    printf("---Hit return to continue---");
X    while (getchar() != '\n');
X}
X
Xlog_deal(pdeal,top_hand)
Xdeal *pdeal;
Xint top_hand;
X{
X    FILE *fp;
X    int i;
X
X    if ((fp = fopen(LOGFILE,"a")) == NULL)
X    {
X	perror(LOGFILE);
X	return;
X    }
X    print_bidding(fp,pdeal,top_hand + 7,
X      ((PASSED_OUT(pdeal)) ? PASSING : LEADING));
X    if (pdeal->opening_lead.suit >= 0)
X	fprintf(fp,"Opening lead: %c of %s\n\n",pdeal->opening_lead.rank,
X	  suit_strings[pdeal->opening_lead.suit]);
X    print_complete_deal(fp,pdeal,top_hand);
X    fprintf(fp,seperator);
X    fclose(fp);
X}
X
Xwrite_deals()
X{
X    FILE *fp;
X    int i;
X
X    if ((fp = fopen(LOGFILE,"a")) == NULL)
X    {
X	perror(LOGFILE);
X	return;
X    }
X    for (i = 0; i < num_deals; i++)
X    {
X	print_complete_deal(fp,&deals[i],1);
X    	fprintf(fp,seperator);
X    }
X    fclose(fp);
X}
X
Xfigure_out_leader(pdeal)
Xdeal *pdeal;
X{
X    int contract_maker;
X    bid *finalsuit,*tmp;
X    int suit_bidder;
X    
X    /* Find out which bid specified the basic contract */
X    for (contract_maker = pdeal->num_bids - 1, finalsuit = pdeal->bids->prev;
X      contract_maker >= 0 && finalsuit->bid.suit > RANK_USED;
X      contract_maker--, finalsuit = finalsuit->prev);
X    if (contract_maker < 0)
X	return(-1);
X    /* Reduce this to a single side */
X    contract_maker &= 1;
X    /* Find the first player of this side to bid this suit. */
X    suit_bidder = contract_maker;
X    tmp = (suit_bidder) ? pdeal->bids->next : pdeal->bids;
X    while (tmp->bid.suit != finalsuit->bid.suit)
X    {
X	suit_bidder += 2;
X	tmp = tmp->next->next;
X    }
X    return((suit_bidder + 1) % 4);
X}
X
Xget_lead(pdeal,handnum)
Xdeal *pdeal;
Xint handnum;
X{
X    int rank,suit,i;
X    char *tmp;
X    static char valid_ranks[] = "23456789TJQKA";
X    static char valid_suits[] = "SHDC";
X    
X    printf("\nEnter your opening lead: ");
X    
X    /* Get rank */
X    while (isspace(rank = getchar()));
X    
X    /* Get suit */
X    while (isspace(suit = getchar()));
X    
X    if (islower(rank))
X	rank = toupper(rank);
X    if (index(valid_ranks,rank) == NULL)
X    {
X	if (rank == '1' && suit == '0')
X	{
X	    rank = 'T';
X	    /* Get suit again */
X	    while (isspace(suit = getchar()));
X	}
X	else
X	    rank = -1;
X    }
X    if (islower(suit))
X	suit = toupper(suit);
X    if ((tmp = index(valid_suits,suit)) == NULL)
X	suit = -1;
X    while (getchar() != '\n');
X    if (rank < 0 || suit < 0)
X	return(1);
X    
X    pdeal->opening_lead.rank = rank;
X    pdeal->opening_lead.suit = tmp - valid_suits;
X    
X    /* Check to see if it's in the hand */
X    for (i = 0; i < 13; i++)
X	if (pdeal->hands[handnum][i].suit == pdeal->opening_lead.suit &&
X	  valid_ranks[pdeal->hands[handnum][i].rank - 2] ==
X	  pdeal->opening_lead.rank)
X	    return(0);
X    return(1);
X}
X
Xclear_screen()
X{
X#ifdef SCREEN_CLEAR_SIZE
X    int i;
X
X    for (i = 0; i < SCREEN_CLEAR_SIZE; i++)
X    	putchar('\n');
X#else
X    putchar('\f');
X#endif
X}
X
Xwrite_log_header(argc,argv)
Xint argc;
Xchar **argv;
X{
X    FILE *fp;
X    int i;
X    
X    if ((fp = fopen(LOGFILE,"a")) == NULL) {
X	
X	perror(LOGFILE);
X	return;
X    }
X    
X    fprintf(fp,"** ");
X    for (i = 0; i < argc; i++)
X	fprintf(fp,"%s ",argv[i]);
X    fprintf(fp,"**");
X    
X    fprintf(fp,"\n\n");
X    fclose(fp);
X}
X
X/*
X * Keep dealing cards into deal i until it qualifies according to handqfunc().
X * If there is no handqfunc(), then it automaticaly qualifies.
X */
Xdeal_qualified(i)
Xint i;
X{
X    int keepdealing = 1;
X    
X    do
X    {
X	(*predeal)(&deals[i]);
X	deal_hands(&deals[i]);
X	if ((++totaltried % 1000) == 0)
X	    printf("%d/%d\n",totalfound,totaltried);
X	if (handqfunc && (*handqfunc)(&deals[i],handqparm))
X	    keepdealing = 0;
X    }
X    while (keepdealing && handqfunc);
X    totalfound++;
X    printf("%d/%d\n",totalfound,totaltried);
X}
X
Xusage(program)
Xchar *program;
X{
X    printf("Bridge Bidder version 3.0 by John Oswalt and Nathan Glasser\n");
X    printf("Usage: %s [-l] [-d] number_of_deals [deal_type [parameter]]\n",
X	   program);
X    printf("\t-l = list deal types\n");
X    printf("\t-d = deal hands without bidding; save in the log file only\n");
X}
X
Xlist_dealtypes()
X{
X    int i;
X
X    printf("\t\t\tImplemented deal_type's:\n\n");
X    for (i = 0; i < NUM_DEAL_TYPES; i++)
X    {
X	if ((i + 1) % 10 == 0)
X	    more();
X	printf("%s%s\n",deal_types[i].deal_name,deal_types[i].description);
X    }
X}
END_OF_FILE
if test 17979 -ne `wc -c <'bidding.c'`; then
    echo shar: \"'bidding.c'\" unpacked with wrong size!
fi
# end of 'bidding.c'
fi
if test -f 'bidding.doc' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'bidding.doc'\"
else
echo shar: Extracting \"'bidding.doc'\" \(6041 characters\)
sed "s/^X//" >'bidding.doc' <<'END_OF_FILE'
X			Bridge Bidder	Version 3.0
X			by John Oswalt and Nathan Glasser
X			..!sun!megatest!jao (usenet)
X			nathan@brokaw.lcs.mit.edu (internet)
X			nathan@mit-eddie.uucp (usenet)
X
X			June, 1989
X------------------------------------------------------------------------------
XCopyright 1988, 1989 by Nathan Glasser and John Oswalt.
XYou may feel free to distribute this program in its current form.
XPlease do not remove this copyright information.
X==============================================================================
XThis program lets you practice your bidding and opening leads.
X
XAny conventions you want to use are allowed because you're your own
Xpartner, as well as your own opponents. The idea behind this program
Xis that if you're involved with a large enough number of boards, you
Xhopefully won't remember all the hands of a given board, and so you
Xcan bid each of the four hands at different times. What the program
Xdoes is let you make all the bids in all the hands, one bid at a
Xtime, choosing which board to use at any point randomly and letting
Xyou enter the next bid in its bidding sequence.
X
XIn this way, you get to practice bidding with 3 other players whose
Xbidding you understand completely and a partner whom you trust
Ximplicitly. If you find this not to be the case, then you'll probably
Xhave discovered ways in which you need to better understand your
Xbidding system or in which bidding can otherwise be improved.
X
X(By the way, randomly dealt hands tend to have more unusual
Xdistribution than cards which are shuffled and dealt. Thus you may
Xfind that you're pushing your knowledge of your bidding system to its
Xlimits with some of the hands you'll get.)
X
XRather than settling for hands which are entirely random, the program
Xallows you to specify a deal types. A list of the possible deal types
Xappears at the end of this file.
X
X------------------------------------------------------------------------------
XThe operation of the program is as follows:
X
XUsage:	bid [-l] [-d] number_of_deals [deal_type [parameter]]
X    -l = list deal types
X    -d = deal hands without bidding; save in the log file only
X
XThe appropriate number of boards of the specified type are dealt.
X
XYou are shown a single hand, and the bidding of the current board so
Xfar (if there's been any), and you get to enter the next bid.
X
XYou continue in this fashion until the bidding is completed on every hand.
X
XThen you are presented with the hand of the player to make the
Xopening lead on a board, and the bidding of the hand, and get to
Xenter the opening lead.
X
XThe complete hand is then presented to you for your analysis.
X
XYou continue in this fashion until all the hands have been bid and led to.
X
XA complete log of each board is automatically written to the file
X"bidding.log" after the board's completion.
X------------------------------------------------------------------------------
XBids are specified in the obvious way, e.g. 1s = 1 spade, 2n = 2 notrump,
Xp = pass, d = double, r = redouble.
X
XSimilarly, opening leads are specified in the obvious way, e.g.
X2c = 2 of clubs, js = jack of spades, th or 10h = ten of hearts.
X------------------------------------------------------------------------------
XIf you enter a bad bid at any point, the current hand and bidding will
Xbe redisplayed. This can be useful if, when running under Unix, you
Xhit ^Z to stop the program, do some other stuff, and then return to
Xthe program later.
X
XA special case of a bad bid is to enter any "8" level bid, which of
Xcourse is meaningless. If you've messed up the bidding, e.g. by
Xtyping 2S when you meant to type 2H, the bidding for the current
Xdeal will be started over from the beginning. It's better than nothing.
X------------------------------------------------------------------------------
XHow using deal_type's works:
X
XDeals are dealt randomly. When a deal_type is specified, each deal is
Xchecked for conformity to deal_type; if it fails, it is redealt.
XAfter each internal deal, a line is printed which tells how many
Xdeals have been dealt and how many have conformed to deal_type. Since
Xsome deal_types can take a long time to find a conforming deal, this
Xline is also printed every thousand attemped deals.
X
Xdeal_type can be:
X
X2clubs: Someone has at least game - 1 trick (but not a 2NT hand).
X
X2clubs1st: Dealer has at least game - 1 trick (but not a 2NT hand).
X
Xgoulash: Hands delt normally, sorted, cut, and redelt 5-5-3.
X
X3nt: Someone has a 7 or 8 card minor to AKQ with no outside A or K.
X
X2nt: Someone has a 20-21 HCP hand with no 5 card major,
X	no 6 card minor, no singleton, and no void.
X
X1nt: Someone has a 15-17 HCP hand with no 5 card major,
X	no 6 card minor, no singleton, and no void.
X
Xmisfit: All fits are 6 or 7 cards.
X
Xflannery: Someone has 5 hearts, 4 spades, and 11-15 HCP.
X
Xflannery1st: Dealer has 5 hearts, 4 spades, and 11-15 HCP.
X
Xlongsuit N: Someone's longest suit is N cards long.
X
Xlosers N: Someone has exactly N losers.
X
Xvoidhands N: N hands contain at least 1 void.
X
Xtotalvoids N: There are N voids in the deal.
X
Xfit N: At least 1 partnership has exactly N cards in some suit.
X
Xdoublefit N: At least 1 partnership has exactly N cards in two suits.
X
Xbadmisfit N: For at least 1 hand the following is true:
X	Let A and B be two suits, and misfit(x) be the total cards
X	of suit x contained in the hand and in some opponent's
X	hand.  Misfit(A) + Misfit(B) >= N for some A and B.
X
Xwild: Equal parts of 2clubs, 2nt, flannery1st, longsuit 8, losers 3,
X	totalvoids 2, doublefit 19, badmisfit 20, 3nt, and goulash.
X
Xexperiment: Uses custom code in exper.c to generate and qualify
X	deals.  See exper.doc and exper.c
X
XBugs: the program does not always check for meaningful parameters.
X	E.g., if you ask for hands with 13 losers, it will look forever.
X	It is not very efficient in generating rare hands.  If you ask
X	for deals with 13 card fits, it will take a long time to find
X	them.
X------------------------------------------------------------------------------
XPlease send any comments or bug reports to us at the above e-mail
Xaddresses.
END_OF_FILE
if test 6041 -ne `wc -c <'bidding.doc'`; then
    echo shar: \"'bidding.doc'\" unpacked with wrong size!
fi
# end of 'bidding.doc'
fi
if test -f 'eval.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'eval.c'\"
else
echo shar: Extracting \"'eval.c'\" \(16790 characters\)
sed "s/^X//" >'eval.c' <<'END_OF_FILE'
X/* eval.c */
X/*
X			Bridge Bidder	Version 3.0
X			by John Oswalt and Nathan Glasser
X			..!sun!megatest!jao (usenet)
X			nathan@brokaw.lcs.mit.edu (internet)
X			nathan@mit-eddie.uucp (usenet)
X
X			June, 1989
X------------------------------------------------------------------------------
XCopyright 1988, 1989 by Nathan Glasser and John Oswalt.
XYou may feel free to distribute this program in its current form.
XPlease do not remove this copyright information.
X*/
X
X/*
X			Routines to evaluate hands.
X			John Oswalt
X			(Using structures by Nathan Glasser.)
X*/
X
X#include "bidding.h"
X
X/* Is this deal a bad misfit?
X * These deals are really fun.  A bad misfit is a deal in which
X * you have good fits in two suits with opponents.
X *
X * Let F(N) be the number of cards in suit N that you share with the
X * opponent with the most N.
X * 
X * We pick two suits X and Y such that F(X) + F(Y) is maximized.
X * If F(X) + F(Y) >= n, then the deal qualifies.
X *
X */
X
Xbadmisfitq(pdeal, n)
Xdeal *pdeal;
Xint n;
X{
X	int s;
X	int suitmisfit[4];
X	int fit1, fit2;
X	int s0;
X	int int_compare();
X
X	card *h0 = pdeal->hands[0];
X	card *h1 = pdeal->hands[1];
X	card *h2 = pdeal->hands[2];
X	card *h3 = pdeal->hands[3];
X
X	for (s=SPADES; s<=CLUBS; s++) {
X
X		s0 = suitcount(h0, s);
X		fit1 = s0 + suitcount(h1, s);
X		fit2 = s0 + suitcount(h3, s);
X		if (fit2 > fit1)
X			suitmisfit[s] = fit2;
X		else
X			suitmisfit[s] = fit1;
X	}
X
X	qsort(suitmisfit, 4, sizeof(int), int_compare);
X
X	if (suitmisfit[0] + suitmisfit[1] >= n) return 1;
X
X	return 0;
X}
X
X	
X/* Is this deal a misfit?
X * Critera:
X *
X *	All fits are 6 or 7 cards.
X */
X
X
Xmisfitq(pdeal, n)
Xdeal *pdeal;
Xint n;
X{
X	int s;
X	int fitcount[4];
X
X	card *h0 = pdeal->hands[0];
X	card *h1 = pdeal->hands[1];
X	card *h2 = pdeal->hands[2];
X	card *h3 = pdeal->hands[3];
X
X	for (s=SPADES; s<=CLUBS; s++) {
X		fitcount[s] = suitcount(h0, s) + suitcount(h2, s);
X	}
X
X
X	for (s=SPADES; s<=CLUBS; s++) {
X
X		if (!(fitcount[s] == 6 || fitcount[s] == 7)) return 0;
X	}
X
X	return 1;
X}
X
X/* Does at least one partnership have n cards in two suits? */
X
Xdoublefitq(pdeal, n)
Xdeal *pdeal;
Xint n;
X{
X	int s;
X	int compn = 26 - n;
X	int count[4];
X	int fitcount;
X
X	card *h0 = pdeal->hands[0];
X	card *h1 = pdeal->hands[1];
X	card *h2 = pdeal->hands[2];
X	card *h3 = pdeal->hands[3];
X
X	for (s=SPADES; s<=CLUBS; s++) {
X		count[s] = suitcount(h0, s) + suitcount(h2, s);
X	}
X
X	fitcount = count[SPADES] + count[HEARTS];
X	if (fitcount == n || fitcount == compn) return 1;
X
X	fitcount = count[SPADES] + count[DIAMONDS];
X	if (fitcount == n || fitcount == compn) return 1;
X
X	fitcount = count[SPADES] + count[CLUBS];
X	if (fitcount == n || fitcount == compn) return 1;
X	
X	fitcount = count[HEARTS] + count[DIAMONDS];
X	if (fitcount == n || fitcount == compn) return 1;
X	
X	fitcount = count[HEARTS] + count[CLUBS];
X	if (fitcount == n || fitcount == compn) return 1;
X
X	fitcount = count[DIAMONDS] + count[CLUBS];
X	if (fitcount == n || fitcount == compn) return 1;
X
X	return 0;
X}
X
X/* Does at least one partnership have an n card fit? */
X
Xfitq(pdeal, n)
Xdeal *pdeal;
Xint n;
X{
X	int s;
X	int compn = 13 - n;
X	int count;
X
X	card *h0 = pdeal->hands[0];
X	card *h1 = pdeal->hands[1];
X	card *h2 = pdeal->hands[2];
X	card *h3 = pdeal->hands[3];
X
X	for (s=SPADES; s<=CLUBS; s++) {
X
X		count = suitcount(h0, s) + suitcount(h2, s);
X		if (count == n) return 1;
X		/* If we have a 13-n card fit, then they have an n card fit*/
X		if (count == compn) return 1;
X	}
X
X	return 0;
X}
X
X/* Does this deal contain n hands with voids? */
X
Xvoidhandsq(pdeal, n)
Xdeal *pdeal;
Xint n;
X{
X	int voids = 0;
X
X	card *h0 = pdeal->hands[0];
X	card *h1 = pdeal->hands[1];
X	card *h2 = pdeal->hands[2];
X	card *h3 = pdeal->hands[3];
X
X	if ((suitcount(h0, SPADES) == 0) || (suitcount(h0, HEARTS) == 0) ||
X	    (suitcount(h0, DIAMONDS) == 0) || (suitcount(h0, CLUBS) == 0))
X		voids++;
X
X	if ((suitcount(h1, SPADES) == 0) || (suitcount(h1, HEARTS) == 0) ||
X	    (suitcount(h1, DIAMONDS) == 0) || (suitcount(h1, CLUBS) == 0))
X		voids++;
X
X	if ((suitcount(h2, SPADES) == 0) || (suitcount(h2, HEARTS) == 0) ||
X	    (suitcount(h2, DIAMONDS) == 0) || (suitcount(h2, CLUBS) == 0))
X		voids++;
X
X	if ((suitcount(h3, SPADES) == 0) || (suitcount(h3, HEARTS) == 0) ||
X	    (suitcount(h3, DIAMONDS) == 0) || (suitcount(h3, CLUBS) == 0))
X		voids++;
X
X	return (voids == n);
X}
X
X/* Does this deal contain n voids? */
X
Xtotalvoidsq(pdeal, n)
Xdeal *pdeal;
Xint n;
X{
X	int voids = 0;
X	int s;
X
X	card *h0 = pdeal->hands[0];
X	card *h1 = pdeal->hands[1];
X	card *h2 = pdeal->hands[2];
X	card *h3 = pdeal->hands[3];
X
X	for (s=SPADES; s<=CLUBS; s++) {
X
X		if (suitcount(h0, s) == 0) voids++;
X		if (suitcount(h1, s) == 0) voids++;
X		if (suitcount(h2, s) == 0) voids++;
X		if (suitcount(h3, s) == 0) voids++;
X	}
X
X	return (voids == n);
X}
X
X
X/* Does this deal contain any hand who's longest suit is exactly n cards long?*/
X
Xlongsuitq(pdeal, n)
Xdeal *pdeal;
Xint n;
X{
X	card *h0 = pdeal->hands[0]; /* Stoopid compiler. */
X	card *h1 = pdeal->hands[1];
X	card *h2 = pdeal->hands[2];
X	card *h3 = pdeal->hands[3];
X
X	return (hand_longsuitq(h0, n) || hand_longsuitq(h1, n) ||
X	    hand_longsuitq(h2, n) || hand_longsuitq(h3, n));
X}
X
X/* Does this deal contain any hand with exactly n losers?*/
X
Xlosersq(pdeal, n)
Xdeal *pdeal;
Xint n;
X{
X	card *h0 = pdeal->hands[0]; /* Stoopid compiler. */
X	card *h1 = pdeal->hands[1];
X	card *h2 = pdeal->hands[2];
X	card *h3 = pdeal->hands[3];
X
X	return (hand_losersq(h0, n) || hand_losersq(h1, n) ||
X	    hand_losersq(h2, n) || hand_losersq(h3, n));
X}
X
X/* Is any hand in this deal worth opening flannery? */
X
Xflanneryq(pdeal)
Xdeal *pdeal;
X{
X	card *h0 = pdeal->hands[0]; /* Stoopid compiler. */
X	card *h1 = pdeal->hands[1];
X	card *h2 = pdeal->hands[2];
X	card *h3 = pdeal->hands[3];
X
X	return (hand_flanneryq(h0) || hand_flanneryq(h1) ||
X	    hand_flanneryq(h2) || hand_flanneryq(h3));
X}
X
X/* Is the first hand in this deal worth opening flannery? */
X
Xflannery1stq(pdeal)
Xdeal *pdeal;
X{
X	card *h0 = pdeal->hands[0]; /* Stoopid compiler. */
X
X	return (hand_flanneryq(h0));
X}
X
X/* Is any hand in this deal worth opening 2 notrump? */
X
Xtwontq(pdeal)
Xdeal *pdeal;
X{
X	card *h0 = pdeal->hands[0]; /* Stoopid compiler. */
X	card *h1 = pdeal->hands[1];
X	card *h2 = pdeal->hands[2];
X	card *h3 = pdeal->hands[3];
X
X	return (hand_twontq(h0) || hand_twontq(h1) ||
X	    hand_twontq(h2) || hand_twontq(h3));
X}
X
X/* Is any hand in this deal worth opening 1 notrump? */
X
Xonentq(pdeal)
Xdeal *pdeal;
X{
X	card *h0 = pdeal->hands[0]; /* Stoopid compiler. */
X	card *h1 = pdeal->hands[1];
X	card *h2 = pdeal->hands[2];
X	card *h3 = pdeal->hands[3];
X
X	return (hand_onentq(h0) || hand_onentq(h1) ||
X	    hand_onentq(h2) || hand_onentq(h3));
X}
X
X/* Is any hand in this deal worth opening 3 notrump? */
X
Xthreentq(pdeal)
Xdeal *pdeal;
X{
X	card *h0 = pdeal->hands[0]; /* Stoopid compiler. */
X	card *h1 = pdeal->hands[1];
X	card *h2 = pdeal->hands[2];
X	card *h3 = pdeal->hands[3];
X
X	return (hand_threentq(h0) || hand_threentq(h1) ||
X	    hand_threentq(h2) || hand_threentq(h3));
X}
X
X/* Is any hand in this deal worth opening 2 clubs? */
X
Xtwoclubq(pdeal)
Xdeal *pdeal;
X{
X	card *h0 = pdeal->hands[0]; /* Stoopid compiler. */
X	card *h1 = pdeal->hands[1];
X	card *h2 = pdeal->hands[2];
X	card *h3 = pdeal->hands[3];
X
X	return (hand_twoclubq(h0) || hand_twoclubq(h1) ||
X	    hand_twoclubq(h2) || hand_twoclubq(h3));
X}
X
X/*
X * Is this hand's longest suit n cards long?
X */
X
Xhand_longsuitq(h, n)
Xcard *h;
Xint n;
X{
X	return (getlongestlength(h) == n);
X}
X
X/*
X * Does this hand have exactly n losers?
X */
X
Xhand_losersq(h, n)
Xcard *h;
Xint n;
X{
X	return (countlosers(h) == n);
X}
X
X/* Is this hand worth a flannery opening?
X *
X *  Critera:
X *
X *	11-15 High card points.
X *	Exactly 5 hearts
X *	Exactly 4 spades.
X *
X *  Yeah, I know that there is more to it than this.
X */
X
Xhand_flanneryq(h)
Xcard *h;
X{
X	int pc = hcp(h);
X
X	if (pc < 11) return 0;
X	if (pc > 15) return 0;
X	if (suitcount(h, SPADES) != 4) return 0;
X	if (suitcount(h, HEARTS) != 5) return 0;
X
X	return 1;
X}
X
X/* Is this hand worth a 2 nt opening?
X *
X *  Critera:
X *	20 - 21 High card points.
X *	No 5 card major.
X *	No 6 card minor.
X *	No singletons.
X *	No voids.
X *
X *	XXX: Some 5 and 6 (maybe even 7) card suit hands should qualify.
X *	(Well, what do you open with AQ AQ AQ QJxxxxx ?)
X */
X
Xhand_twontq(h)
Xcard *h;
X{
X	int pc = hcp(h);
X	int s;
X
X	if (pc != 20 && pc != 21) return 0;
X
X	for (s=SPADES; s<=CLUBS; s++) {
X
X		switch (suitcount(h, s)) {
X
X		case 0:
X		case 1:
X			return 0;
X
X		case 2:
X		case 3:
X		case 4:
X			break;
X
X		case 5:
X			if (s == SPADES) return 0;
X			if (s == HEARTS) return 0;
X			break;
X
X		default: /* 6 - 13 */
X			return 0;
X		}
X	}
X
X	return 1;
X}
X
X/* Is this hand worth a 1 nt opening?
X *
X *  Critera:
X *	15 - 17 High card points.
X *	No 5 card major.
X *	No 6 card minor.
X *	No singletons.
X *	No voids.
X *
X *	XXX: Some 5 and 6 (maybe even 7) card suit hands should qualify.
X *	(Well, what do you open with AQ AQ AQ QJxxxxx ?)
X */
X
Xhand_onentq(h)
Xcard *h;
X{
X	int pc = hcp(h);
X	int s;
X
X	if (pc < 15 || pc > 17) return 0;
X
X	for (s=SPADES; s<=CLUBS; s++) {
X
X		switch (suitcount(h, s)) {
X
X		case 0:
X		case 1:
X			return 0;
X
X		case 2:
X		case 3:
X		case 4:
X			break;
X
X		case 5:
X			if (s == SPADES) return 0;
X			if (s == HEARTS) return 0;
X			break;
X
X		default: /* 6 - 13 */
X			return 0;
X		}
X	}
X
X	return 1;
X}
X
X/* Is this hand worth a 2 club opening?
X *
X * Critera:
X *	Doesn't qualify for 2NT opener.
X *	If longest suit is major (tie goes to the major), contains
X *	    4 or fewer losers.
X *	If longest suit is minor, contains 3 or fewer losers.
X *
X *	XXX: what about 2C followed by 2NT?
X *	XXX: what about 4414 hands?
X *	XXX: what about hands which should open high pre-empts?
X *	XXX: what about strong two suiters?
X */
X
Xhand_twoclubq(h)
Xcard *h;
X{
X	int longestsuit, losers;
X
X	if (hand_twontq(h)) return 0;
X
X	longestsuit = getlongestsuit(h);
X	losers = countlosers(h);
X
X	if (longestsuit == SPADES || longestsuit == HEARTS)
X		return (losers <= 4);
X
X	return (losers <= 3);
X}
X
X/* Is this hand worth a (gambling) 3 nt opening?
X *
X * Critera:
X *	Contains a 7 or 8 card minor headed by AKQ
X *	Has no outside A or K.
X */
X
Xhand_threentq(h)
Xcard *h;
X{
X	int clubc = suitcount(h, CLUBS);
X	int diamondc = suitcount(h, DIAMONDS);
X	int thesuit;  
X	int s;
X
X	if (clubc == 7 || clubc == 8) {
X
X		thesuit = CLUBS;
X
X	} else if (diamondc == 7 || diamondc == 8) {
X
X		thesuit = DIAMONDS;
X
X	} else {
X		return 0;
X	}
X
X	if (!cardinhandq(h, thesuit, ACE)) return 0;
X	if (!cardinhandq(h, thesuit, KING)) return 0;
X	if (!cardinhandq(h, thesuit, QUEEN)) return 0;
X
X	for (s=SPADES; s<=CLUBS; s++) {
X
X		if (s == thesuit) continue;
X		if (cardinhandq(h, s, ACE)) return 0;
X		if (cardinhandq(h, s, KING)) return 0;
X	}
X	return 1;
X}
X		
X	
X/*
X * Return the hand's longest suit.
X * Ties go to higher ranking suit.
X */
X
Xgetlongestsuit(h)
Xcard *h;
X{
X	int suitcount[4];
X	int i;
X	int longest = 0;
X	int longestsuit;
X
X	for (i=0; i<4; i++)
X		suitcount[i] = 0;
X
X	for (i=0; i<13; i++)
X		suitcount[h[i].suit]++;
X
X	for (i = CLUBS; i>=SPADES; i--) {
X		if (suitcount[i] >= longest) {
X			longest = suitcount[i];
X			longestsuit = i;
X		}
X	}
X	
X	return (longestsuit);
X}
X
X/*
X * How long is this hand's longest suit?
X */
X
Xgetlongestlength(h)
Xcard *h;
X{
X	int suitcount[4];
X	int i;
X	int longest = 0;
X
X	for (i=0; i<4; i++)
X		suitcount[i] = 0;
X
X	for (i=0; i<13; i++)
X		suitcount[h[i].suit]++;
X
X	for (i = CLUBS; i>=SPADES; i--) {
X		if (suitcount[i] >= longest) {
X			longest = suitcount[i];
X		}
X	}
X	
X	return (longest);
X}
X		
X/*
X * How many losers are in this hand?
X *
X * We count losers as follows:
X *
X * In each suit, count 1 loser for each missing A, K or Q, but
X * never more losers than you have cards in the suit.
X * Thus the worst hand you can have has 12 losers.
X *
X * Some bridge books suggest refinements to this, where
X * Qxx counts as 3 losers, QJx counts as 2, and QTx counts
X * as 2.5. 
X */
X
Xcountlosers(h)
Xcard  *h;
X{
X	int losers = 0;
X	int s;
X
X	for (s = SPADES; s <= CLUBS; s++) {
X
X		switch (suitcount(h, s)) {
X
X		case 0:
X			break;
X
X		case 1:
X			if (!cardinhandq(h, s, ACE))
X				losers += 1;
X			break;
X
X		case 2:
X			if (!cardinhandq(h, s, ACE))
X				losers += 1;
X			if (!cardinhandq(h, s, KING))
X				losers += 1;
X			break;
X
X		default:
X			if (!cardinhandq(h, s, ACE))
X				losers += 1;
X			if (!cardinhandq(h, s, KING))
X				losers += 1;
X			if (!cardinhandq(h, s, QUEEN))
X				losers += 1;
X			break;
X		}
X	}
X
X	return losers;
X}
X
X/* How many cards of suit s are in hand h? */
X
Xsuitcount(h, s)
Xcard *h;
Xint s;
X{
X	int i, count = 0;
X
X	for (i=0; i<13; i++) {
X		if (h[i].suit == s) count++;
X	}
X
X	return count;
X}
X
X/* Is the r of s in hand h? */
X
Xcardinhandq(h, s, r)
Xcard *h;
Xint s;
Xint r;
X{
X	int i;
X
X	for (i=0; i<13; i++)
X		if (h[i].suit == s && h[i].rank == r) return 1;
X
X	return 0;
X}
X
X/* Return number of high card points in hand h. */
X
Xhcp(h)
Xcard *h;
X{
X	int pc = 0;
X	int i;
X
X	for (i=0; i<13; i++) switch (h[i].rank) {
X
X	case ACE:
X		pc += 4;
X		break;
X
X	case KING:
X		pc += 3;
X		break;
X
X	case QUEEN:
X		pc += 2;
X		break;
X
X	case JACK:
X		pc += 1;
X		break;
X	}
X	
X	return pc;
X}
X
Xint_compare(a, b)
Xint *a, *b;
X{
X	return (*a < *b);
X}
X
X#define NUMWILDS	10
Xint totals[NUMWILDS];
X
Xwildq(pdeal, t)
Xdeal *pdeal;
Xint t;		/* Total number of deals requested. */
X{
X	static int firsttime = 1;
X	int i;
X	int eachgets;
X
X	if (firsttime) {
X
X		firsttime = 0;
X		eachgets = t/NUMWILDS;
X		for (i=0; i<NUMWILDS; i++) {
X			totals[i] = eachgets;
X		}
X		t = t % NUMWILDS;
X		while (t--)
X			totals[t]++;
X	}
X		
X	t = 1;
X	for (i=0; i<NUMWILDS; i++) {
X		if (totals[i]) {
X			t = 0;
X			break;
X		}
X	}
X	if (t) exit(1); /* shouldn't happen. */
X
X	if (totals[0]) {
X		if (twoclubq(pdeal)) {
X			totals[0]--;
X			return 1;
X		}
X	}
X	if (totals[1]) {
X		if (twontq(pdeal)) {
X			totals[1]--;
X			return 1;
X		}
X	}
X	if (totals[2]) {
X		if (flannery1stq(pdeal)) {
X			totals[2]--;
X			return 1;
X		}
X	}
X	if (totals[3]) {
X		if (longsuitq(pdeal, 8)) {
X			totals[3]--;
X			return 1;
X		}
X	}
X	if (totals[4]) {
X		if (losersq(pdeal, 3)) {
X			totals[4]--;
X			return 1;
X		}
X	}
X	if (totals[5]) {
X		if (totalvoidsq(pdeal, 2)) {
X			totals[5]--;
X			return 1;
X		}
X	}
X	if (totals[6]) {
X		if (doublefitq(pdeal, 19)) {
X			totals[6]--;
X			return 1;
X		}
X	}
X	if (totals[7]) {
X		if (badmisfitq(pdeal, 20)) {
X			totals[7]--;
X			return 1;
X		}
X	}
X	if (totals[8]) {
X		if (threentq(pdeal)) {
X			totals[8]--;
X			return 1;
X		}
X	}
X	if (totals[9]) {
X		if (goulash(pdeal)) {
X			totals[9]--;
X			return 1;
X		}
X	}
X
X	return 0;
X}
X
Xgoulash(pdeal, filler)
Xdeal *pdeal;
Xint filler;
X{
X	extern int card_compare();
X	int i, s;
X	card pile[52];
X
X	card *h0 = pdeal->hands[0];
X	card *h1 = pdeal->hands[1];
X	card *h2 = pdeal->hands[2];
X	card *h3 = pdeal->hands[3];
X
X	s = (random() % 46) + 3;
X
X	for (i = 0; i<13; i++) {
X		pile[s].suit = h0[i].suit;
X		pile[s].rank = h0[i].rank;
X		if (++s == 52) s = 0;
X	}
X		
X	for (i = 0; i<13; i++) {
X		pile[s].suit = h1[i].suit;
X		pile[s].rank = h1[i].rank;
X		if (++s == 52) s = 0;
X	}
X		
X	for (i = 0; i<13; i++) {
X		pile[s].suit = h2[i].suit;
X		pile[s].rank = h2[i].rank;
X		if (++s == 52) s = 0;
X	}
X		
X	for (i = 0; i<13; i++) {
X		pile[s].suit = h3[i].suit;
X		pile[s].rank = h3[i].rank;
X		if (++s == 52) s = 0;
X	}
X
X	s = 0;
X
X	for (i=0; i<=4; i++) {
X		h0[i].suit = pile[s].suit;
X		h0[i].rank = pile[s++].rank;
X	}
X
X	for (i=0; i<=4; i++) {
X		h1[i].suit = pile[s].suit;
X		h1[i].rank = pile[s++].rank;
X	}
X
X	for (i=0; i<=4; i++) {
X		h2[i].suit = pile[s].suit;
X		h2[i].rank = pile[s++].rank;
X	}
X
X	for (i=0; i<=4; i++) {
X		h3[i].suit = pile[s].suit;
X		h3[i].rank = pile[s++].rank;
X	}
X
X	for (i=5; i<=9; i++) {
X		h0[i].suit = pile[s].suit;
X		h0[i].rank = pile[s++].rank;
X	}
X
X	for (i=5; i<=9; i++) {
X		h1[i].suit = pile[s].suit;
X		h1[i].rank = pile[s++].rank;
X	}
X
X	for (i=5; i<=9; i++) {
X		h2[i].suit = pile[s].suit;
X		h2[i].rank = pile[s++].rank;
X	}
X
X	for (i=5; i<=9; i++) {
X		h3[i].suit = pile[s].suit;
X		h3[i].rank = pile[s++].rank;
X	}
X
X	for (i=10; i<=12; i++) {
X		h0[i].suit = pile[s].suit;
X		h0[i].rank = pile[s++].rank;
X	}
X
X	for (i=10; i<=12; i++) {
X		h1[i].suit = pile[s].suit;
X		h1[i].rank = pile[s++].rank;
X	}
X
X	for (i=10; i<=12; i++) {
X		h2[i].suit = pile[s].suit;
X		h2[i].rank = pile[s++].rank;
X	}
X
X	for (i=10; i<=12; i++) {
X		h3[i].suit = pile[s].suit;
X		h3[i].rank = pile[s++].rank;
X	}
X
X	qsort(h0, 13, sizeof(card), card_compare);
X	qsort(h1, 13, sizeof(card), card_compare);
X	qsort(h2, 13, sizeof(card), card_compare);
X	qsort(h3, 13, sizeof(card), card_compare);
X
X	return 1;
X}
X
Xswaphands(a, b)
Xcard *a, *b;
X{
X	int i, t;
X
X	for (i=0; i<13; i++) {
X
X		t = a[i].suit;
X		a[i].suit = b[i].suit;
X		b[i].suit = t;
X
X		t = a[i].rank;
X		a[i].rank = b[i].rank;
X		b[i].rank = t;
X	}
X}
X
Xtwoclub1stq(pdeal)
Xdeal *pdeal;
X{
X	card *h0 = pdeal->hands[0]; /* Stoopid compiler. */
X	card *h1 = pdeal->hands[1];
X	card *h2 = pdeal->hands[2];
X	card *h3 = pdeal->hands[3];
X
X	if (hand_twoclubq(h0)) return 1;
X	if (hand_twoclubq(h1)) {
X		swaphands(h0, h1);
X		return 1;
X	}
X	if (hand_twoclubq(h2)) {
X		swaphands(h0, h2);
X		return 1;
X	}
X	if (hand_twoclubq(h3)) {
X		swaphands(h0, h3);
X		return 1;
X	}
X	return 0;
X}
END_OF_FILE
if test 16790 -ne `wc -c <'eval.c'`; then
    echo shar: \"'eval.c'\" unpacked with wrong size!
fi
# end of 'eval.c'
fi
if test -f 'example.exp' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'example.exp'\"
else
echo shar: Extracting \"'example.exp'\" \(4221 characters\)
sed "s/^X//" >'example.exp' <<'END_OF_FILE'
XIn a flight B (0-1500) matchpoint event at the California Capitol Regional
Xlast weekend, I picked up the following hand, white against red:
X
X	
X  Spades:   9
X  Hearts:   A K Q 9 3 2
XDiamonds:   K Q J 
X   Clubs:   A 6 2
X
X
XDealer on my left passed, partner (a disciplined preemptor) opened
X3 diamonds, and RHO overcalled 3 spades.
X
XDecide what you would do before you read on.
X
XI reasoned as follows:  I am sure that partner has 7 diamonds to the
Xace, and does not have the spade ace.  Therefore, barring an unlikely
X6NT, the only reasonable spots are 6 diamonds and 6 hearts.  I'm not
Xsure which is best.  Can I get partner's help?
X
XI can't double, as that would be penality.  I can't bid 4 hearts; that isn't
Xforcing.  I could say 5 hearts, inviting 6 with good trump.  But will partner
Xknow that xxx or Jx is excellent support, and 2 small might be good 
Xenough?  Bidding 5 hearts is likely to miss slam.  The only reasonable
Xforcing sequence begins with 4 spades.  Partner will probably say
X5 diamonds, and and then where am I?  I can say 5 hearts, but I doubt that
Xthis is forcing.  Will she raise to six on xxx or Jx? (I'm not sure I want
Xto be in 6 hearts opposite xx, since the chances of a 3-2 heart split is
Xprobably less than normal.  I may analyze this later.)  Partner is a
Xgood player, but she is not psychic.  I judged it more likely that she
Xwould pass 5 hearts than that she would correctly bid 6 on Jx or xxx. 
XSo I decided that I must bid 6 diamonds or 6 hearts myself.
X
XI judged that 6 diamonds virtually 100%, and 6 hearts maybe 50%.  Since
Xany slam will beat everyone not in slam, I bid 6 diamonds.
X
XTurns out that partner had Jx in hearts, and 6 hearts makes.  However,
Xwe got a 10 (of 12 top) for bidding and making 6 diamonds.
X
XBut I wondered if I did the right thing.
X
XThis is exactly the sort of problem which computers are helpful in
Xanalyzing.  It so happens that I have a program which will let me
Xgenerate large numbers of deals conforming to various criteria.
X
XSo I did it.  I made the following assumptions:
X
X	1) LHO has less than 11 HCP, and not 6 spades or 7 clubs.
X	2) Partner has 7 diamonds to the ace, less than 11 HCP,
X	   no 4 card major, does not have the ace of spades,
X	   and does not have 5 clubs.
X	3) RHO has 5 or 6 losers, and at least 5 spades.
X	4) I hold the given hand.
X
XI then generated 100 such deals and hand inspected them.  I threw out
Xsome that I judged RHO would pass, double, or overcall something else.
X(Usually 4 spades, but there were a couple of hands with 5 spades and 6
Xclubs that I, at least, would bid 4 clubs on.)  I generated more deals
Xto bring the total up to 100.
X
XI analyzed these by hand.  Results:
X
X51 times both slams make.  Two of these make 7, because partner has
X	a spade void.  Three will also make 6NT (from the right side)
X	because partner has spade king.
X
X39 times 6D makes, but 6H doesn't.  One of these also makes
X	6NT, as partner has the spade king.
X
X4 times 6H does not make, and 6D can be beat on what I consider an
X	unlikely defense.  (Twice my RHO must underlead the spade ace
X	to get a heart ruff, once he must underlead the AKQJ (!) to
X	get a heart ruff, and once he must give his partner a heart
X	ruff on opening lead, or after cashing one spade.)
X
X3 times 6H does not make, and 6D can be beat on good defense.  (Spade
X	king led and overtaken to return a heart, ruffed.  Dummy
X	(my hand) will show that this is the only place a trick could
X	come from.)
X
X2 times 6H makes, but 6D will not on an unlikely ruff.
X
X1 time 6D makes, but 6H will not on an unlikely ruff.
X
XIf we assume good but not inspired defense, and ignore the unlikely
X6NT and 7 level contacts, then we have:
X
X6 hearts makes, 6 diamonds does not:	0
X6 diamonds makes, 6 hearts does not:	43
XBoth make:				54
XNeither make:				3
X
XConclusions: 6 diamonds was a good call.  It beats everybody not in
Xslam, ties those in 6 diamonds, and beats those in 6 hearts almost 
Xhalf the time.  6 hearts beats everyone not in 6 hearts about half
Xthe time, but loses to everybody about half the time.  There is also
Xthe fact that when 6 hearts goes down, it frequently goes down
Xmore than one, sometimes doubled (e.g. when LHO has five to the jack.)
X
XJohn Oswalt (..!sun!megatest!jao)
END_OF_FILE
if test 4221 -ne `wc -c <'example.exp'`; then
    echo shar: \"'example.exp'\" unpacked with wrong size!
fi
# end of 'example.exp'
fi
if test -f 'exper.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'exper.c'\"
else
echo shar: Extracting \"'exper.c'\" \(3678 characters\)
sed "s/^X//" >'exper.c' <<'END_OF_FILE'
X/* experiment.c */
X/*
X			Bridge Bidder	Version 3.0
X			by John Oswalt and Nathan Glasser
X			..!sun!megatest!jao (usenet)
X			nathan@brokaw.lcs.mit.edu (internet)
X			nathan@mit-eddie.uucp (usenet)
X
X			June, 1989
X------------------------------------------------------------------------------
XCopyright 1988, 1989 by Nathan Glasser and John Oswalt.
XYou may feel free to distribute this program in its current form.
XPlease do not remove this copyright information.
X*/
X
X/*
X *
X *			Routines to do an experiment.
X *			John Oswalt
X *			(Using structures by Nathan Glasser.)
X */
X
X#include "bidding.h"
X
X#define	TRUE	1
X#define	FALSE	0
X
X#define SPADE2		0
X#define SPADE3		1
X#define SPADE4		2
X#define SPADE5		3
X#define SPADE6		4
X#define SPADE7		5
X#define SPADE8		6
X#define SPADE9		7
X#define SPADETEN	8
X#define SPADEJACK	9
X#define SPADEQUEEN	10
X#define SPADEKING	11
X#define SPADEACE	12
X#define HEART2		13
X#define HEART3		14
X#define HEART4		15
X#define HEART5		16
X#define HEART6		17
X#define HEART7		18
X#define HEART8		19
X#define HEART9		20
X#define HEARTTEN	21
X#define HEARTJACK	22
X#define HEARTQUEEN	23
X#define HEARTKING	24
X#define HEARTACE	25
X#define DIAMOND2	26
X#define DIAMOND3	27
X#define DIAMOND4	28
X#define DIAMOND5	29
X#define DIAMOND6	30
X#define DIAMOND7	31
X#define DIAMOND8	32
X#define DIAMOND9	33
X#define DIAMONDTEN	34
X#define DIAMONDJACK	35
X#define DIAMONDQUEEN	36
X#define DIAMONDKING	37
X#define DIAMONDACE	38
X#define CLUB2		39
X#define CLUB3		40
X#define CLUB4		41
X#define CLUB5		42
X#define CLUB6		43
X#define CLUB7		44
X#define CLUB8		45
X#define CLUB9		46
X#define CLUBTEN		47
X#define CLUBJACK	48
X#define CLUBQUEEN	49
X#define CLUBKING	50
X#define CLUBACE		51
X
X/*
X * Variables used by deal_hand().  The trick is to fill one or more
X * hand, using some of the cards, and let deal_hand() deal out the
X * rest randomly.  Set hand_setup[n] iff hand n is pre-dealt.  
X * mark cardsused[n] iff card n has been pre-dealt.  Set cards left
X * to 52 - 13N, where N is number of pre-dealt hands.
X *
X * default_predeal() is provided for when no hands are predealt.
X *
X * experimentq is a function provided to test whether the deal qualifies
X * under the terms of the experiment.
X */
X
Xexperimentq(pdeal)
Xdeal *pdeal;
X{
X	card *h0 = pdeal->hands[0]; /* Stoopid compiler. */
X	card *h1 = pdeal->hands[1];
X	card *h2 = pdeal->hands[2];
X	card *h3 = pdeal->hands[3];
X
X	if (suitcount(h1, DIAMONDS) != 7) return FALSE;
X	if (hcp(h1) > 11) return FALSE;
X	if (suitcount(h1, HEARTS) > 3) return FALSE;
X	if (suitcount(h1, SPADES) > 3) return FALSE;
X	if (suitcount(h1, CLUBS) > 4) return FALSE;
X	if (cardinhandq(h1, SPADES, ACE)) return FALSE;
X	if (!cardinhandq(h1, DIAMONDS, ACE)) return FALSE;
X
X	if (hcp(h0) > 11) return FALSE;
X	if (suitcount(h0, HEARTS) > 5) return FALSE;
X	if (suitcount(h0, SPADES) > 5) return FALSE;
X	if (suitcount(h0, CLUBS) > 6) return FALSE;
X
X	if (suitcount(h2, SPADES) < 5) return FALSE;
X	if (countlosers(h2) > 6) return FALSE;
X	if (countlosers(h2) < 5) return FALSE;
X
X	return TRUE;
X}
X
Xdefault_predeal(pdeal)
Xdeal *pdeal;
X{
X	int player, cardnum;
X
X	for (cardnum = 0; cardnum < 52; cardnum++) {
X		cardsused[cardnum] = 0;
X	}
X
X	for (player = 0; player < 4; player++) {
X		hand_setup[player] = 0;
X	}
X	cardsleft = 52;
X}
X
Xint experiment_hand[13] = {
X	SPADE9,
X	HEARTACE, HEARTKING, HEARTQUEEN, HEART9, HEART3, HEART2,
X	DIAMONDKING, DIAMONDQUEEN, DIAMONDJACK,
X	CLUBACE, CLUB6, CLUB2
X};
X
Xexperiment_predeal(pdeal)
Xdeal *pdeal;
X{
X	int i, cardnum;
X	card *thehand = pdeal->hands[3];
X
X	default_predeal(pdeal);
X	hand_setup[3] = 1;
X	cardsleft -= 13;
X
X	for (i=0; i<13; i++) {
X
X		cardnum = experiment_hand[i];
X
X		cardsused[cardnum] = 1;
X		thehand[i].suit = cardnum / 13;
X		thehand[i].rank = 2 + (cardnum % 13);
X	}
X}
END_OF_FILE
if test 3678 -ne `wc -c <'exper.c'`; then
    echo shar: \"'exper.c'\" unpacked with wrong size!
fi
# end of 'exper.c'
fi
if test -f 'makefile.dos' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'makefile.dos'\"
else
echo shar: Extracting \"'makefile.dos'\" \(581 characters\)
sed "s/^X//" >'makefile.dos' <<'END_OF_FILE'
X# Makefile (ibm-pc/ms-dos) for
X#			Bridge Bidder	Version 3.0
X#			by John Oswalt and Nathan Glasser
X#			..!sun!megatest!jao (usenet)
X#			nathan@brokaw.lcs.mit.edu (internet)
X#			nathan@mit-eddie.uucp (usenet)
X#
X#			June, 1989
X#-----------------------------------------------------------------------------
X#Copyright 1988, 1989 by Nathan Glasser.
X#You may feel free to distribute this program in its current form.
X#Please do not remove this copyright information.
X
XOBJS = bidding.obj deal.obj eval.obj exper.obj
X
Xbid.exe:	$(OBJS)
X	link $(OBJS),bid /stack:0x1000;
X
X$(OBJS):	bidding.h
END_OF_FILE
if test 581 -ne `wc -c <'makefile.dos'`; then
    echo shar: \"'makefile.dos'\" unpacked with wrong size!
fi
# end of 'makefile.dos'
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