DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T b

⟦88b56df0f⟧ TextFile

    Length: 17979 (0x463b)
    Types: TextFile
    Names: »bidding.c«

Derivation

└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
    └─⟦this⟧ »EUUGD18/General/Bidding/bidding.c« 

TextFile

/* bidding.c */
/*
			Bridge Bidder	Version 3.0
			by John Oswalt and Nathan Glasser
			..!sun!megatest!jao (usenet)
			nathan@brokaw.lcs.mit.edu (internet)
			nathan@mit-eddie.uucp (usenet)

			June, 1989
------------------------------------------------------------------------------
Copyright 1988, 1989 by Nathan Glasser and John Oswalt.
You may feel free to distribute this program in its current form.
Please do not remove this copyright information.
*/

#include "bidding.h"

char *vuln_relative[] = {"Your side","Other side"};
char *vuln_absolute[] = {"1st side","2nd side","Neither side","Both sides"};
char *suit_strings[4] = {"Spades","Hearts","Diamonds","Clubs"};
char *vuln_format[2][2] = {
  {"Declarer side","Defender side"},
  {"North/South","East/West"}};
char seperator[] =
"\n---------------------------------------------------------------------\n\n";

#define PASSED_OUT(pdeal) \
    ((pdeal)->num_bids == 4 && (pdeal)->bids->bid.suit == PASS)

/* Functions used for deal qualification */
extern int twoclubq(), twoclub1stq(), threentq(), twontq(), flanneryq(),
    longsuitq(), losersq(), flannery1stq(), voidhandsq(),
    totalvoidsq(), fitq(), doublefitq(), misfitq(), badmisfitq();
    wildq(), goulash(), experimentq(), onentq();
extern int default_predeal(), experiment_predeal();

struct deal_type deal_types[] = {
    {"2clubs",default_predeal,twoclubq,-1,
      ": Someone has at least game - 1 trick (but not a 2NT hand)."},
    {"2clubs1st",default_predeal,twoclub1stq,-1,
      ": Dealer has at least game - 1 trick (but not a 2NT hand)."},
    {"goulash",default_predeal,goulash,-1,
      ": Hands delt normally, sorted, cut, and redelt 5-5-3."},
    {"3nt",default_predeal,threentq,-1,
      ": Someone has a 7 or 8 card minor to AKQ with no outside A or K."},
    {"2nt",default_predeal,twontq,-1,
      ": Someone has a 20-21 HCP hand with no 5 card major,\n\
\tno 6 card minor, no singleton, and no void."},
    {"1nt",default_predeal,onentq,-1,
      ": Someone has a 15-17 HCP hand with no 5 card major,\n\
\tno 6 card minor, no singleton, and no void."},
    {"misfit",default_predeal,misfitq,-1,
      ": All fits are 6 or 7 cards."},
    {"flannery",default_predeal,flanneryq,-1,
      ": Someone has 5 hearts, 4 spades, and 11-15 HCP."},
    {"flannery1st",default_predeal,flannery1stq,-1,
      ": Dealer has 5 hearts, 4 spades, and 11-15 HCP."},
    {"longsuit",default_predeal,longsuitq,13,
      " N: Someone's longest suit is N cards long."},
    {"losers",default_predeal,losersq,12,
      " N: Someone has exactly N losers."},
    {"voidhands",default_predeal,voidhandsq,4,
      " N: N hands contain at least 1 void."},
    {"totalvoids",default_predeal,totalvoidsq,12,
      " N: There are N voids in the deal."},
    {"fit",default_predeal,fitq,13,
      " N: At least 1 partnership has exactly N cards in some suit."},
    {"doublefit",default_predeal,doublefitq,26,
      " N: At least 1 partnership has exactly N cards in two suits."},
    {"badmisfit",default_predeal,badmisfitq,26,
      "N: For at least 1 hand the following is true:\n\
\tLet A and B be two suits, and misfit(x) be the total cards\n\
\tof suit x contained in the hand and in some opponent's\n\
\thand.  Misfit(A) + Misfit(B) >= N for some A and B."},
    {"wild",default_predeal,wildq,0,
      ": Equal parts of 2clubs, 2nt, flannery1st, longsuit 8, losers 3,\n\
\ttotalvoids 2, doublefit 19, badmisfit 20, 3nt, and goulash."},
    {"experiment",experiment_predeal,experimentq,-1,
      ": Uses custom code in exper.c to generate and qualify\n\
\tdeals.  See exper.doc and exper.c."},
};

#define NUM_DEAL_TYPES (sizeof(deal_types) / sizeof(struct deal_type))

PFI predeal = default_predeal;
deal *deals;
int totaltried = 0;
int totalfound = 0;
PFI handqfunc = (PFI)NULL;
int handqparm;
int cardsused[52];
int hand_setup[4];
int cardsleft;
int num_deals;
int dobidding = 1;


main(argc,argv)
int argc;
char **argv;
{
    int i,j;
    int num_deals_left;
    int deal_num;
    int origargc = argc;
    char **origargv = argv;
    
    if (argc < 2)
    {
	usage(argv[0]);
	exit(0);
    }
    
    while (argc--, (++argv)[0][0] == '-')
	switch (argv[0][1])
	{
	    case 'l':
	    case 'L':
	        list_dealtypes();
		exit(0);
	    case 'd':
	    case 'D':
	        dobidding = 0;
		break;
	    default:
		printf("Unknown option: %s.\n",argv[0]);
		exit(1);
	}
    
    num_deals = atoi((argv++)[0]);
    argc--;
    
    /* Handle a deal_type. Look up the name in the table.
       If we find it there, then we may have to process a parameter.
       A param_max value of < 0 means it takes no parameter. A
       parameter of 0 means that it takes no parameter, but the function
       is automatically given num_deals as its parameter. A positive
       value means that it takes a parameter, which must be positive and
       is not allowed to exceed that value. */
    if (argc)
    {
	for (i = NUM_DEAL_TYPES - 1; i >= 0; i--)
	    if (!strcmp(argv[0],deal_types[i].deal_name))
	    {
		predeal = deal_types[i].predeal_func;
		handqfunc = deal_types[i].hand_func;
		if (deal_types[i].param_max == 0)
		    handqparm = num_deals;
		else if (deal_types[i].param_max > 0)
		{
		    if (argc < 2)
		    {
			printf("Missing required parameter.\n");
			exit(1);
		    }
		    if ((handqparm = atoi(argv[1])) < 1 ||
		      handqparm > deal_types[i].param_max)
		    {
			printf("Parameter %d not in the range 1-%d.\n",
			  handqparm,deal_types[i].param_max);
			exit(1);
		    }
		}
		break;
	    }
	if (i < 0)
    	{
	    printf("Unknown deal_type %s.\n",argv[0]);
	    exit(1);
    	}
    }

    printf("Dealing %d hand%s...\n",num_deals_left = num_deals,
	num_deals == 1 ? "" : "s");
    
    deals = (deal *)malloc(num_deals * sizeof(deal));
    
    srandom((unsigned)time(NULL));
    
    for (i = 0; i < num_deals; i++)
	deal_qualified(i);
    
    write_log_header(origargc,origargv);
    
    if (!dobidding)
    {
	bid tmp;
	tmp.bid.suit = PASS;

	/* Make it look like all hands were passed out so that
	   print_complete_deal will work right. Kludge. */
	for (i = 0; i < num_deals; i++)
	{
	    deals[i].num_bids = 4;
	    deals[i].bids = &tmp;
	}
	write_deals();
	printf("All dealing complete.\n");
	exit(0);
    }
    
    /* Accept bids */
    while (num_deals_left)
    {
	deal_num = random() % num_deals;
	
	if (deals[deal_num].bidding_done)
	    continue;
	clear_screen();
	for (;;)
	{
	    print_bidding(stdout,&deals[deal_num],deals[deal_num].num_bids,
	      BIDDING);
	    printf("Your hand (%s vulnerable):\n",
	      (deals[deal_num].vulnerability <= RELATIVE) ?
	      vuln_relative[(deals[deal_num].num_bids & 1) ^ 
	      deals[deal_num].vulnerability] :
	      vuln_absolute[deals[deal_num].vulnerability]);
	    print_hand(stdout,
	      deals[deal_num].hands[deals[deal_num].num_bids % 4]);
	    if (!accept_bid(&deals[deal_num]))
	    	break;
	    printf("Bad bid.\n\n");
	}
	
	if (deals[deal_num].bidding_done)
	{
	    num_deals_left--;
	    /* If hand was passed out */
	    if (PASSED_OUT(&deals[deal_num]))
		display_complete_deal(&deals[deal_num],1);
	}
    }
    
    /* Accept opening leads */
    for (deal_num = 0; deal_num < num_deals; deal_num++)
    {
    	/* Make sure hand wasn't passed out */
	if (PASSED_OUT(&deals[deal_num]))
	    continue;
	clear_screen();
	j = figure_out_leader(&deals[deal_num]);

	for (;;)
	{
	    print_bidding(stdout,&deals[deal_num],j,LEADING);
	    printf("Your hand (%s vulnerable):\n",
	      (deals[deal_num].vulnerability <= RELATIVE) ?
	      vuln_relative[(j & 1) ^ 
	      deals[deal_num].vulnerability] :
	      vuln_absolute[deals[deal_num].vulnerability]);
	    print_hand(stdout,deals[deal_num].hands[j]);
	    if (!get_lead(&deals[deal_num],j))
	    	break;
	    printf("Bad lead.\n\n");
	}

	display_complete_deal(&deals[deal_num],((j + 1) % 4));
    }
    
    printf("All bidding complete.\n");
}

display_complete_deal(pdeal,top_hand)
deal *pdeal;
int top_hand;
{
    print_complete_deal(stdout,pdeal,top_hand);
    more();
    log_deal(pdeal,top_hand);
}

print_complete_deal(fp,pdeal,top_hand)
FILE *fp;
deal *pdeal;
int top_hand;
{
    int i;
    char top_h[4][80],left_h[4][80],right_h[4][80],bottom_h[4][80];
    
    format_hand(top_h,pdeal->hands[top_hand]);
    format_hand(right_h,pdeal->hands[(top_hand + 1) % 4]);
    format_hand(bottom_h,pdeal->hands[(top_hand + 2) % 4]);
    format_hand(left_h,pdeal->hands[(top_hand + 3) % 4]);
    fprintf(fp,"\t\tComplete deal (%s vulnerable):\n",
      ((pdeal->vulnerability <= RELATIVE) ?
      vuln_format[PASSED_OUT(pdeal)][(top_hand & 1) ^ pdeal->vulnerability] :
      vuln_absolute[pdeal->vulnerability]));
    
    for (i = 0; i < 4; i++)
	fprintf(fp,"\t\t\t%s\n",top_h[i]);
    for (i = 0; i < 4; i++)
	fprintf(fp,"%-43s%s\n",left_h[i],right_h[i]);
    for (i = 0; i < 4; i++)
	fprintf(fp,"\t\t\t%s\n",bottom_h[i]);
}

print_bidding(fp,pdeal,your_position,status)
FILE *fp;
deal *pdeal;
int your_position;
int status;
{
    bid *bids;
    static char *bid_suits[] = {"S","H","D","C","NT","DB","RD","P"};
    static char *bid_labels[] = {"*You*","LHO","Partner","RHO"};
#ifdef LISTING_FIRST_COL
    static char *lead_labels[] = {"*You*","Dummy","Partner","Declarer"};
#endif
#ifdef LISTING_ANY_COL
    static char *lead_labels[] = {"*You*","Dummy","Partner","Decl."};
#endif
    static char *passed_labels[] = {"West","North","East","South"};
    char **labels;
    int bid_num;
    int i;
    int lastnum;

    if (status == BIDDING)
    	labels = bid_labels;
    else if (status == PASSING)
	labels = passed_labels;
    else if (status == LEADING)
	labels = lead_labels;

    your_position = your_position % 4;

    putc('\t',fp);
    for (i = 0; i < 4; i++)
#ifdef LISTING_FIRST_COL
	fprintf(fp,"\t%s",labels[i]);
#endif
#ifdef LISTING_ANY_COL
	fprintf(fp,"\t%s",labels[(i + 4 - your_position) % 4]);
#endif
    fprintf(fp,"\nBidding:\t--------------------------------\n");

#ifdef LISTING_FIRST_COL
    bid_num = (4 - your_position) % 4;
    if (bid_num)
	putc('\t',fp);
    for (i = 0; i < bid_num; i++)
	fprintf(fp,"\t-");
    lastnum = bid_num + pdeal->num_bids;
#endif
#ifdef LISTING_ANY_COL
    bid_num = 0;
    lastnum = pdeal->num_bids;
#endif

    for (bids = pdeal->bids; bid_num < lastnum; bids = bids->next)
    {
	if ((bid_num % 4) == 0)
	    putc('\t',fp);
	if (bids->bid.suit <= RANK_USED)
	    fprintf(fp,"\t%d%s",bids->bid.rank,bid_suits[bids->bid.suit]);
	else
	    fprintf(fp,"\t%s",bid_suits[bids->bid.suit]);
	if ((++bid_num % 4) == 0)
	    putc('\n',fp);
    }

#ifdef LISTING_FIRST_COL
    if (status == BIDDING)
	fprintf(fp,"\t\t?\n\n");
    else
    {
#endif
    putc('\n',fp);
    if (bid_num % 4)
	putc('\n',fp);
#ifdef LISTING_FIRST_COL
    }
#endif
}

accept_bid(pdeal)
deal *pdeal;
{
    int ch;
    int rank = -1,suit;
    bid *newbid;
    static int suit_cvt[] = {3,2,1,0,4};
    bid *tmp;
    int i;
    
    printf("\nEnter your bid: ");
    
    /* Get optional rank */
    while (isspace(ch = getchar()));
    
    if (isdigit(ch))
    {
	rank = ch - '0';
	while (isspace(ch = getchar()));
    }
    
    /* Get suit, notrump, pass, double, or redouble */
    if (islower(ch))
	ch = toupper(ch);
    
    switch (ch)
    {
	case 'S':
    	    suit = SPADES;
    	    break;
	case 'H':
    	    suit = HEARTS;
    	    break;
	case 'D':
    	    suit = (rank >= 0) ? DIAMONDS : DOUBLE;
    	    break;
	case 'C':
    	    suit = CLUBS;
    	    break;
	case 'N':
    	    suit = NOTRUMP;
    	    break;
	case 'P':
    	    suit = PASS;
    	    break;
	case 'R':
    	    suit = REDOUBLE;
    	    break;
	default:
    	    suit = -1;
    	    break;
    }
    
    while (getchar() != '\n');
    if (suit < 0)
	return(1);
    
    /* Make sure numerical bid is ok */
    if (suit <= RANK_USED)
    {
	if (rank < 1 || rank > 7)
	{
	    char tmp[10];

	    printf("Do you wish to restart the bidding for this hand? ");
	    fgets(tmp,10,stdin);
	    if (tmp[0] != 'y' && tmp[0] != 'Y')
		return(1);
	    pdeal->num_bids = 0;
	    pdeal->bids = NULL;
	    return(0);
	}
	if (pdeal->num_bids > 0)
	    for (tmp = pdeal->bids->prev, i = pdeal->num_bids; i;
	      tmp = tmp->prev, i--)
		if (tmp->bid.suit <= RANK_USED)
		{
		    if (rank < tmp->bid.rank || rank == tmp->bid.rank &&
		      suit_cvt[suit] <= suit_cvt[tmp->bid.suit])
			return(1);
		    break;
		}
    }
    /* Make sure double or redouble is valid */
    else if (suit == DOUBLE || suit == REDOUBLE)
    {
	if (pdeal->num_bids <= 0)
	    return(1);
	for (tmp = pdeal->bids->prev, i = pdeal->num_bids; i;
	     tmp = tmp->prev, i--)
	    if (tmp->bid.suit != PASS)
	    {
		/* Double or redouble by wrong side */
		/* The person bidding in the num_bids position was
		   an opponent. The last valid bidder must have had
		   this parity. */
		if (((i ^ pdeal->num_bids) & 1) == 1)
		    return(1);
		/* Double of a double or redouble */
		if (suit == DOUBLE && tmp->bid.suit > RANK_USED)
		    return(1);
		/* Redouble of a bid other than double */
		if (suit == REDOUBLE && tmp->bid.suit != DOUBLE)
		    return(1);
		break;
	    }
	/* Double or redouble as first non-pass bid */
	if (!i)
	    return(1);
    }
    
    newbid = (bid *)malloc(sizeof(bid));
    newbid->bid.rank = rank;
    newbid->bid.suit = suit;
    
    if (++(pdeal->num_bids) == 1)
	newbid->next = newbid->prev = pdeal->bids = newbid;
    else
    {
	(newbid->next = pdeal->bids)->prev =
	  (newbid->prev = pdeal->bids->prev)->next = newbid;
	if (newbid->bid.suit == PASS && newbid->prev->bid.suit == PASS &&
	  newbid->prev->prev->bid.suit == PASS && pdeal->num_bids >= 4)
	    pdeal->bidding_done = 1;
    }
    return(0);
}

more()
{
    printf("---Hit return to continue---");
    while (getchar() != '\n');
}

log_deal(pdeal,top_hand)
deal *pdeal;
int top_hand;
{
    FILE *fp;
    int i;

    if ((fp = fopen(LOGFILE,"a")) == NULL)
    {
	perror(LOGFILE);
	return;
    }
    print_bidding(fp,pdeal,top_hand + 7,
      ((PASSED_OUT(pdeal)) ? PASSING : LEADING));
    if (pdeal->opening_lead.suit >= 0)
	fprintf(fp,"Opening lead: %c of %s\n\n",pdeal->opening_lead.rank,
	  suit_strings[pdeal->opening_lead.suit]);
    print_complete_deal(fp,pdeal,top_hand);
    fprintf(fp,seperator);
    fclose(fp);
}

write_deals()
{
    FILE *fp;
    int i;

    if ((fp = fopen(LOGFILE,"a")) == NULL)
    {
	perror(LOGFILE);
	return;
    }
    for (i = 0; i < num_deals; i++)
    {
	print_complete_deal(fp,&deals[i],1);
    	fprintf(fp,seperator);
    }
    fclose(fp);
}

figure_out_leader(pdeal)
deal *pdeal;
{
    int contract_maker;
    bid *finalsuit,*tmp;
    int suit_bidder;
    
    /* Find out which bid specified the basic contract */
    for (contract_maker = pdeal->num_bids - 1, finalsuit = pdeal->bids->prev;
      contract_maker >= 0 && finalsuit->bid.suit > RANK_USED;
      contract_maker--, finalsuit = finalsuit->prev);
    if (contract_maker < 0)
	return(-1);
    /* Reduce this to a single side */
    contract_maker &= 1;
    /* Find the first player of this side to bid this suit. */
    suit_bidder = contract_maker;
    tmp = (suit_bidder) ? pdeal->bids->next : pdeal->bids;
    while (tmp->bid.suit != finalsuit->bid.suit)
    {
	suit_bidder += 2;
	tmp = tmp->next->next;
    }
    return((suit_bidder + 1) % 4);
}

get_lead(pdeal,handnum)
deal *pdeal;
int handnum;
{
    int rank,suit,i;
    char *tmp;
    static char valid_ranks[] = "23456789TJQKA";
    static char valid_suits[] = "SHDC";
    
    printf("\nEnter your opening lead: ");
    
    /* Get rank */
    while (isspace(rank = getchar()));
    
    /* Get suit */
    while (isspace(suit = getchar()));
    
    if (islower(rank))
	rank = toupper(rank);
    if (index(valid_ranks,rank) == NULL)
    {
	if (rank == '1' && suit == '0')
	{
	    rank = 'T';
	    /* Get suit again */
	    while (isspace(suit = getchar()));
	}
	else
	    rank = -1;
    }
    if (islower(suit))
	suit = toupper(suit);
    if ((tmp = index(valid_suits,suit)) == NULL)
	suit = -1;
    while (getchar() != '\n');
    if (rank < 0 || suit < 0)
	return(1);
    
    pdeal->opening_lead.rank = rank;
    pdeal->opening_lead.suit = tmp - valid_suits;
    
    /* Check to see if it's in the hand */
    for (i = 0; i < 13; i++)
	if (pdeal->hands[handnum][i].suit == pdeal->opening_lead.suit &&
	  valid_ranks[pdeal->hands[handnum][i].rank - 2] ==
	  pdeal->opening_lead.rank)
	    return(0);
    return(1);
}

clear_screen()
{
#ifdef SCREEN_CLEAR_SIZE
    int i;

    for (i = 0; i < SCREEN_CLEAR_SIZE; i++)
    	putchar('\n');
#else
    putchar('\f');
#endif
}

write_log_header(argc,argv)
int argc;
char **argv;
{
    FILE *fp;
    int i;
    
    if ((fp = fopen(LOGFILE,"a")) == NULL) {
	
	perror(LOGFILE);
	return;
    }
    
    fprintf(fp,"** ");
    for (i = 0; i < argc; i++)
	fprintf(fp,"%s ",argv[i]);
    fprintf(fp,"**");
    
    fprintf(fp,"\n\n");
    fclose(fp);
}

/*
 * Keep dealing cards into deal i until it qualifies according to handqfunc().
 * If there is no handqfunc(), then it automaticaly qualifies.
 */
deal_qualified(i)
int i;
{
    int keepdealing = 1;
    
    do
    {
	(*predeal)(&deals[i]);
	deal_hands(&deals[i]);
	if ((++totaltried % 1000) == 0)
	    printf("%d/%d\n",totalfound,totaltried);
	if (handqfunc && (*handqfunc)(&deals[i],handqparm))
	    keepdealing = 0;
    }
    while (keepdealing && handqfunc);
    totalfound++;
    printf("%d/%d\n",totalfound,totaltried);
}

usage(program)
char *program;
{
    printf("Bridge Bidder version 3.0 by John Oswalt and Nathan Glasser\n");
    printf("Usage: %s [-l] [-d] number_of_deals [deal_type [parameter]]\n",
	   program);
    printf("\t-l = list deal types\n");
    printf("\t-d = deal hands without bidding; save in the log file only\n");
}

list_dealtypes()
{
    int i;

    printf("\t\t\tImplemented deal_type's:\n\n");
    for (i = 0; i < NUM_DEAL_TYPES; i++)
    {
	if ((i + 1) % 10 == 0)
	    more();
	printf("%s%s\n",deal_types[i].deal_name,deal_types[i].description);
    }
}